Skip to content

Commit

Permalink
Merge pull request #185 from Real-Dev-Squad/develop
Browse files Browse the repository at this point in the history
Dev to main sync
  • Loading branch information
iamitprakash authored Jan 22, 2024
2 parents df741f7 + fc35ed4 commit c813985
Show file tree
Hide file tree
Showing 18 changed files with 372 additions and 51 deletions.
3 changes: 2 additions & 1 deletion src/controllers/changeNickname.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { updateNickName } from "../utils/updateNickname";

export async function changeNickname(request: IRequest, env: env) {
const authHeader = await request.headers.get("Authorization");
const reason = request.headers.get("X-Audit-Log-Reason");

if (!authHeader) {
return new JSONResponse(response.BAD_SIGNATURE);
Expand All @@ -15,7 +16,7 @@ export async function changeNickname(request: IRequest, env: env) {
try {
await verifyAuthToken(authHeader, env);
const { discordId, userName } = await request.json();
const res = await updateNickName(discordId, userName, env);
const res = await updateNickName(discordId, userName, env, reason);
return new JSONResponse(res);
} catch {
return new JSONResponse(response.BAD_SIGNATURE);
Expand Down
4 changes: 3 additions & 1 deletion src/controllers/generateDiscordInvite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ export async function generateInviteLink(request: IRequest, env: env) {
}
try {
await verifyAuthToken(authHeader, env);
const reason = request.headers.get("X-Audit-Log-Reason");

const body: inviteLinkBody = await request.json();
const res = await generateDiscordLink(body, env);
const res = await generateDiscordLink(body, env, reason);
return new JSONResponse(res);
} catch (err) {
return new JSONResponse(response.BAD_SIGNATURE);
Expand Down
35 changes: 23 additions & 12 deletions src/controllers/guildRoleHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ import {
createNewRole,
memberGroupRole,
} from "../typeDefinitions/discordMessage.types";
import { verifyAuthToken } from "../utils/verifyAuthToken";
import { verifyAuthToken, verifyCronJobsToken } from "../utils/verifyAuthToken";
import { batchDiscordRequests } from "../utils/batchDiscordRequests";
import { DISCORD_BASE_URL } from "../constants/urls";
import { GROUP_ROLE_ADD } from "../constants/requestsActions";
import createDiscordHeaders from "../utils/createDiscordHeaders";

export async function createGuildRoleHandler(request: IRequest, env: env) {
const authHeader = request.headers.get("Authorization");
Expand All @@ -26,8 +27,8 @@ export async function createGuildRoleHandler(request: IRequest, env: env) {
try {
await verifyAuthToken(authHeader, env);
const body: createNewRole = await request.json();

const res = await createGuildRole(body, env);
const reason = request.headers.get("X-Audit-Log-Reason");
const res = await createGuildRole(body, env, reason);
return new JSONResponse(res);
} catch (err) {
return new JSONResponse(response.BAD_SIGNATURE);
Expand All @@ -41,8 +42,9 @@ export async function addGroupRoleHandler(request: IRequest, env: env) {
try {
await verifyAuthToken(authHeader, env);
const body: memberGroupRole = await request.json();
const reason = request.headers.get("X-Audit-Log-Reason");

const res = await addGroupRole(body, env);
const res = await addGroupRole(body, env, reason);
return new JSONResponse(res);
} catch (err) {
return new JSONResponse(response.BAD_SIGNATURE);
Expand All @@ -54,15 +56,20 @@ export async function getGuildRolesPostHandler(request: IRequest, env: env) {
if (!authHeader) {
return new JSONResponse(response.BAD_SIGNATURE);
}
const reason = request.headers.get("X-Audit-Log-Reason");

try {
await verifyAuthToken(authHeader, env);
await verifyCronJobsToken(authHeader, env);
const { action } = request.query;

switch (action) {
case GROUP_ROLE_ADD.ADD_ROLE: {
const memberGroupRoleList = await request.json();
const res = await bulkAddGroupRoleHandler(memberGroupRoleList, env);
const res = await bulkAddGroupRoleHandler(
memberGroupRoleList,
env,
reason
);
return res;
}
default: {
Expand All @@ -77,7 +84,8 @@ export async function getGuildRolesPostHandler(request: IRequest, env: env) {

export async function bulkAddGroupRoleHandler(
memberGroupRoleList: memberGroupRole[],
env: env
env: env,
reason?: string
): Promise<JSONResponse> {
try {
if (!Array.isArray(memberGroupRoleList)) {
Expand Down Expand Up @@ -105,12 +113,13 @@ export async function bulkAddGroupRoleHandler(
const { userid, roleid } = memberGroupRole;
try {
const createGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members/${userid}/roles/${roleid}`;
const headers: HeadersInit = createDiscordHeaders({
reason,
token: env.DISCORD_TOKEN,
});
const options = {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bot ${env.DISCORD_TOKEN}`,
},
headers,
};
return await fetch(createGuildRoleUrl, options);
} catch (error) {
Expand Down Expand Up @@ -141,13 +150,15 @@ export async function bulkAddGroupRoleHandler(

export async function removeGuildRoleHandler(request: IRequest, env: env) {
const authHeader = request.headers.get("Authorization");
const reason = request.headers.get("X-Audit-Log-Reason");

if (!authHeader) {
return new JSONResponse(response.BAD_SIGNATURE, { status: 401 });
}
try {
await verifyAuthToken(authHeader, env);
const body: memberGroupRole = await request.json();
const res = await removeGuildRole(body, env);
const res = await removeGuildRole(body, env, reason);
return new JSONResponse(res, {
status: 200,
headers: {
Expand Down
17 changes: 17 additions & 0 deletions src/utils/createDiscordHeaders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const createDiscordHeaders = ({
reason,
token,
}: {
reason?: string;
token: string;
}) => {
const headers: HeadersInit = {
"Content-Type": "application/json",
Authorization: `Bot ${token}`,
};
if (reason) {
headers["X-Audit-Log-Reason"] = reason;
}
return headers;
};
export default createDiscordHeaders;
5 changes: 4 additions & 1 deletion src/utils/formatTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ export function generateTaskResponseMessage(
formattedTasks: string[],
status: string
) {
const title = `## ${formatStatusToTitleCase(status)} Tasks of ${nickName}`;
const title =
formattedTasks.length !== 0
? `## ${formatStatusToTitleCase(status)} Tasks of ${nickName}`
: `## ${nickName} doesn't have any in-progress task`;
const tasks = formattedTasks.join("\n\n");
const allTaskLink = `[→ All Tasks](${RDS_STATUS_SITE_URL}/tasks?q=status:all+assignee:${nickName})
`;
Expand Down
16 changes: 11 additions & 5 deletions src/utils/generateDiscordInvite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ import {
import { DISCORD_BASE_URL } from "../constants/urls";
import { env } from "../typeDefinitions/default.types";
import { inviteLinkBody } from "../typeDefinitions/discordLink.types";
import createDiscordHeaders from "./createDiscordHeaders";

export async function generateDiscordLink(body: inviteLinkBody, env: env) {
export async function generateDiscordLink(
body: inviteLinkBody,
env: env,
reason?: string
) {
const { channelId } = body;
const generateInviteUrl = `${DISCORD_BASE_URL}/channels/${channelId}/invites`;

Expand All @@ -20,13 +25,14 @@ export async function generateDiscordLink(body: inviteLinkBody, env: env) {
unique: INVITE_OPTIONS.UNIQUE, // Whether to create a unique invite or not
};
try {
const headers: HeadersInit = createDiscordHeaders({
reason,
token: env.DISCORD_TOKEN,
});
const response = await fetch(generateInviteUrl, {
method: "POST",
body: JSON.stringify(inviteOptions),
headers: {
"Content-Type": "application/json",
Authorization: `Bot ${env.DISCORD_TOKEN}`,
},
headers,
});

if (response.ok) {
Expand Down
52 changes: 33 additions & 19 deletions src/utils/guildRole.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { HeadersInit } from "node-fetch";
import {
INTERNAL_SERVER_ERROR,
ROLE_ADDED,
Expand All @@ -12,23 +13,26 @@ import {
memberGroupRole,
} from "../typeDefinitions/discordMessage.types";
import { GuildRole, Role } from "../typeDefinitions/role.types";
import createDiscordHeaders from "./createDiscordHeaders";

export async function createGuildRole(
body: createNewRole,
env: env
env: env,
reason?: string
): Promise<guildRoleResponse | string> {
const createGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/roles`;
const data = {
...body,
name: body.rolename,
};
const headers: HeadersInit = createDiscordHeaders({
reason,
token: env.DISCORD_TOKEN,
});
try {
const response = await fetch(createGuildRoleUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bot ${env.DISCORD_TOKEN}`,
},
headers,
body: JSON.stringify(data),
});
if (response.ok) {
Expand All @@ -41,16 +45,21 @@ export async function createGuildRole(
}
}

export async function addGroupRole(body: memberGroupRole, env: env) {
export async function addGroupRole(
body: memberGroupRole,
env: env,
reason?: string
) {
const { userid, roleid } = body;
const createGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members/${userid}/roles/${roleid}`;
try {
const headers: HeadersInit = createDiscordHeaders({
reason,
token: env.DISCORD_TOKEN,
});
const response = await fetch(createGuildRoleUrl, {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bot ${env.DISCORD_TOKEN}`,
},
headers,
});
if (response.ok) {
return { message: ROLE_ADDED };
Expand All @@ -62,16 +71,21 @@ export async function addGroupRole(body: memberGroupRole, env: env) {
}
}

export async function removeGuildRole(details: memberGroupRole, env: env) {
export async function removeGuildRole(
details: memberGroupRole,
env: env,
reason?: string
) {
const { userid, roleid } = details;
const removeGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members/${userid}/roles/${roleid}`;
try {
const headers: HeadersInit = createDiscordHeaders({
reason,
token: env.DISCORD_TOKEN,
});
const response = await fetch(removeGuildRoleUrl, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Authorization: `Bot ${env.DISCORD_TOKEN}`,
},
headers,
});
if (response.ok) {
return {
Expand All @@ -91,12 +105,12 @@ export async function getGuildRoles(env: env): Promise<Array<Role>> {
const guildRolesUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/roles`;

try {
const headers: HeadersInit = createDiscordHeaders({
token: env.DISCORD_TOKEN,
});
const response = await fetch(guildRolesUrl, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bot ${env.DISCORD_TOKEN}`,
},
headers,
});

if (!response.ok) {
Expand Down
13 changes: 8 additions & 5 deletions src/utils/updateNickname.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { INTERNAL_SERVER_ERROR, NAME_CHANGED } from "../constants/responses";
import { DISCORD_BASE_URL } from "../constants/urls";
import { env } from "../typeDefinitions/default.types";
import createDiscordHeaders from "./createDiscordHeaders";

export async function updateNickName(
discordId: string,
nickname: string,
env: env
env: env,
reason?: string
) {
const changeNickNameURL = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members/${discordId}`;
const data = { nick: nickname };
const headers: HeadersInit = createDiscordHeaders({
reason,
token: env.DISCORD_TOKEN,
});
try {
const nameChangeResponse = await fetch(changeNickNameURL, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
Authorization: `Bot ${env.DISCORD_TOKEN}`,
},
headers,
body: JSON.stringify(data),
});
if (nameChangeResponse.ok) {
Expand Down
22 changes: 22 additions & 0 deletions src/utils/verifyAuthToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,25 @@ export async function verifyAuthToken(authHeader: string, env: env) {
throw new Error(AUTHENTICATION_ERROR);
}
}

/**
*
* @param authHeader { string } : the auth header of request
* @param env { env }: the ctx (context) which contains the secrets put in as wrangler secrets.
*/
export async function verifyCronJobsToken(authHeader: string, env: env) {
if (!authHeader) {
throw new Error(INVALID_TOKEN_FORMAT);
}
const authHeaderParts = authHeader.split(" ");
if (authHeaderParts.length !== 2 || authHeaderParts[0] !== "Bearer") {
throw new Error(INVALID_TOKEN_FORMAT);
}
const authToken = authHeaderParts[1];
const isValid = await jwt.verify(authToken, env.CRON_JOBS_PUBLIC_KEY, {
algorithm: "RS256",
});
if (!isValid) {
throw new Error(AUTHENTICATION_ERROR);
}
}
1 change: 1 addition & 0 deletions tests/fixtures/fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export const dummyAddRoleBody: memberGroupRole = {
export const guildEnv = {
DISCORD_GUILD_ID: "1234",
DISCORD_TOKEN: "abcd",
CRON_JOBS_PUBLIC_KEY: "test",
};

export const dummyInviteBody = {
Expand Down
Loading

0 comments on commit c813985

Please sign in to comment.