From fbe72a5a852be7e37416029a1e58978128d29b79 Mon Sep 17 00:00:00 2001 From: Ibrahim Ansari Date: Sat, 11 Jul 2020 21:43:40 +0530 Subject: [PATCH] Check for permissions in all admin commands, update /ec and README. --- README.md | 85 +++++++++++++++------------ server/bot/commands/admin/ban.ts | 4 ++ server/bot/commands/admin/channels.ts | 20 +++++-- server/bot/commands/admin/emoji.ts | 12 +++- server/bot/commands/admin/index.ts | 15 ++++- server/bot/commands/admin/mute.ts | 5 ++ server/bot/commands/admin/roles.ts | 18 +++++- 7 files changed, 111 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index ace09af..230d7d5 100644 --- a/README.md +++ b/README.md @@ -4,64 +4,73 @@ The bot that created the iPhone X. It's strictly private. You may run it locally **Requires Node.js 8.5.0 or higher.** +It includes many different and useful commands, from games to tools, utilities, fun commands and moderation. It also uses Next.js to provide a web dashboard as part of the bot itself. + It's planned to have some nifty commands like /assistant which directly communicates with the Google Assistant gRPC API. You heard that, Google Assistant in a Discord bot. -2.0 is built upon Next.js with administrative commands and a web dashboard. 3.0 in development uses Eris and is a rewritten and refined codebase focused on stability and a framework for further enhancements. +1.0 and 2.0 used discord.io while 3.0 uses Eris and is much more refined and full-featured. It is highly recommended to use 3.0 as older versions are unsupported and may not connect to Discord's API gateway anymore.
Commands
-\`/halp\` and \`/help\` - The most innovative help. +`/halp` and `/help` - The most innovative help. **Games.** -- \`/gunfight\` -- \`/random\` -- \`/randomword\` -- \`/choose\` -- \`/reverse\` -- \`/8ball\` -- \`/repeat\` -- \`/calculate\` -- \`/distort\` +- `/gunfight` +- `/random` +- `/randomword` +- `/choose` +- `/reverse` +- `/8ball` +- `/repeat` +- `/calculate` +- `/distort` **Random searches.** -- \`/urban\` -- \`/cat\` and \`/dog\` -- \`/robohash\` -- \`/zalgo\` \`/dezalgo\` -- \`/namemc\` -- \`/astronomy-picture-of-the-day\` or \`/apod\` -- \`/currency\` +- `/urban` +- `/cat` and `/dog` +- `/robohash` +- `/zalgo` `/dezalgo` +- `/namemc` +- `/astronomy-picture-of-the-day` or `/apod` +- `/currency` +- `/xkcd` +- `/httpcat` **Utilities.** -- \`/request\` (for test pilots) -- \`/token\` -- \`/weather\` -- \`/say\` | \`/type\` -- \`/editLastSay\` -- \`/remindme\` -- \`/leave\` -- \`/ocr\` -- \`/avatar\` -- \`/userinfo\` -- \`/serverinfo\` -- \`/about\`, \`/ping\`, \`/uptime\` and \`/version\` -- \`/giverole\` and \`/takerole\` +- `/request` +- `/token` +- `/weather` +- `/say` | `/type` +- `/editLastSay` +- `/remindme` +- `/leave` +- `/ocr` +- `/avatar` +- `/userinfo` +- `/serverinfo` +- `/creationtime` +- `/about`, `/ping`, `/uptime` and `/version` +- `/emojiImage` +- `/giverole` and `/takerole` +- `/notify` **Administrative commands.** -- \`/deleteChannel\` and \`/editChannel\` -- \`/changeserverregion\` and \`/listserverregions\` -- \`/ban\`, \`/unban\`, \`/kick\`, \`/mute\` and \`/unmute\` -- \`/warn\` and \`/warnings\` | \`/clearwarns\` and \`/removewarn\` -- \`/addEmoji\`, \`/deleteEmoji\`, \`/emojiImage\` and \`/editEmoji\` -- \`/purge\` -- \`/slowmode\` +- `/deleteChannel` and `/editChannel` +- `/changeserverregion` and `/listserverregions` +- `/ban`, `/unban`, `/kick`, `/mute` and `/unmute` +- `/warn` and `/warnings` | `/clearwarns` and `/removewarn` +- `/addEmoji`, `/deleteEmoji` and `/editEmoji` +- `/purge` +- `/slowmode` + +[Complete list of commands along with their descriptions available here.](https://github.com/retrixe/IveBot/blob/master/server/bot/commands/help.ts#L6)

diff --git a/server/bot/commands/admin/ban.ts b/server/bot/commands/admin/ban.ts index e3bd336..1373252 100644 --- a/server/bot/commands/admin/ban.ts +++ b/server/bot/commands/admin/ban.ts @@ -95,6 +95,10 @@ export const handleUnban: Command = { requirements: { permissions: { 'banMembers': true } } }, generator: async (message, args, { client }) => { + // Check bot for permissions. + if (!message.member.guild.members.get(client.user.id).permission.has('banMembers')) { + return `I lack permission to unban members, you ${getInsult()}.` + } // Find the user ID. const userSpecified = args.shift() let user: User diff --git a/server/bot/commands/admin/channels.ts b/server/bot/commands/admin/channels.ts index adf5cb9..40c4ed2 100644 --- a/server/bot/commands/admin/channels.ts +++ b/server/bot/commands/admin/channels.ts @@ -12,12 +12,18 @@ export const handleDeletechannel: Command = { guildOnly: true, requirements: { permissions: { 'manageChannels': true } } }, - generator: async (message, args) => { + generator: async (message, args, { client }) => { // Get the channel ID. const channel = getChannel(message, args.shift()) if (!channel) return `Specify a valid channel, you ${getInsult()}!` + // If no permission to manage channels, say it. + if (!message.member.guild.members.get(client.user.id).permission.has('manageChannels')) { + return 'I can\'t even delete that channel, you ' + getInsult() + '.' + } // Delete it. - await channel.delete(args.join(' ')) + try { + await channel.delete(args.join(' ')) + } catch (e) { return 'I was unable to delete that channel >_<' } // Confirm the delete. return `Channel \`${channel.name}\` deleted.` } @@ -36,10 +42,14 @@ export const handleEditchannel: Command = { guildOnly: true, requirements: { permissions: { 'manageChannels': true } } }, - generator: async (message, args) => { + generator: async (message, args, { client }) => { // Get the channel ID. const channel = getChannel(message, args.shift()) if (!channel) return `Specify a valid channel, you ${getInsult()}!` + // If no permission to manage channel, say it. + if (!channel.permissionsOf(client.user.id).has('manageChannels')) { + return 'I can\'t edit that channel, you ' + getInsult() + '.' + } // Get the operations. const ops: string[] = args.join(' ').split('|') // Now iterate over each operation and execute them. @@ -69,8 +79,8 @@ export const handleEditchannel: Command = { }) } else if (name === 'nsfw' && value !== 'true' && value !== 'false') { failedOps.push({ name: `❌ ${operation}`, value: 'NSFW must be either true or false.' }) - } else if (name === 'bitrate' && (isNaN(+value) || +value < 8 || +value > 96)) { - failedOps.push({ name: `❌ ${operation}`, value: 'bitrate must be a number between 8-96.' }) + } else if (name === 'bitrate' && (isNaN(+value) || +value < 8 || +value > 384)) { + failedOps.push({ name: `❌ ${operation}`, value: 'bitrate must be a number between 8-384.' }) } else if (name === 'userLimit' && (isNaN(+value) || +value > 99 || +value < 0)) { failedOps.push({ name: `❌ ${operation}`, value: 'userLimit must be a number between 0-99.' }) // Now we edit the channel. diff --git a/server/bot/commands/admin/emoji.ts b/server/bot/commands/admin/emoji.ts index af9b837..59fd5fd 100644 --- a/server/bot/commands/admin/emoji.ts +++ b/server/bot/commands/admin/emoji.ts @@ -71,7 +71,11 @@ export const handleDeleteemoji: Command = { guildOnly: true, requirements: { permissions: { 'manageEmojis': true } } }, - generator: async (message, args) => { + generator: async (message, args, { client }) => { + // Check bot permissions. + if (!message.member.guild.members.get(client.user.id).permission.has('manageEmojis')) { + return `I don't even have permissions to do that, you ${getInsult()}.` + } // Try deleting it, else throw an error. try { const emoji = message.member.guild.emojis.find( @@ -98,9 +102,13 @@ export const handleEditemoji: Command = { guildOnly: true, requirements: { permissions: { 'manageEmojis': true } } }, - generator: async (message, args) => { + generator: async (message, args, { client }) => { // Check if enough arguments were provided. if (args.length !== 2) return 'Correct usage: /editEmoji ' + // Check bot permissions. + if (!message.member.guild.members.get(client.user.id).permission.has('manageEmojis')) { + return `I don't even have permissions to do that, you ${getInsult()}.` + } // Try editing it, else throw an error. try { const emoji = message.member.guild.emojis.find( diff --git a/server/bot/commands/admin/index.ts b/server/bot/commands/admin/index.ts index b7e0722..19658cd 100644 --- a/server/bot/commands/admin/index.ts +++ b/server/bot/commands/admin/index.ts @@ -44,6 +44,11 @@ export const handlePurge: Command = { if ( isNaN(+args[0]) || args.length !== 1 || +args[0] <= 0 || +args[0] > 100 ) { return 'Correct usage: /purge ' } + // Check bot for permissions. + const permission = message.member.guild.channels.get(message.channel.id).permissionsOf(client.user.id) + if (!permission.has('manageMessages')) { + return `I lack permission to purge messages in this channel, you ${getInsult()}.` + } // Pre-defined variables. let messages: Array // Get the list of messages. @@ -130,16 +135,22 @@ export const handleSlowmode: Command = { permissions: { 'manageChannels': true }, custom: (message) => ( message.member.guild.channels.get(message.channel.id) - .permissionsOf(message.author.id).has('manageChannels') + .permissionsOf(message.author.id).has('manageChannels') || + message.member.guild.channels.get(message.channel.id) + .permissionsOf(message.author.id).has('manageMessages') ) } }, generator: async (message, args, { client }) => { - // Check user for permissions. const t = +args[0] if ( (isNaN(t) && args[0] !== 'off') || !args[0] || t < 0 || t > 120 || args.length > 1 ) { return 'Correct usage: /slowmode ' } + // Check bot for permissions. + const permission = message.member.guild.channels.get(message.channel.id).permissionsOf(client.user.id) + if (!permission.has('manageMessages') && !permission.has('manageChannels')) { + return `I lack permission to set slowmode in this channel, you ${getInsult()}.` + } // Set slowmode. try { await client.editChannel(message.channel.id, { rateLimitPerUser: isNaN(t) ? 0 : t }) diff --git a/server/bot/commands/admin/mute.ts b/server/bot/commands/admin/mute.ts index d0ae608..ea45368 100644 --- a/server/bot/commands/admin/mute.ts +++ b/server/bot/commands/admin/mute.ts @@ -71,6 +71,11 @@ export const handleMute: Command = { }) } catch (e) { return 'I cannot set permissions for the Muted role.' } } + // Can the bot manage this role? + if ( + role.position >= checkRolePosition(message.member.guild.members.get(client.user.id)) || + !message.member.guild.members.get(client.user.id).permission.has('manageRoles') + ) return `I lack permissions to mute people with the role, you ${getInsult()}.` // Mute person. try { await client.addGuildMemberRole(message.member.guild.id, user.id, role.id, args.join(' ')) diff --git a/server/bot/commands/admin/roles.ts b/server/bot/commands/admin/roles.ts index cfe25f9..e82056c 100644 --- a/server/bot/commands/admin/roles.ts +++ b/server/bot/commands/admin/roles.ts @@ -33,6 +33,11 @@ export const handleGiverole: Command = { // Can the user manage this role? if (role.position >= checkRolePosition(message.member) && !isPublicRole ) return `You cannot give this role. Pfft, overestimating their own powers now.` + // Can the bot manage this role? + if ( + role.position >= checkRolePosition(message.member.guild.members.get(client.user.id)) || + !message.member.guild.members.get(client.user.id).permission.has('manageRoles') + ) return `I lack permissions to give this role, you ${getInsult()}.` // Give the role. const rolesOfMember = user.id !== message.author.id // Ternary statement. ? message.member.guild.members.find(a => a.id === user.id).roles @@ -86,6 +91,11 @@ export const handleTakerole: Command = { // Can the user manage this role? if (role.position >= checkRolePosition(message.member) && !isPublicRole ) return `You cannot take this role. Pfft, overestimating their own powers now.` + // Can the bot manage this role? + if ( + role.position >= checkRolePosition(message.member.guild.members.get(client.user.id)) || + !message.member.guild.members.get(client.user.id).permission.has('manageRoles') + ) return `I lack permissions to take this role, you ${getInsult()}.` // Give the role. const rolesOfMember = user.id !== message.author.id // Ternary statement. ? message.member.guild.members.find(a => a.id === user.id).roles @@ -119,7 +129,7 @@ export const handleNotify: Command = { deleteCommand: true, requirements: { permissions: { 'manageRoles': true } } }, - generator: async (message, args) => { + generator: async (message, args, { client }) => { // Find the role. const arg = args.shift() const role = message.member.guild.roles.find( @@ -129,6 +139,12 @@ export const handleNotify: Command = { // Can the user manage this role? if (role.position >= checkRolePosition(message.member) && !role.mentionable ) return `You cannot notify this role, you ${getInsult()}.` + // Can the bot manage this role? + if ( + (role.position >= checkRolePosition(message.member.guild.members.get(client.user.id)) || + !message.member.guild.members.get(client.user.id).permission.has('manageRoles')) && + !role.mentionable + ) return `I cannot notify this role, you ${getInsult()}.` // Edit the role. const wasMentionable = role.mentionable if (!wasMentionable) await role.edit({ mentionable: true })