Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added functionality to pass down the header to bot #1848

Merged
merged 14 commits into from
Jan 21, 2024
18 changes: 8 additions & 10 deletions controllers/discordactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
const discordRolesModel = require("../models/discordactions");
const discordServices = require("../services/discordService");
const { fetchAllUsers, fetchUser } = require("../models/users");
const { generateCloudFlareHeaders } = require("../utils/discord-actions");
const discordDeveloperRoleId = config.get("discordDeveloperRoleId");
const discordMavenRoleId = config.get("discordMavenRoleId");

Expand Down Expand Up @@ -39,15 +40,13 @@
createdBy: req.userData.id,
date: admin.firestore.Timestamp.fromDate(new Date()),
};
const authToken = jwt.sign({}, config.get("rdsServerlessBot.rdsServerLessPrivateKey"), {
algorithm: "RS256",
expiresIn: config.get("rdsServerlessBot.ttl"),
});

const headers = generateCloudFlareHeaders(req.userData);

const responseForCreatedRole = await fetch(`${DISCORD_BASE_URL}/roles/create`, {
method: "PUT",
body: JSON.stringify(dataForDiscord),
headers: { "Content-Type": "application/json", Authorization: `Bearer ${authToken}` },
headers,
}).then((response) => response.json());

groupRoleData.roleid = responseForCreatedRole.id;
Expand Down Expand Up @@ -132,14 +131,12 @@
const dataForDiscord = {
...req.body,
};
const authToken = jwt.sign({}, config.get("rdsServerlessBot.rdsServerLessPrivateKey"), {
algorithm: "RS256",
expiresIn: config.get("rdsServerlessBot.ttl"),
});
const headers = generateCloudFlareHeaders(req.userData);

