From c4c9f8ef7cf7caee1c59702017112c0225cfa7b1 Mon Sep 17 00:00:00 2001 From: Yash Raj <56453897+yesyash@users.noreply.github.com> Date: Fri, 11 Oct 2024 23:43:26 +0530 Subject: [PATCH] add super user check in kickEachUser action (#267) * add super user check in kickEachUser action * revert hot:fix /remove command removed * fix:linting * fix: test fail due to change in function signature * Add test for super user check --------- Co-authored-by: Shubham Raj --- src/controllers/baseHandler.ts | 26 +++++------ src/controllers/kickEachUser.ts | 12 +++++ src/register.ts | 2 + src/typeDefinitions/discordMessage.types.d.ts | 2 +- tests/fixtures/fixture.ts | 25 +++++++++++ tests/unit/handlers/kickEachUser.test.ts | 45 ++++++++++++++++--- 6 files changed, 91 insertions(+), 21 deletions(-) diff --git a/src/controllers/baseHandler.ts b/src/controllers/baseHandler.ts index d53b78bf..2d36c389 100644 --- a/src/controllers/baseHandler.ts +++ b/src/controllers/baseHandler.ts @@ -27,6 +27,7 @@ import { NOTIFY_ONBOARDING, OOO, USER, + REMOVE, GROUP_INVITE, } from "../constants/commands"; import { updateNickName } from "../utils/updateNickname"; @@ -41,7 +42,7 @@ import { RETRY_COMMAND, } from "../constants/responses"; import { DevFlag } from "../typeDefinitions/filterUsersByRole"; -// import { kickEachUser } from "./kickEachUser"; +import { kickEachUser } from "./kickEachUser"; import { groupInvite } from "./groupInvite"; export async function baseHandler( @@ -78,19 +79,16 @@ export async function baseHandler( return await mentionEachUser(transformedArgument, env, ctx); } - /** - * HOT FIX to prevent non superusers from running the /remove commmand. - * More info :- https://discord.com/channels/673083527624916993/729399523268624405/1293604361758441605 - * --- - */ - // case getCommandName(REMOVE): { - // const data = message.data?.options as Array; - // const transformedArgument = { - // roleToBeRemovedObj: data[0], - // channelId: message.channel_id, - // }; - // return await kickEachUser(transformedArgument, env, ctx); - // } + case getCommandName(REMOVE): { + const data = message.data?.options as Array; + const transformedArgument = { + member: message.member, + roleToBeRemovedObj: data[0], + channelId: message.channel_id, + }; + + return await kickEachUser(transformedArgument, env, ctx); + } case getCommandName(LISTENING): { const data = message.data?.options; diff --git a/src/controllers/kickEachUser.ts b/src/controllers/kickEachUser.ts index 68566894..efa2a881 100644 --- a/src/controllers/kickEachUser.ts +++ b/src/controllers/kickEachUser.ts @@ -7,15 +7,27 @@ import { getMembersInServer } from "../utils/getMembersInServer"; import { filterUserByRoles } from "../utils/filterUsersByRole"; import { discordTextResponse } from "../utils/discordResponse"; import { removeUsers } from "../utils/removeUsers"; +import { SUPER_USER_ONE, SUPER_USER_TWO } from "../constants/variables"; +import { messageRequestMember } from "../typeDefinitions/discordMessage.types"; export async function kickEachUser( transformedArgument: { + member: messageRequestMember; roleToBeRemovedObj: MentionEachUserOptions; channelId: number; }, env: env, ctx: ExecutionContext ) { + const isUserSuperUser = [SUPER_USER_ONE, SUPER_USER_TWO].includes( + transformedArgument.member.user.id.toString() + ); + + if (!isUserSuperUser) { + const responseText = `You're not authorized to make this request.`; + return discordTextResponse(responseText); + } + const getMembersInServerResponse = await getMembersInServer(env); const roleId = transformedArgument.roleToBeRemovedObj.value; diff --git a/src/register.ts b/src/register.ts index 1ca0f302..6bd22737 100644 --- a/src/register.ts +++ b/src/register.ts @@ -8,6 +8,7 @@ import { NOTIFY_ONBOARDING, OOO, USER, + REMOVE, GROUP_INVITE, } from "./constants/commands"; import { config } from "dotenv"; @@ -38,6 +39,7 @@ async function registerGuildCommands( USER, NOTIFY_OVERDUE, NOTIFY_ONBOARDING, + REMOVE, GROUP_INVITE, ]; diff --git a/src/typeDefinitions/discordMessage.types.d.ts b/src/typeDefinitions/discordMessage.types.d.ts index 451a712d..7101d51f 100644 --- a/src/typeDefinitions/discordMessage.types.d.ts +++ b/src/typeDefinitions/discordMessage.types.d.ts @@ -77,7 +77,7 @@ export interface messageRequestMember { } export interface messageMember { - id: number; + id: number | bigint; username: string; avatar: string; discriminator: string; diff --git a/tests/fixtures/fixture.ts b/tests/fixtures/fixture.ts index ecc0453c..c5d9855f 100644 --- a/tests/fixtures/fixture.ts +++ b/tests/fixtures/fixture.ts @@ -8,6 +8,7 @@ import { InteractionType } from "discord-interactions"; import { UserBackend } from "../../src/typeDefinitions/userBackend.types"; import { TaskOverdueResponse } from "../../src/typeDefinitions/taskOverdue.types"; import { UserStatus } from "../../src/typeDefinitions/userStatus.type"; +import { SUPER_USER_ONE } from "../../src/constants/variables"; export const dummyHelloMessage: discordMessageRequest = { type: InteractionType.APPLICATION_COMMAND, @@ -292,6 +293,30 @@ export const userFutureStatusMock: UserStatus = { message: "User Status found successfully.", }; +export const messageRequestMemberMockNonSuperUser = { + member: { + user: { + id: 123455, + username: "ankush", + avatar: "https://cdn.discordapp.com/avatars/1/userAvatarHash.jpg", + discriminator: "discriminator", + }, + joined_at: "2024-03-07T18:46:20.327000+00:00", + }, +}; + +export const messageRequestMemberMockSuperUser = { + member: { + user: { + id: 154585730465660929n, + username: "ankush", + avatar: "https://cdn.discordapp.com/avatars/1/userAvatarHash.jpg", + discriminator: "discriminator", + }, + joined_at: "2024-03-07T18:46:20.327000+00:00", + }, +}; + export const memberGroupRoleList: memberGroupRole[] = [ { userid: "XXXX", roleid: "XXXX" }, { userid: "YYYY", roleid: "YYYY" }, diff --git a/tests/unit/handlers/kickEachUser.test.ts b/tests/unit/handlers/kickEachUser.test.ts index a12e05d5..9a432fc9 100644 --- a/tests/unit/handlers/kickEachUser.test.ts +++ b/tests/unit/handlers/kickEachUser.test.ts @@ -1,8 +1,13 @@ import { kickEachUser } from "../../../src/controllers/kickEachUser"; -import { transformedArgument, ctx } from "../../fixtures/fixture"; +import { + transformedArgument, + ctx, + messageRequestMemberMockSuperUser, + messageRequestMemberMockNonSuperUser, +} from "../../fixtures/fixture"; describe("kickEachUser", () => { - it("should run when found no users with Matched Role", async () => { + it("should fail when a non super_user runs ", async () => { const env = { BOT_PUBLIC_KEY: "xyz", DISCORD_GUILD_ID: "123", @@ -10,11 +15,39 @@ describe("kickEachUser", () => { }; const { roleToBeTaggedObj } = transformedArgument; // Extracting roleToBeTaggedObj - const response = kickEachUser( - { roleToBeRemovedObj: roleToBeTaggedObj, channelId: 12345 }, - env, - ctx + const messageRequestMember = { + roleToBeRemovedObj: roleToBeTaggedObj, + channelId: 12345, + ...messageRequestMemberMockNonSuperUser, + }; + const response = kickEachUser(messageRequestMember, env, ctx); + + const roleID = roleToBeTaggedObj.value; + + expect(response).toBeInstanceOf(Promise); + + const textMessage: { data: { content: string } } = await response.then( + (res) => res.json() + ); + expect(textMessage.data.content).toBe( + `You're not authorized to make this request.` ); + }); + + it("should run when found no users with Matched Role", async () => { + const env = { + BOT_PUBLIC_KEY: "xyz", + DISCORD_GUILD_ID: "123", + DISCORD_TOKEN: "abc", + }; + + const { roleToBeTaggedObj } = transformedArgument; // Extracting roleToBeTaggedObj + const messageRequestMember = { + roleToBeRemovedObj: roleToBeTaggedObj, + channelId: 12345, + ...messageRequestMemberMockSuperUser, + }; + const response = kickEachUser(messageRequestMember, env, ctx); const roleID = roleToBeTaggedObj.value;