From 3e1da96360251e0939e5ed4bd4894bd8bcdd7688 Mon Sep 17 00:00:00 2001 From: JandereDev Date: Sat, 9 Oct 2021 22:20:06 +0200 Subject: [PATCH] code --- .vscode/launch.json | 14 ++++++ src/bot/commands/debug.ts | 17 +++++++ src/bot/commands/ping.ts | 20 ++++++++ src/bot/commands/prefix.ts | 74 ++++++++++++++++++++++++++++++ src/bot/commands/test.ts | 3 +- src/bot/db.ts | 6 +-- src/bot/modules/command_handler.ts | 21 +++++++-- src/bot/util.ts | 27 +++++++++++ src/struct/Command.ts | 1 + src/struct/ServerConfig.ts | 7 +++ 10 files changed, 182 insertions(+), 8 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 src/bot/commands/debug.ts create mode 100644 src/bot/commands/ping.ts create mode 100644 src/bot/commands/prefix.ts create mode 100644 src/bot/util.ts create mode 100644 src/struct/ServerConfig.ts diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9f681f5 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "command": "yarn dev", + "name": "Debug", + "request": "launch", + "type": "node-terminal" + } + ] +} \ No newline at end of file diff --git a/src/bot/commands/debug.ts b/src/bot/commands/debug.ts new file mode 100644 index 0000000..eae9355 --- /dev/null +++ b/src/bot/commands/debug.ts @@ -0,0 +1,17 @@ +import Command from "../../struct/Command"; +import { Message } from "revolt.js/dist/maps/Messages"; +import { hasPerm } from "../util"; + +export default { + name: 'debug', + aliases: null, + description: 'give info helpful for development and debugging', + serverOnly: false, + run: (message: Message, args: string[]) => { + message.reply(`Server ID: ${message.channel?.server_id || 'None'}\n` + + `Channel ID: ${message.channel_id}\n` + + `User ID: ${message.author_id}`); + + console.log(hasPerm(message.member!, 'BanMembers')); + } +} as Command; diff --git a/src/bot/commands/ping.ts b/src/bot/commands/ping.ts new file mode 100644 index 0000000..ef3556b --- /dev/null +++ b/src/bot/commands/ping.ts @@ -0,0 +1,20 @@ +import Command from "../../struct/Command"; +import { Message } from "revolt.js/dist/maps/Messages"; +import { client } from "../.."; + +export default { + name: 'ping', + aliases: null, + description: 'ping pong', + serverOnly: false, + run: async (message: Message, args: string[]) => { + let now = Date.now(); + message.reply(`Measuring...`) + ?.catch(console.error) + .then(msg => { + msg?.edit({ content: `## Ping Pong!\n` + + `WS: \`${client.websocket.ping ?? '--'}ms\`\n` + + `Msg: \`${Math.round(Date.now() - now) / 2}ms\`` }); + }); + } +} as Command; diff --git a/src/bot/commands/prefix.ts b/src/bot/commands/prefix.ts new file mode 100644 index 0000000..b97f3a6 --- /dev/null +++ b/src/bot/commands/prefix.ts @@ -0,0 +1,74 @@ +import Command from "../../struct/Command"; +import { Message } from "revolt.js/dist/maps/Messages"; +import { client } from "../.."; +import ServerConfig from "../../struct/ServerConfig"; +import { DEFAULT_PREFIX } from "../modules/command_handler"; +import { hasPerm } from "../util"; + +const SYNTAX = '/prefix set [new prefix]; /prefix get; prefix clear'; +const MENTION_TEXT = 'You can also @mention me instead of using the prefix.'; + +export default { + name: 'prefix', + aliases: null, + description: 'modify prefix', + syntax: SYNTAX, + serverOnly: true, + run: async (message: Message, args: string[]) => { + let config: ServerConfig = (await client.db.get('servers').findOne({ id: message.channel?.server_id })) ?? {}; + switch(args[0]?.toLowerCase()) { + case 'set': + if (!hasPerm(message.member!, 'ManageServer')) return message.reply('You need ManageServer permission for this.'); + + args.shift(); + if (args.length == 0) return message.reply('You need to specify a prefix.'); + let newPrefix = args.join(' ').trim(); + let oldPrefix = config.prefix ?? DEFAULT_PREFIX; + + let val = validatePrefix(newPrefix); + if (typeof val != 'boolean') { + return message.reply(val); + } + + await client.db.get('servers').update({ 'id': message.channel?.server_id }, { $set: { 'prefix': newPrefix } }); + + message.reply(`✅ Prefix has been changed from \`${oldPrefix}\` to \`${newPrefix}\`.\n${MENTION_TEXT}`); + break; + case 'get': + case undefined: + if (config.prefix) message.reply(`This server's prefix is \`${config.prefix}\`.\n${MENTION_TEXT}`); + else message.reply(`This server uses the default prefix \`${DEFAULT_PREFIX}\`.\n${MENTION_TEXT}`); + break; + case 'clear': + case 'reset': + if (!hasPerm(message.member!, 'ManageServer')) return message.reply('You need ManageServer permission for this.'); + + if (config.prefix != null) { + await client.db.get('servers').update({ 'id': message.channel?.server_id }, { $set: { 'prefix': null } }); + } + + message.reply(`✅ Prefix has been reset to the default: \`${DEFAULT_PREFIX}\`.`); + break; + default: + message.reply(`Unknown action. Correct syntax: \`${SYNTAX}\``); + } + + } +} as Command; + +function validatePrefix(prefix: string): string|true { + // Check length + if (prefix.length > 32) return 'Prefix may not be longer than 32 characters'; + + // Check for forbidden characters + let matched = []; + for (const char of ['`', '\n', '#']) { + if (prefix.indexOf(char) > -1) matched.push(char); + } + + if (matched.length > 0) return `Prefix may not contain the following characters: ` + + `${matched.map(char => char).join(', ') + .replace(new RegExp('\n', 'g'), '\\n')}`; + + return true; +} diff --git a/src/bot/commands/test.ts b/src/bot/commands/test.ts index 96cc640..27e465c 100644 --- a/src/bot/commands/test.ts +++ b/src/bot/commands/test.ts @@ -1,5 +1,4 @@ import Command from "../../struct/Command"; -import { client } from "../.."; import { Message } from "revolt.js/dist/maps/Messages"; export default { @@ -10,4 +9,4 @@ export default { run: (message: Message, args: string[]) => { message.reply('I am here'); } -} as Command; \ No newline at end of file +} as Command; diff --git a/src/bot/db.ts b/src/bot/db.ts index 33ff32b..510a803 100644 --- a/src/bot/db.ts +++ b/src/bot/db.ts @@ -20,9 +20,9 @@ function getDBUrl() { // mongodb://username:password@hostname:port/dbname let dburl = 'mongodb://'; - dburl += env['DB_USERNAME'] ?? 'root'; - if (env['DB_PASSWORD']) dburl += `:${env['DB_PASSWORD']}`; - dburl += `@${env['DB_HOST']}`; // DB_HOST is assumed to contain the port + if (env['DB_USERNAME']) dburl += env['DB_USERNAME']; + if (env['DB_PASS']) dburl += `:${env['DB_PASS']}`; + dburl += `${process.env['DB_USERNAME'] ? '@' : ''}${env['DB_HOST']}`; // DB_HOST is assumed to contain the port dburl += `/${env['DB_NAME'] ?? 'automod'}`; return dburl; diff --git a/src/bot/modules/command_handler.ts b/src/bot/modules/command_handler.ts index 39dea72..d74f4e0 100644 --- a/src/bot/modules/command_handler.ts +++ b/src/bot/modules/command_handler.ts @@ -3,6 +3,7 @@ import logger from "../logger"; import { client } from "../../index"; import fs from 'fs'; import path from 'path'; +import ServerConfig from "../../struct/ServerConfig"; const DEFAULT_PREFIX = process.env['PREFIX'] ?? '/'; @@ -12,17 +13,29 @@ let commands: Command[] = fs.readdirSync(path.join(__dirname, '..', 'commands')) client.on('message', async message => { logger.debug(`Message -> ${message.content}`); - if (typeof message.content != 'string') return; // Ignore system messages + if (typeof message.content != 'string' || message.author_id == client.user?._id || !message.channel) return; - if (!message.content.startsWith(DEFAULT_PREFIX)) return; + let config: ServerConfig = (await client.db.get('servers').findOne({ 'id': message.channel?.server_id })) ?? {}; + let guildPrefix = config.prefix ?? DEFAULT_PREFIX; let args = message.content.split(' '); - let cmdName = args.shift()?.substr(DEFAULT_PREFIX.length); + let cmdName = args.shift() ?? ''; + + if (cmdName.startsWith(`<@${client.user?._id}>`)) { + cmdName = cmdName.substr(`<@${client.user?._id}>`.length); + if (!cmdName) cmdName = args.shift() ?? ''; // Space between mention and command name + } else if (cmdName.startsWith(guildPrefix)) { + cmdName = cmdName.substr(guildPrefix.length); + if (config.spaceAfterPrefix && !cmdName) cmdName = args.shift() ?? ''; + } + if (!cmdName) return; let cmd = commands.find(c => c.name == cmdName || (c.aliases?.indexOf(cmdName!) ?? -1) > -1); if (!cmd) return; + logger.info(`Command: ${message.author?.username} in ${message.channel?.server?.name}: ${message.content}`); + if (cmd.serverOnly && !message.channel?.server) { return message.reply('This command is not available in direct messages.'); } @@ -33,3 +46,5 @@ client.on('message', async message => { message.reply(`### An error has occurred:\n\`\`\`js\n${e}\n\`\`\``); } }); + +export { DEFAULT_PREFIX } diff --git a/src/bot/util.ts b/src/bot/util.ts new file mode 100644 index 0000000..fe007f5 --- /dev/null +++ b/src/bot/util.ts @@ -0,0 +1,27 @@ +import { Member } from "revolt.js/dist/maps/Members"; + +let ServerPermissions = { + ['View' as string]: 1 << 0, + ['ManageRoles' as string]: 1 << 1, + ['ManageChannels' as string]: 1 << 2, + ['ManageServer' as string]: 1 << 3, + ['KickMembers' as string]: 1 << 4, + ['BanMembers' as string]: 1 << 5, + ['ChangeNickname' as string]: 1 << 12, + ['ManageNicknames' as string]: 1 << 13, + ['ChangeAvatar' as string]: 1 << 14, + ['RemoveAvatars' as string]: 1 << 15, +} + + +function hasPerm(member: Member, perm: 'View'|'ManageRoles'|'ManageChannels'|'ManageServer'| // its late and im tired + 'KickMembers'|'BanMembers'|'ChangeNickname'| // dont judge my code + 'ManageNicknames'|'ChangeAvatar'|'RemoveAvatars') { + let p = ServerPermissions[perm]; + if (member.server?.owner == member.user?._id) return true; + + // TODO how the fuck do bitfields work + return false; +} + +export { hasPerm } diff --git a/src/struct/Command.ts b/src/struct/Command.ts index d47e968..92dba19 100644 --- a/src/struct/Command.ts +++ b/src/struct/Command.ts @@ -2,6 +2,7 @@ class Command { name: string; aliases: string[] | null; description: string | null; + syntax?: string | null; run: Function; serverOnly: boolean; } diff --git a/src/struct/ServerConfig.ts b/src/struct/ServerConfig.ts new file mode 100644 index 0000000..0cd1226 --- /dev/null +++ b/src/struct/ServerConfig.ts @@ -0,0 +1,7 @@ +class ServerConfig { + id: string | undefined; + prefix: string | undefined; + spaceAfterPrefix: boolean | undefined; +} + +export default ServerConfig;