Skip to content

Commit c813985

Browse files
authored
Merge pull request #185 from Real-Dev-Squad/develop
Dev to main sync
2 parents df741f7 + fc35ed4 commit c813985

18 files changed

+372
-51
lines changed

src/controllers/changeNickname.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { updateNickName } from "../utils/updateNickname";
77

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

1112
if (!authHeader) {
1213
return new JSONResponse(response.BAD_SIGNATURE);
@@ -15,7 +16,7 @@ export async function changeNickname(request: IRequest, env: env) {
1516
try {
1617
await verifyAuthToken(authHeader, env);
1718
const { discordId, userName } = await request.json();
18-
const res = await updateNickName(discordId, userName, env);
19+
const res = await updateNickName(discordId, userName, env, reason);
1920
return new JSONResponse(res);
2021
} catch {
2122
return new JSONResponse(response.BAD_SIGNATURE);

src/controllers/generateDiscordInvite.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ export async function generateInviteLink(request: IRequest, env: env) {
1313
}
1414
try {
1515
await verifyAuthToken(authHeader, env);
16+
const reason = request.headers.get("X-Audit-Log-Reason");
17+
1618
const body: inviteLinkBody = await request.json();
17-
const res = await generateDiscordLink(body, env);
19+
const res = await generateDiscordLink(body, env, reason);
1820
return new JSONResponse(res);
1921
} catch (err) {
2022
return new JSONResponse(response.BAD_SIGNATURE);

src/controllers/guildRoleHandler.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import {
1313
createNewRole,
1414
memberGroupRole,
1515
} from "../typeDefinitions/discordMessage.types";
16-
import { verifyAuthToken } from "../utils/verifyAuthToken";
16+
import { verifyAuthToken, verifyCronJobsToken } from "../utils/verifyAuthToken";
1717
import { batchDiscordRequests } from "../utils/batchDiscordRequests";
1818
import { DISCORD_BASE_URL } from "../constants/urls";
1919
import { GROUP_ROLE_ADD } from "../constants/requestsActions";
20+
import createDiscordHeaders from "../utils/createDiscordHeaders";
2021

2122
export async function createGuildRoleHandler(request: IRequest, env: env) {
2223
const authHeader = request.headers.get("Authorization");
@@ -26,8 +27,8 @@ export async function createGuildRoleHandler(request: IRequest, env: env) {
2627
try {
2728
await verifyAuthToken(authHeader, env);
2829
const body: createNewRole = await request.json();
29-
30-
const res = await createGuildRole(body, env);
30+
const reason = request.headers.get("X-Audit-Log-Reason");
31+
const res = await createGuildRole(body, env, reason);
3132
return new JSONResponse(res);
3233
} catch (err) {
3334
return new JSONResponse(response.BAD_SIGNATURE);
@@ -41,8 +42,9 @@ export async function addGroupRoleHandler(request: IRequest, env: env) {
4142
try {
4243
await verifyAuthToken(authHeader, env);
4344
const body: memberGroupRole = await request.json();
45+
const reason = request.headers.get("X-Audit-Log-Reason");
4446

45-
const res = await addGroupRole(body, env);
47+
const res = await addGroupRole(body, env, reason);
4648
return new JSONResponse(res);
4749
} catch (err) {
4850
return new JSONResponse(response.BAD_SIGNATURE);
@@ -54,15 +56,20 @@ export async function getGuildRolesPostHandler(request: IRequest, env: env) {
5456
if (!authHeader) {
5557
return new JSONResponse(response.BAD_SIGNATURE);
5658
}
59+
const reason = request.headers.get("X-Audit-Log-Reason");
5760

5861
try {
59-
await verifyAuthToken(authHeader, env);
62+
await verifyCronJobsToken(authHeader, env);
6063
const { action } = request.query;
6164

6265
switch (action) {
6366
case GROUP_ROLE_ADD.ADD_ROLE: {
6467
const memberGroupRoleList = await request.json();
65-
const res = await bulkAddGroupRoleHandler(memberGroupRoleList, env);
68+
const res = await bulkAddGroupRoleHandler(
69+
memberGroupRoleList,
70+
env,
71+
reason
72+
);
6673
return res;
6774
}
6875
default: {
@@ -77,7 +84,8 @@ export async function getGuildRolesPostHandler(request: IRequest, env: env) {
7784

7885
export async function bulkAddGroupRoleHandler(
7986
memberGroupRoleList: memberGroupRole[],
80-
env: env
87+
env: env,
88+
reason?: string
8189
): Promise<JSONResponse> {
8290
try {
8391
if (!Array.isArray(memberGroupRoleList)) {
@@ -105,12 +113,13 @@ export async function bulkAddGroupRoleHandler(
105113
const { userid, roleid } = memberGroupRole;
106114
try {
107115
const createGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members/${userid}/roles/${roleid}`;
116+
const headers: HeadersInit = createDiscordHeaders({
117+
reason,
118+
token: env.DISCORD_TOKEN,
119+
});
108120
const options = {
109121
method: "PUT",
110-
headers: {
111-
"Content-Type": "application/json",
112-
Authorization: `Bot ${env.DISCORD_TOKEN}`,
113-
},
122+
headers,
114123
};
115124
return await fetch(createGuildRoleUrl, options);
116125
} catch (error) {
@@ -141,13 +150,15 @@ export async function bulkAddGroupRoleHandler(
141150

142151
export async function removeGuildRoleHandler(request: IRequest, env: env) {
143152
const authHeader = request.headers.get("Authorization");
153+
const reason = request.headers.get("X-Audit-Log-Reason");
154+
144155
if (!authHeader) {
145156
return new JSONResponse(response.BAD_SIGNATURE, { status: 401 });
146157
}
147158
try {
148159
await verifyAuthToken(authHeader, env);
149160
const body: memberGroupRole = await request.json();
150-
const res = await removeGuildRole(body, env);
161+
const res = await removeGuildRole(body, env, reason);
151162
return new JSONResponse(res, {
152163
status: 200,
153164
headers: {

src/utils/createDiscordHeaders.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const createDiscordHeaders = ({
2+
reason,
3+
token,
4+
}: {
5+
reason?: string;
6+
token: string;
7+
}) => {
8+
const headers: HeadersInit = {
9+
"Content-Type": "application/json",
10+
Authorization: `Bot ${token}`,
11+
};
12+
if (reason) {
13+
headers["X-Audit-Log-Reason"] = reason;
14+
}
15+
return headers;
16+
};
17+
export default createDiscordHeaders;

src/utils/formatTask.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ export function generateTaskResponseMessage(
2121
formattedTasks: string[],
2222
status: string
2323
) {
24-
const title = `## ${formatStatusToTitleCase(status)} Tasks of ${nickName}`;
24+
const title =
25+
formattedTasks.length !== 0
26+
? `## ${formatStatusToTitleCase(status)} Tasks of ${nickName}`
27+
: `## ${nickName} doesn't have any in-progress task`;
2528
const tasks = formattedTasks.join("\n\n");
2629
const allTaskLink = `[→ All Tasks](${RDS_STATUS_SITE_URL}/tasks?q=status:all+assignee:${nickName})
2730
`;

src/utils/generateDiscordInvite.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ import {
1010
import { DISCORD_BASE_URL } from "../constants/urls";
1111
import { env } from "../typeDefinitions/default.types";
1212
import { inviteLinkBody } from "../typeDefinitions/discordLink.types";
13+
import createDiscordHeaders from "./createDiscordHeaders";
1314

14-
export async function generateDiscordLink(body: inviteLinkBody, env: env) {
15+
export async function generateDiscordLink(
16+
body: inviteLinkBody,
17+
env: env,
18+
reason?: string
19+
) {
1520
const { channelId } = body;
1621
const generateInviteUrl = `${DISCORD_BASE_URL}/channels/${channelId}/invites`;
1722

@@ -20,13 +25,14 @@ export async function generateDiscordLink(body: inviteLinkBody, env: env) {
2025
unique: INVITE_OPTIONS.UNIQUE, // Whether to create a unique invite or not
2126
};
2227
try {
28+
const headers: HeadersInit = createDiscordHeaders({
29+
reason,
30+
token: env.DISCORD_TOKEN,
31+
});
2332
const response = await fetch(generateInviteUrl, {
2433
method: "POST",
2534
body: JSON.stringify(inviteOptions),
26-
headers: {
27-
"Content-Type": "application/json",
28-
Authorization: `Bot ${env.DISCORD_TOKEN}`,
29-
},
35+
headers,
3036
});
3137

3238
if (response.ok) {

src/utils/guildRole.ts

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { HeadersInit } from "node-fetch";
12
import {
23
INTERNAL_SERVER_ERROR,
34
ROLE_ADDED,
@@ -12,23 +13,26 @@ import {
1213
memberGroupRole,
1314
} from "../typeDefinitions/discordMessage.types";
1415
import { GuildRole, Role } from "../typeDefinitions/role.types";
16+
import createDiscordHeaders from "./createDiscordHeaders";
1517

1618
export async function createGuildRole(
1719
body: createNewRole,
18-
env: env
20+
env: env,
21+
reason?: string
1922
): Promise<guildRoleResponse | string> {
2023
const createGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/roles`;
2124
const data = {
2225
...body,
2326
name: body.rolename,
2427
};
28+
const headers: HeadersInit = createDiscordHeaders({
29+
reason,
30+
token: env.DISCORD_TOKEN,
31+
});
2532
try {
2633
const response = await fetch(createGuildRoleUrl, {
2734
method: "POST",
28-
headers: {
29-
"Content-Type": "application/json",
30-
Authorization: `Bot ${env.DISCORD_TOKEN}`,
31-
},
35+
headers,
3236
body: JSON.stringify(data),
3337
});
3438
if (response.ok) {
@@ -41,16 +45,21 @@ export async function createGuildRole(
4145
}
4246
}
4347

44-
export async function addGroupRole(body: memberGroupRole, env: env) {
48+
export async function addGroupRole(
49+
body: memberGroupRole,
50+
env: env,
51+
reason?: string
52+
) {
4553
const { userid, roleid } = body;
4654
const createGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members/${userid}/roles/${roleid}`;
4755
try {
56+
const headers: HeadersInit = createDiscordHeaders({
57+
reason,
58+
token: env.DISCORD_TOKEN,
59+
});
4860
const response = await fetch(createGuildRoleUrl, {
4961
method: "PUT",
50-
headers: {
51-
"Content-Type": "application/json",
52-
Authorization: `Bot ${env.DISCORD_TOKEN}`,
53-
},
62+
headers,
5463
});
5564
if (response.ok) {
5665
return { message: ROLE_ADDED };
@@ -62,16 +71,21 @@ export async function addGroupRole(body: memberGroupRole, env: env) {
6271
}
6372
}
6473

65-
export async function removeGuildRole(details: memberGroupRole, env: env) {
74+
export async function removeGuildRole(
75+
details: memberGroupRole,
76+
env: env,
77+
reason?: string
78+
) {
6679
const { userid, roleid } = details;
6780
const removeGuildRoleUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members/${userid}/roles/${roleid}`;
6881
try {
82+
const headers: HeadersInit = createDiscordHeaders({
83+
reason,
84+
token: env.DISCORD_TOKEN,
85+
});
6986
const response = await fetch(removeGuildRoleUrl, {
7087
method: "DELETE",
71-
headers: {
72-
"Content-Type": "application/json",
73-
Authorization: `Bot ${env.DISCORD_TOKEN}`,
74-
},
88+
headers,
7589
});
7690
if (response.ok) {
7791
return {
@@ -91,12 +105,12 @@ export async function getGuildRoles(env: env): Promise<Array<Role>> {
91105
const guildRolesUrl = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/roles`;
92106

93107
try {
108+
const headers: HeadersInit = createDiscordHeaders({
109+
token: env.DISCORD_TOKEN,
110+
});
94111
const response = await fetch(guildRolesUrl, {
95112
method: "GET",
96-
headers: {
97-
"Content-Type": "application/json",
98-
Authorization: `Bot ${env.DISCORD_TOKEN}`,
99-
},
113+
headers,
100114
});
101115

102116
if (!response.ok) {

src/utils/updateNickname.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
import { INTERNAL_SERVER_ERROR, NAME_CHANGED } from "../constants/responses";
22
import { DISCORD_BASE_URL } from "../constants/urls";
33
import { env } from "../typeDefinitions/default.types";
4+
import createDiscordHeaders from "./createDiscordHeaders";
45

56
export async function updateNickName(
67
discordId: string,
78
nickname: string,
8-
env: env
9+
env: env,
10+
reason?: string
911
) {
1012
const changeNickNameURL = `${DISCORD_BASE_URL}/guilds/${env.DISCORD_GUILD_ID}/members/${discordId}`;
1113
const data = { nick: nickname };
14+
const headers: HeadersInit = createDiscordHeaders({
15+
reason,
16+
token: env.DISCORD_TOKEN,
17+
});
1218
try {
1319
const nameChangeResponse = await fetch(changeNickNameURL, {
1420
method: "PATCH",
15-
headers: {
16-
"Content-Type": "application/json",
17-
Authorization: `Bot ${env.DISCORD_TOKEN}`,
18-
},
21+
headers,
1922
body: JSON.stringify(data),
2023
});
2124
if (nameChangeResponse.ok) {

src/utils/verifyAuthToken.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,25 @@ export async function verifyAuthToken(authHeader: string, env: env) {
2424
throw new Error(AUTHENTICATION_ERROR);
2525
}
2626
}
27+
28+
/**
29+
*
30+
* @param authHeader { string } : the auth header of request
31+
* @param env { env }: the ctx (context) which contains the secrets put in as wrangler secrets.
32+
*/
33+
export async function verifyCronJobsToken(authHeader: string, env: env) {
34+
if (!authHeader) {
35+
throw new Error(INVALID_TOKEN_FORMAT);
36+
}
37+
const authHeaderParts = authHeader.split(" ");
38+
if (authHeaderParts.length !== 2 || authHeaderParts[0] !== "Bearer") {
39+
throw new Error(INVALID_TOKEN_FORMAT);
40+
}
41+
const authToken = authHeaderParts[1];
42+
const isValid = await jwt.verify(authToken, env.CRON_JOBS_PUBLIC_KEY, {
43+
algorithm: "RS256",
44+
});
45+
if (!isValid) {
46+
throw new Error(AUTHENTICATION_ERROR);
47+
}
48+
}

tests/fixtures/fixture.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export const dummyAddRoleBody: memberGroupRole = {
5454
export const guildEnv = {
5555
DISCORD_GUILD_ID: "1234",
5656
DISCORD_TOKEN: "abcd",
57+
CRON_JOBS_PUBLIC_KEY: "test",
5758
};
5859

5960
export const dummyInviteBody = {

0 commit comments

Comments
 (0)