const apiCallToDiscord = fetch(`${DISCORD_BASE_URL}/roles/add`, {
method: "PUT",
body: JSON.stringify(dataForDiscord),
headers: { "Content-Type": "application/json", Authorization: `Bearer ${authToken}` },
headers,
});
const discordLastJoinedDateUpdate = discordRolesModel.groupUpdateLastJoinDate({
id: existingRoles.docs[0].id,
Expand Down Expand Up @@ -168,6 +165,7 @@
if (!roleExists || req.userData.id !== userData.user.id) {
res.boom.forbidden("Permission denied. Cannot delete the role.");
}
await discordServices.removeRoleFromUser(roleid, userid, req.userData);
iamitprakash marked this conversation as resolved.
Show resolved Hide resolved

const { wasSuccess } = await discordRolesModel.removeMemberGroup(roleid, userid);
if (wasSuccess) {
Expand Down Expand Up @@ -285,7 +283,7 @@
const nickNameUpdatedUsers = [];
let counter = 0;
for (let i = 0; i < usersToBeEffected.length; i++) {
const { discordId, username, first_name: firstName } = usersToBeEffected[i];

Check warning on line 286 in controllers/discordactions.js

View workflow job for this annotation

GitHub Actions / build (18.x)

Variable Assigned to Object Injection Sink
try {
if (counter % 10 === 0 && counter !== 0) {
await new Promise((resolve) => setTimeout(resolve, 5500));
Expand All @@ -301,7 +299,7 @@
if (message) {
counter++;
totalNicknamesUpdated.count++;
nickNameUpdatedUsers.push(usersToBeEffected[i].id);

Check warning on line 302 in controllers/discordactions.js

View workflow job for this annotation

GitHub Actions / build (18.x)

Generic Object Injection Sink
}
}
} catch (error) {
Expand Down
8 changes: 2 additions & 6 deletions models/discordactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,12 @@

const removeMemberGroup = async (roleId, discordId) => {
try {
const discordResponse = await removeRoleFromUser(roleId, discordId);
if (discordResponse) {
const backendResponse = await deleteRoleFromDatabase(roleId, discordId);
return backendResponse;
}
const backendResponse = await deleteRoleFromDatabase(roleId, discordId);
return backendResponse;
skv93-coder marked this conversation as resolved.
Show resolved Hide resolved
} catch (error) {
logger.error(`Error while removing role: ${error}`);
iamitprakash marked this conversation as resolved.
Show resolved Hide resolved
throw new Error(error);
}
return false;
};

const deleteRoleFromDatabase = async (roleId, discordId) => {
Expand Down Expand Up @@ -494,7 +490,7 @@

for (let i = 0; i < nicknameUpdateBatches.length; i++) {
const promises = [];
const usersStatusDocsBatch = nicknameUpdateBatches[i];

Check warning on line 493 in models/discordactions.js

View workflow job for this annotation

GitHub Actions / build (18.x)

Variable Assigned to Object Injection Sink
usersStatusDocsBatch.forEach((document) => {
const doc = document.data();
const userId = doc.userId;
Expand Down
8 changes: 4 additions & 4 deletions services/discordService.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const firestore = require("../utils/firestore");
const { fetchAllUsers } = require("../models/users");
const { generateAuthTokenForCloudflare } = require("../utils/discord-actions");
const { generateAuthTokenForCloudflare, generateCloudFlareHeaders } = require("../utils/discord-actions");
const userModel = firestore.collection("users");
const DISCORD_BASE_URL = config.get("services.discordBot.baseUrl");

Expand Down Expand Up @@ -70,12 +70,12 @@ const addRoleToUser = async (userid, roleid) => {
return response;
};

const removeRoleFromUser = async (roleId, discordId) => {
const removeRoleFromUser = async (roleId, discordId, userData) => {
try {
const authToken = generateAuthTokenForCloudflare();
const headers = generateCloudFlareHeaders(userData);
const data = await fetch(`${DISCORD_BASE_URL}/roles`, {
method: "DELETE",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${authToken}` },
headers,
body: JSON.stringify({ userid: discordId, roleid: roleId }),
});
const response = await data.json();
Expand Down
42 changes: 42 additions & 0 deletions test/integration/discordactions.test.js
skv93-coder marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,28 @@ describe("Discord actions", function () {
expect(res.body).to.be.an("object");
expect(res.body.message).to.equal("Role added successfully!");
});
it("should create a reason and pass it down to the bot, on adding the role to the user", async function () {
fetchStub.returns(
Promise.resolve({
status: 200,
json: () => Promise.resolve({}),
})
);

const body = { roleid, userid: userData[0].discordId };
satyam73 marked this conversation as resolved.
Show resolved Hide resolved
const res = await chai
.request(app)
.post("/discord-actions/roles")
.set("cookie", `${cookieName}=${jwt}`)
.send(body);

expect(res).to.have.status(201);
expect(res.body).to.be.an("object");
expect(res.body.message).to.equal("Role added successfully!");
expect(fetchStub.getCall(0).args[1].headers["X-Audit-Log-Reason"]).to.equal(
`Action initiator's username=>ankur and id=${userId}`
);
});
it("should not allow unknown role to be added to user", async function () {
const res = await chai
.request(app)
Expand Down Expand Up @@ -304,6 +326,26 @@ describe("Discord actions", function () {
});
});

it("should create a reason and pass it down to the bot on deleting the role", async function () {
fetchStub.returns(
Promise.resolve({
status: 200,
json: () => Promise.resolve({ roleId: "1234", wasSuccess: true }),
})
);
const res = await chai
.request(app)
.delete("/discord-actions/roles")
.set("cookie", `${cookieName}=${jwt}`)
.send({ roleid, userid: userData[0].discordId });

expect(res).to.have.status(200);
expect(res.body).to.be.an("object");
expect(res.body.message).to.equal("Role deleted successfully");
expect(fetchStub.getCall(0).args[1].headers["X-Audit-Log-Reason"]).to.equal(
`Action initiator's username=>ankur and id=${userId}`
);
});
it("should not allow unknown role to be deleted from user", async function () {
const res = await chai
.request(app)
Expand Down
16 changes: 16 additions & 0 deletions test/unit/utils/genrateCloudFlareHeaders.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const { expect } = require("chai");
const { generateCloudFlareHeaders } = require("../../../utils/discord-actions");

describe("generateCloudFlareHeaders", function () {
it("generates headers with property Content-Type and Authorization", function () {
const data = generateCloudFlareHeaders();
expect(data["Content-Type"]).to.be.eq("application/json");
expect(data.Authorization).to.include("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9");
});
it("generates headers with property Content-Type and Authorization and X-Audit-Log-Reason when id and userName is passed", function () {
const data = generateCloudFlareHeaders({ id: "id", username: "userName" });
expect(data["Content-Type"]).to.be.eq("application/json");
expect(data.Authorization).to.include("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9");
expect(data["X-Audit-Log-Reason"]).to.be.eq("Action initiator's username=>userName and id=id");
});
});
12 changes: 12 additions & 0 deletions utils/discord-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ const generateAuthTokenForCloudflare = () => {
});
return authToken;
};
const generateCloudFlareHeaders = ({ username, id } = {}) => {
const authToken = generateAuthTokenForCloudflare();
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${authToken}`,
};
if (username && id) {
headers["X-Audit-Log-Reason"] = `Action initiator's username=>${username} and id=${id}`;
}
return headers;
};

const generateDiscordProfileImageUrl = async (discordId) => {
try {
Expand Down Expand Up @@ -63,5 +74,6 @@ const generateDiscordInviteLink = async () => {
module.exports = {
generateDiscordProfileImageUrl,
generateAuthTokenForCloudflare,
generateCloudFlareHeaders,
generateDiscordInviteLink,
};
Loading