From a06c3547fb772eed6d7e7ea7dba9ea255cf83d5c Mon Sep 17 00:00:00 2001 From: janderedev Date: Sat, 9 Apr 2022 13:03:12 +0200 Subject: [PATCH] refactoring --- bot/src/bot/commands/bot_managers.ts | 10 ++--- bot/src/bot/commands/botctl.ts | 4 +- bot/src/bot/commands/login.ts | 8 ++-- bot/src/bot/commands/logout.ts | 21 +++++----- bot/src/bot/commands/moderator.ts | 10 ++--- bot/src/bot/commands/prefix.ts | 22 +++++----- bot/src/bot/commands/unban.ts | 4 +- bot/src/bot/commands/votekick.ts | 12 +++--- bot/src/bot/commands/warns.ts | 7 ++-- bot/src/bot/commands/whitelist.ts | 18 ++++---- bot/src/bot/modules/antispam.ts | 8 ++-- bot/src/bot/modules/api/server_details.ts | 10 ++--- bot/src/bot/modules/api_communication.ts | 12 +++--- bot/src/bot/modules/command_handler.ts | 12 +++--- bot/src/bot/modules/event_handler.ts | 6 +-- bot/src/bot/modules/mod_logs.ts | 13 +++--- bot/src/bot/modules/tempbans.ts | 15 +++---- bot/src/bot/modules/user_scan.ts | 17 ++++---- bot/src/bot/util.ts | 50 ++++++++++++++--------- bot/src/index.ts | 20 ++++++++- bot/src/struct/DbUser.ts | 11 +++++ bot/src/struct/ServerConfig.ts | 32 +++++++-------- 22 files changed, 179 insertions(+), 143 deletions(-) create mode 100644 bot/src/struct/DbUser.ts diff --git a/bot/src/bot/commands/bot_managers.ts b/bot/src/bot/commands/bot_managers.ts index d50888c..c483444 100644 --- a/bot/src/bot/commands/bot_managers.ts +++ b/bot/src/bot/commands/bot_managers.ts @@ -1,7 +1,7 @@ import SimpleCommand from "../../struct/commands/SimpleCommand"; import { hasPerm, parseUser } from "../util"; import ServerConfig from "../../struct/ServerConfig"; -import { client } from "../.."; +import { client, dbs } from "../.."; import { User } from "@janderedev/revolt.js/dist/maps/Users"; import MessageCommandContext from "../../struct/MessageCommandContext"; import CommandCategory from "../../struct/commands/CommandCategory"; @@ -18,8 +18,8 @@ export default { if (!hasPerm(message.member!, 'ManageServer')) return message.reply('You need **ManageServer** permission to use this command.'); - let config: ServerConfig = (await client.db.get('servers').findOne({ id: message.serverContext._id })) ?? {}; - let admins = config.botManagers ?? []; + let config = await dbs.SERVERS.findOne({ id: message.serverContext._id }); + let admins = config?.botManagers ?? []; let user: User|null; switch(args[0]?.toLowerCase()) { @@ -32,7 +32,7 @@ export default { if (admins.indexOf(user._id) > -1) return message.reply('This user is already added as bot admin.'); admins.push(user._id); - await client.db.get('servers').update({ id: message.serverContext._id }, { $set: { botManagers: admins } }); + await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { botManagers: admins } }); message.reply(`✅ Added [@${user.username}](/@${user._id}) to bot admins.`); break; @@ -47,7 +47,7 @@ export default { if (admins.indexOf(user._id) == -1) return message.reply('This user is not added as bot admin.'); admins = admins.filter(a => a != user?._id); - await client.db.get('servers').update({ id: message.serverContext._id }, { $set: { botManagers: admins } }); + await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { botManagers: admins } }); message.reply(`✅ Removed [@${user.username}](/@${user._id}) from bot admins.`); break; diff --git a/bot/src/bot/commands/botctl.ts b/bot/src/bot/commands/botctl.ts index 69e1cb4..61b832e 100644 --- a/bot/src/bot/commands/botctl.ts +++ b/bot/src/bot/commands/botctl.ts @@ -1,5 +1,5 @@ import { FindOneResult } from "monk"; -import { client } from "../.."; +import { client, dbs } from "../.."; import CommandCategory from "../../struct/commands/CommandCategory"; import SimpleCommand from "../../struct/commands/SimpleCommand"; import MessageCommandContext from "../../struct/MessageCommandContext"; @@ -21,7 +21,7 @@ export default { switch(action) { case 'scan_userlist': try { - let serverConf: FindOneResult = await client.db.get('servers').findOne({ id: message.serverContext._id }); + let serverConf: FindOneResult = await dbs.SERVERS.findOne({ id: message.serverContext._id }); if (!serverConf?.enableUserScan) return message.reply(`User scanning is not enabled for this server.`); if (userscans.includes(message.serverContext._id)) return message.reply(`There is already a scan running for this server.`); diff --git a/bot/src/bot/commands/login.ts b/bot/src/bot/commands/login.ts index 8f7dc95..9cd8e29 100644 --- a/bot/src/bot/commands/login.ts +++ b/bot/src/bot/commands/login.ts @@ -1,5 +1,5 @@ import { FindOneResult } from "monk"; -import { client } from "../.."; +import { client, dbs } from "../.."; import CommandCategory from "../../struct/commands/CommandCategory"; import SimpleCommand from "../../struct/commands/SimpleCommand"; import MessageCommandContext from "../../struct/MessageCommandContext"; @@ -21,7 +21,7 @@ export default { + `If you already have a code, you can use \`${DEFAULT_PREFIX}login [Code]\`.`); } - const login: FindOneResult = await client.db.get('pending_logins').findOne({ + const login: FindOneResult = await dbs.PENDING_LOGINS.findOne({ code, user: message.author_id, confirmed: false, @@ -45,7 +45,7 @@ export default { `you can run this command again to continue.\n` + `##### You're seeing this because this is the first time you're trying to log in. Stay safe!` ), - client.db.get('pending_logins').update({ _id: login._id }, { $set: { requirePhishingConfirmation: false } }), + dbs.PENDING_LOGINS.update({ _id: login._id }, { $set: { requirePhishingConfirmation: false } }), ]); return; } @@ -53,7 +53,7 @@ export default { await Promise.all([ message.reply(`Successfully logged in.\n\n` + `If this wasn't you, run \`${DEFAULT_PREFIX}logout ${code}\` immediately.`), - client.db.get('pending_logins').update({ _id: login._id }, { $set: { confirmed: true } }), + dbs.PENDING_LOGINS.update({ _id: login._id }, { $set: { confirmed: true } }), ]); } catch(e) { console.error(e); diff --git a/bot/src/bot/commands/logout.ts b/bot/src/bot/commands/logout.ts index 6d93f60..4f5bebb 100644 --- a/bot/src/bot/commands/logout.ts +++ b/bot/src/bot/commands/logout.ts @@ -1,5 +1,5 @@ import { FindOneResult, FindResult } from "monk"; -import { client } from "../.."; +import { client, dbs } from "../.."; import CommandCategory from "../../struct/commands/CommandCategory"; import SimpleCommand from "../../struct/commands/SimpleCommand"; import MessageCommandContext from "../../struct/MessageCommandContext"; @@ -22,30 +22,29 @@ export default { if (code.toLowerCase() == 'all') { const [resA, resB] = await Promise.all([ - client.db.get('pending_logins').update({ user: message.author_id, invalid: false }, { $set: { invalid: true } }), - client.db.get('sessions').update({ user: message.author_id, invalid: false }, { $set: { invalid: true } }), + dbs.PENDING_LOGINS.update({ user: message.author_id, invalid: false }, { $set: { invalid: true } }), + dbs.SESSIONS.update({ user: message.author_id, invalid: false }, { $set: { invalid: true } }), ]); if (resA.nModified == 0 && resB.nModified == 0) return message.reply('There are no sessions to invalidate.'); message.reply(`Successfully invalidated ${resA.nModified} codes and ${resB.nModified} sessions.`); } else { - const loginAttempt: FindOneResult = await client.db.get('pending_logins') - .findOne({ - code: code.toUpperCase(), - user: message.author_id, - }); + const loginAttempt = await dbs.PENDING_LOGINS.findOne({ + code: code.toUpperCase(), + user: message.author_id, + }); if (!loginAttempt || loginAttempt.invalid) { return message.reply('That code doesn\'t seem to exist.'); } - await client.db.get('pending_logins').update({ _id: loginAttempt._id }, { $set: { invalid: true } }); + await dbs.PENDING_LOGINS.update({ _id: loginAttempt._id }, { $set: { invalid: true } }); if (loginAttempt.exchanged) { - const session: FindOneResult = await client.db.get('sessions').findOne({ nonce: loginAttempt.nonce }); + const session = await dbs.SESSIONS.findOne({ nonce: loginAttempt.nonce }); if (session) { - await client.db.get('sessions').update({ _id: session._id }, { $set: { invalid: true } }); + await dbs.SESSIONS.update({ _id: session._id }, { $set: { invalid: true } }); return message.reply(`Successfully invalidated code and terminated associated session.`); } } diff --git a/bot/src/bot/commands/moderator.ts b/bot/src/bot/commands/moderator.ts index 880d60d..2a4702c 100644 --- a/bot/src/bot/commands/moderator.ts +++ b/bot/src/bot/commands/moderator.ts @@ -2,7 +2,7 @@ import SimpleCommand from "../../struct/commands/SimpleCommand"; import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { isBotManager, NO_MANAGER_MSG, parseUser } from "../util"; import ServerConfig from "../../struct/ServerConfig"; -import { client } from "../.."; +import { client, dbs } from "../.."; import { User } from "@janderedev/revolt.js/dist/maps/Users"; import MessageCommandContext from "../../struct/MessageCommandContext"; import CommandCategory from "../../struct/commands/CommandCategory"; @@ -20,8 +20,8 @@ export default { run: async (message: MessageCommandContext, args: string[]) => { if (!await isBotManager(message)) return message.reply(NO_MANAGER_MSG); - let config: ServerConfig = (await client.db.get('servers').findOne({ id: message.serverContext._id })) ?? {}; - let mods = config.moderators ?? []; + let config = await dbs.SERVERS.findOne({ id: message.serverContext._id }); + let mods = config?.moderators ?? []; let user: User|null; switch(args[0]?.toLowerCase()) { @@ -34,7 +34,7 @@ export default { if (mods.indexOf(user._id) > -1) return message.reply('This user is already added as moderator.'); mods.push(user._id); - await client.db.get('servers').update({ id: message.serverContext._id }, { $set: { moderators: mods } }); + await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { moderators: mods } }); message.reply(`✅ Added [@${user.username}](/@${user._id}) to moderators.`); break; @@ -49,7 +49,7 @@ export default { if (mods.indexOf(user._id) == -1) return message.reply('This user is not added as moderator.'); mods = mods.filter(a => a != user?._id); - await client.db.get('servers').update({ id: message.serverContext._id }, { $set: { moderators: mods } }); + await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { moderators: mods } }); message.reply(`✅ Removed [@${user.username}](/@${user._id}) from moderators.`); break; diff --git a/bot/src/bot/commands/prefix.ts b/bot/src/bot/commands/prefix.ts index ec81111..665f11d 100644 --- a/bot/src/bot/commands/prefix.ts +++ b/bot/src/bot/commands/prefix.ts @@ -1,9 +1,8 @@ import SimpleCommand from "../../struct/commands/SimpleCommand"; -import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; -import { client } from "../.."; +import { client, dbs } from "../.."; import ServerConfig from "../../struct/ServerConfig"; import { DEFAULT_PREFIX } from "../modules/command_handler"; -import { hasPerm, isBotManager, NO_MANAGER_MSG } from "../util"; +import { isBotManager, NO_MANAGER_MSG } from "../util"; import MessageCommandContext from "../../struct/MessageCommandContext"; import CommandCategory from "../../struct/commands/CommandCategory"; @@ -17,8 +16,8 @@ export default { syntax: SYNTAX, category: CommandCategory.Config, run: async (message: MessageCommandContext, args: string[]) => { - let config: ServerConfig = (await client.db.get('servers').findOne({ id: message.channel?.server_id })) ?? {}; - + let config = await dbs.SERVERS.findOne({ id: message.channel!.server_id! }); + switch(args[0]?.toLowerCase()) { case 'set': if (!await isBotManager(message)) return message.reply(NO_MANAGER_MSG); @@ -26,28 +25,28 @@ export default { 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 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 } }); + await dbs.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}`); + 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 (!await isBotManager(message)) return message.reply(NO_MANAGER_MSG); - - if (config.prefix != null) { - await client.db.get('servers').update({ 'id': message.channel?.server_id }, { $set: { 'prefix': null } }); + + if (config?.prefix != null) { + await dbs.SERVERS.update({ id: message.channel!.server_id! }, { $set: { prefix: undefined } }); } message.reply(`✅ Prefix has been reset to the default: \`${DEFAULT_PREFIX}\`.`); @@ -55,7 +54,6 @@ export default { default: message.reply(`Unknown action. Correct syntax: \`${SYNTAX}\``); } - } } as SimpleCommand; diff --git a/bot/src/bot/commands/unban.ts b/bot/src/bot/commands/unban.ts index e9882f7..39b4f74 100644 --- a/bot/src/bot/commands/unban.ts +++ b/bot/src/bot/commands/unban.ts @@ -1,5 +1,5 @@ import { FindResult } from "monk"; -import { client } from "../.."; +import { client, dbs } from "../.."; import CommandCategory from "../../struct/commands/CommandCategory"; import SimpleCommand from "../../struct/commands/SimpleCommand"; import MessageCommandContext from "../../struct/MessageCommandContext"; @@ -17,7 +17,7 @@ export default { if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG); let checkTempBans = async (id: string): Promise => { - let tempbans: FindResult = await client.db.get('tempbans').find({ bannedUser: id, server: message.serverContext._id }); + let tempbans = await dbs.TEMPBANS.find({ bannedUser: id, server: message.serverContext._id }); if (tempbans.length > 0) { for (const ban of tempbans) { await removeTempBan(ban.id); diff --git a/bot/src/bot/commands/votekick.ts b/bot/src/bot/commands/votekick.ts index 1d9d969..1608293 100644 --- a/bot/src/bot/commands/votekick.ts +++ b/bot/src/bot/commands/votekick.ts @@ -1,6 +1,6 @@ import { FindResult } from "monk"; import { ulid } from "ulid"; -import { client } from "../.."; +import { client, dbs } from "../.."; import CommandCategory from "../../struct/commands/CommandCategory"; import SimpleCommand from "../../struct/commands/SimpleCommand"; import MessageCommandContext from "../../struct/MessageCommandContext"; @@ -25,7 +25,7 @@ export default { category: CommandCategory.Moderation, run: async (message: MessageCommandContext, args: string[]) => { try { - const serverConfig: ServerConfig = await client.db.get('servers').findOne({ id: message.serverContext._id }); + const serverConfig = await dbs.SERVERS.findOne({ id: message.serverContext._id }); if (!serverConfig?.votekick?.enabled) return message.reply('Vote kick is not enabled for this server.'); if (!message.member!.roles?.filter(r => serverConfig.votekick?.trustedRoles.includes(r)).length && !(await isModerator(message))) { @@ -55,7 +55,7 @@ export default { ignore: false, } - const votes: FindResult = await client.db.get('votekicks').find({ + const votes = await dbs.VOTEKICKS.find({ server: message.serverContext._id, target: target._id, time: { @@ -66,7 +66,7 @@ export default { if (votes.find(v => v.user == message.author_id)) return message.reply('You can\'t vote twice for this user.'); - await client.db.get('votekicks').insert(vote); + await dbs.VOTEKICKS.insert(vote); votes.push({ _id: '' as any, ...vote }); await logModAction( @@ -99,7 +99,7 @@ export default { message.reply(`**${votes.length}/${serverConfig.votekick.votesRequired}** votes - ` + `Banned @${target.username} for ${serverConfig.votekick.banDuration} minutes.`); // Todo: display ban duration properly (Permban, kick, etc) - await client.db.get('votekicks').update({ + await dbs.VOTEKICKS.update({ server: message.serverContext._id, target: target._id, time: { $gt: Date.now() - 1000 * 60 * 30 }, @@ -115,3 +115,5 @@ export default { } } } as SimpleCommand; + +export { VoteEntry } diff --git a/bot/src/bot/commands/warns.ts b/bot/src/bot/commands/warns.ts index 3c41ec1..1799316 100644 --- a/bot/src/bot/commands/warns.ts +++ b/bot/src/bot/commands/warns.ts @@ -1,5 +1,5 @@ import SimpleCommand from "../../struct/commands/SimpleCommand"; -import { client } from "../.."; +import { client, dbs } from "../.."; import Infraction from "../../struct/antispam/Infraction"; import InfractionType from "../../struct/antispam/InfractionType"; import { isModerator, NO_MANAGER_MSG, parseUserOrId, uploadFile } from "../util"; @@ -21,8 +21,7 @@ export default { run: async (message: MessageCommandContext, args: string[]) => { if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG); - let collection = client.db.get('infractions'); - let infractions: Array = await collection.find({ + let infractions: Array = await dbs.INFRACTIONS.find({ server: message.serverContext._id, }); let userInfractions: Map = new Map(); @@ -50,7 +49,7 @@ export default { case 'del': let id = args[1]; if (!id) return message.reply('No infraction ID provided.'); - let inf: Infraction|null = await client.db.get('infractions').findOneAndDelete({ + let inf = await dbs.INFRACTIONS.findOneAndDelete({ _id: { $eq: id.toUpperCase() }, server: message.serverContext._id }); diff --git a/bot/src/bot/commands/whitelist.ts b/bot/src/bot/commands/whitelist.ts index 071bd17..5c6be4f 100644 --- a/bot/src/bot/commands/whitelist.ts +++ b/bot/src/bot/commands/whitelist.ts @@ -1,6 +1,5 @@ -import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { User } from "@janderedev/revolt.js/dist/maps/Users"; -import { client } from "../.."; +import { client, dbs } from "../.."; import CommandCategory from "../../struct/commands/CommandCategory"; import SimpleCommand from "../../struct/commands/SimpleCommand"; import MessageCommandContext from "../../struct/MessageCommandContext"; @@ -16,7 +15,8 @@ export default { syntax: SYNTAX, category: CommandCategory.Config, run: async (message: MessageCommandContext, args: string[]) => { - let config: ServerConfig = await client.db.get('servers').findOne({ id: message.serverContext._id }) || {} + let config: ServerConfig|null = await dbs.SERVERS.findOne({ id: message.serverContext._id }) + if (!config) config = { id: message.channel!.server_id! }; if (!config.whitelist) config.whitelist = { users: [], roles: [], managers: true } if (!isBotManager(message)) return message.reply(NO_MANAGER_MSG); @@ -37,7 +37,7 @@ export default { return message.reply('That role is already whitelisted.'); config.whitelist!.roles = [role, ...(config.whitelist!.roles ?? [])]; - await client.db.get('servers').update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } }); + await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } }); return message.reply(`Added role to whitelist!`); } @@ -48,7 +48,7 @@ export default { return message.reply('That user is already whitelisted.'); config.whitelist!.users = [user._id, ...(config.whitelist!.users ?? [])]; - await client.db.get('servers').update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } }); + await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } }); return message.reply('Added user to whitelist!'); break; case 'rm': @@ -67,7 +67,7 @@ export default { return message.reply('That role is not whitelisted.'); config.whitelist!.roles = config.whitelist!.roles.filter(r => r != role); - await client.db.get('servers').update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } }); + await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } }); return message.reply(`Removed role from whitelist!`); } @@ -77,7 +77,7 @@ export default { return message.reply('That user is not whitelisted.'); config.whitelist!.users = config.whitelist!.users.filter(u => u != user?._id); - await client.db.get('servers').update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } }); + await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } }); return message.reply('Removed user from whitelist!'); break; case 'l': @@ -90,7 +90,7 @@ export default { if (config.whitelist.users?.length) { config.whitelist.users?.forEach((u, index) => { if (index < 15) str += `* [@${client.users.get(u)?.username || u}](/@${u})\n`; - if (index == 15) str += `**${index - 15} more user${config.whitelist?.users?.length == 16 ? '' : 's'}**\n`; + if (index == 15) str += `**${index - 15} more user${config?.whitelist?.users?.length == 16 ? '' : 's'}**\n`; }); } else str += `**No whitelisted users**\n`; @@ -101,7 +101,7 @@ export default { ?.map(r => message.serverContext.roles?.[r]?.name || `Unknown role (${r})`) .forEach((r, index) => { if (index < 15) str += `* ${r}\n`; - if (index == 15) str += `**${config.whitelist!.roles!.length - 15} more role${config.whitelist?.roles?.length == 16 ? '' : 's'}**\n`; + if (index == 15) str += `**${config!.whitelist!.roles!.length - 15} more role${config?.whitelist?.roles?.length == 16 ? '' : 's'}**\n`; }); } else str += `**No whitelisted roles**\n`; diff --git a/bot/src/bot/modules/antispam.ts b/bot/src/bot/modules/antispam.ts index 54c51c6..e91c836 100644 --- a/bot/src/bot/modules/antispam.ts +++ b/bot/src/bot/modules/antispam.ts @@ -1,6 +1,6 @@ import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { ulid } from "ulid"; -import { client } from "../.."; +import { client, dbs } from "../.."; import AntispamRule from "../../struct/antispam/AntispamRule"; import Infraction from "../../struct/antispam/Infraction"; import InfractionType from "../../struct/antispam/InfractionType"; @@ -17,8 +17,8 @@ let msgCountStore: Map = new Map(); * @returns true if ok, false if spam rule triggered */ async function antispam(message: Message): Promise { - let serverRules: ServerConfig = await client.db.get('servers').findOne({ id: message.channel?.server_id }) ?? {}; - if (!serverRules.automodSettings) return true; + let serverRules = await dbs.SERVERS.findOne({ id: message.channel!.server_id! }); + if (!serverRules?.automodSettings) return true; let ruleTriggered = false; @@ -29,7 +29,7 @@ async function antispam(message: Message): Promise { if (message.author?.bot != null) break; if (serverRules.whitelist?.users?.includes(message.author_id)) break; - if (message.member?.roles?.filter(r => serverRules.whitelist?.roles?.includes(r)).length) break; + if (message.member?.roles?.filter(r => serverRules!.whitelist?.roles?.includes(r)).length) break; if (serverRules.whitelist?.managers !== false && await isModerator(message)) break; if (rule.channels?.length && rule.channels.indexOf(message.channel_id) == -1) break; diff --git a/bot/src/bot/modules/api/server_details.ts b/bot/src/bot/modules/api/server_details.ts index a5bb3d2..93baac7 100644 --- a/bot/src/bot/modules/api/server_details.ts +++ b/bot/src/bot/modules/api/server_details.ts @@ -1,6 +1,6 @@ import { Member } from "@janderedev/revolt.js/dist/maps/Members"; import { User } from "@janderedev/revolt.js/dist/maps/Users"; -import { client } from "../../.."; +import { client, dbs } from "../../.."; import ServerConfig from "../../../struct/ServerConfig"; import { getPermissionLevel } from "../../util"; import { wsEvents, WSResponse } from "../api_communication"; @@ -42,7 +42,7 @@ wsEvents.on('req:getUserServerDetails', async (data: ReqData, cb: (data: WSRespo return; } - const serverConfig: ServerConfig = await client.db.get('servers').findOne({ id: server._id }); + const serverConfig = await dbs.SERVERS.findOne({ id: server._id }); // todo: remove unwanted keys from server config @@ -55,8 +55,8 @@ wsEvents.on('req:getUserServerDetails', async (data: ReqData, cb: (data: WSRespo } const users = await Promise.allSettled([ - ...(serverConfig.botManagers?.map(u => fetchUser(u)) ?? []), - ...(serverConfig.moderators?.map(u => fetchUser(u)) ?? []), + ...(serverConfig?.botManagers?.map(u => fetchUser(u)) ?? []), + ...(serverConfig?.moderators?.map(u => fetchUser(u)) ?? []), fetchUser(user._id), ]); @@ -67,7 +67,7 @@ wsEvents.on('req:getUserServerDetails', async (data: ReqData, cb: (data: WSRespo description: server.description ?? undefined, bannerURL: server.generateBannerURL(), iconURL: server.generateIconURL(), - serverConfig, + serverConfig: (serverConfig as ServerConfig|undefined), users: users.map( u => u.status == 'fulfilled' ? { id: u.value._id, avatarURL: u.value.generateAvatarURL(), username: u.value.username } diff --git a/bot/src/bot/modules/api_communication.ts b/bot/src/bot/modules/api_communication.ts index c6ef4ed..5cf3531 100644 --- a/bot/src/bot/modules/api_communication.ts +++ b/bot/src/bot/modules/api_communication.ts @@ -5,7 +5,7 @@ import ws from "ws"; import logger from "../logger"; import crypto from 'crypto'; -import { client as bot } from '../..'; +import { client as bot, dbs } from '../..'; import { EventEmitter } from "events"; import { parseUser } from "../util"; import PendingLogin from "../../struct/PendingLogin"; @@ -102,7 +102,7 @@ wsEvents.on('req:requestLogin', async (data: any, cb: (data: WSResponse) => void let code: string|null = null; while (!code) { const c = crypto.randomBytes(8).toString('hex'); - const found = await bot.db.get('pending_logins').find({ code: c, user: user._id, confirmed: false }); + const found = await dbs.PENDING_LOGINS.find({ code: c, user: user._id, confirmed: false }); if (found.length > 0) continue; code = c.substring(0, 8).toUpperCase(); } @@ -112,13 +112,13 @@ wsEvents.on('req:requestLogin', async (data: any, cb: (data: WSResponse) => void const nonce = ulid(); const [previousLogins, currentValidLogins] = await Promise.all([ - bot.db.get('pending_logins').find({ user: user._id, confirmed: true }), - bot.db.get('pending_logins').find({ user: user._id, confirmed: false, expires: { $gt: Date.now() } }), + dbs.PENDING_LOGINS.find({ user: user._id, confirmed: true }), + dbs.PENDING_LOGINS.find({ user: user._id, confirmed: false, expires: { $gt: Date.now() } }), ]); if (currentValidLogins.length >= 5) return cb({ success: false, statusCode: 403, error: 'Too many pending logins. Try again later.' }); - - await bot.db.get('pending_logins').insert({ + + await dbs.PENDING_LOGINS.insert({ code, expires: Date.now() + (1000 * 60 * 15), // Expires in 15 minutes user: user._id, diff --git a/bot/src/bot/modules/command_handler.ts b/bot/src/bot/modules/command_handler.ts index 76f2902..44a57ee 100644 --- a/bot/src/bot/modules/command_handler.ts +++ b/bot/src/bot/modules/command_handler.ts @@ -1,6 +1,6 @@ import SimpleCommand from "../../struct/commands/SimpleCommand"; import logger from "../logger"; -import { client } from "../../index"; +import { client, dbs } from "../../index"; import fs from 'fs'; import path from 'path'; import ServerConfig from "../../struct/ServerConfig"; @@ -64,15 +64,15 @@ let commands: SimpleCommand[]; let args = msg.content.split(' '); let cmdName = args.shift() ?? ''; - let config: ServerConfig = (await client.db.get('servers').findOne({ 'id': msg.channel?.server_id })) ?? {}; - let guildPrefix = config.prefix ?? DEFAULT_PREFIX; + let config = await dbs.SERVERS.findOne({ id: msg.channel!.server_id! }); + let guildPrefix = config?.prefix ?? DEFAULT_PREFIX; if (cmdName.startsWith(`<@${client.user?._id}>`)) { cmdName = cmdName.substring(`<@${client.user?._id}>`.length); if (!cmdName) cmdName = args.shift() ?? ''; // Space between mention and command name } else if (cmdName.startsWith(guildPrefix)) { cmdName = cmdName.substring(guildPrefix.length); - if (config.spaceAfterPrefix && !cmdName) cmdName = args.shift() ?? ''; + if (config?.spaceAfterPrefix && !cmdName) cmdName = args.shift() ?? ''; } else return; if (!cmdName) return; @@ -92,7 +92,7 @@ let commands: SimpleCommand[]; let serverCtx = msg.channel?.server; - if (config.linkedServer) { + if (config?.linkedServer) { try { serverCtx = client.servers.get(config.linkedServer) || await client.servers.fetch(config.linkedServer); @@ -109,7 +109,7 @@ let commands: SimpleCommand[]; logger.info(`Command: ${message.author?.username} (${message.author?._id}) in ${message.channel?.server?.name} (${message.channel?.server?._id}): ${message.content}`); // Create document for server in DB, if not already present - if (JSON.stringify(config) == '{}') await client.db.get('servers').insert({ id: message.channel?.server_id }); + if (JSON.stringify(config) == '{}') await dbs.SERVERS.insert({ id: message.channel!.server_id! }); if (cmd.removeEmptyArgs !== false) { args = args.filter(a => a.length > 0); diff --git a/bot/src/bot/modules/event_handler.ts b/bot/src/bot/modules/event_handler.ts index f8ac8b8..3d04cb6 100644 --- a/bot/src/bot/modules/event_handler.ts +++ b/bot/src/bot/modules/event_handler.ts @@ -1,5 +1,5 @@ import { ulid } from "ulid"; -import { client } from "../.."; +import { client, dbs } from "../.."; import Infraction from "../../struct/antispam/Infraction"; import InfractionType from "../../struct/antispam/InfractionType"; import logger from "../logger"; @@ -25,10 +25,10 @@ client.on('message', async message => { case 'user_kicked': case 'user_banned': try { - let recentEvents = await client.db.get('infractions').findOne({ + let recentEvents = await dbs.INFRACTIONS.findOne({ date: { $gt: Date.now() - 30000 }, user: sysMsg.user?._id, - server: message.channel?.server_id, + server: message.channel!.server_id!, actionType: sysMsg.type == 'user_kicked' ? 'kick' : 'ban', }); diff --git a/bot/src/bot/modules/mod_logs.ts b/bot/src/bot/modules/mod_logs.ts index 178ec1f..f1842bf 100644 --- a/bot/src/bot/modules/mod_logs.ts +++ b/bot/src/bot/modules/mod_logs.ts @@ -1,6 +1,6 @@ import { Member } from "@janderedev/revolt.js/dist/maps/Members"; import { Server } from "@janderedev/revolt.js/dist/maps/Servers"; -import { client } from "../.."; +import { client, dbs } from "../.."; import Infraction from "../../struct/antispam/Infraction"; import LogMessage from "../../struct/LogMessage"; import ServerConfig from "../../struct/ServerConfig"; @@ -28,7 +28,7 @@ client.on('packet', async (packet) => { let server = channel?.server; if (!server || !channel) return logger.warn('Received message update in unknown channel or server'); - let config: ServerConfig = await client.db.get('servers').findOne({ id: server._id }) ?? {}; + let config = await dbs.SERVERS.findOne({ id: server._id }); if (config?.logs?.messageUpdate) { const attachFullMessage = oldMsg.length > 800 || newMsg.length > 800; let embed: LogMessage = { @@ -75,8 +75,8 @@ client.on('packet', async (packet) => { let msgRaw = String(message.content ?? '(Unknown)'); let msg = sanitizeMessageContent(msgRaw); - let config: ServerConfig = await client.db.get('servers').findOne({ id: message.channel?.server?._id }) ?? {}; - if (config.logs?.messageUpdate) { + let config = await dbs.SERVERS.findOne({ id: message.channel?.server?._id }); + if (config?.logs?.messageUpdate) { let embed: LogMessage = { title: `Message deleted in ${message.channel?.server?.name}`, description: `[\\[#${channel.name}\\]](/server/${channel.server_id}/channel/${channel._id}) | ` @@ -116,15 +116,14 @@ client.on('packet', async (packet) => { async function logModAction(type: 'warn'|'kick'|'ban'|'votekick', server: Server, mod: Member, target: string, reason: string|null, infractionID: string, extraText?: string): Promise { try { - let config: ServerConfig = await client.db.get('servers').findOne({ id: server._id }) ?? {}; + let config = await dbs.SERVERS.findOne({ id: server._id }); - if (config.logs?.modAction) { + if (config?.logs?.modAction) { let aType = type == 'ban' ? 'banned' : type + 'ed'; let embedColor = '#0576ff'; if (type == 'kick') embedColor = '#ff861d'; if (type == 'ban') embedColor = '#ff2f05'; - sendLogMessage(config.logs.modAction, { title: `User ${aType}`, description: `\`@${mod.user?.username}\` **${aType}** \`` diff --git a/bot/src/bot/modules/tempbans.ts b/bot/src/bot/modules/tempbans.ts index 4ab48e5..eb88ab7 100644 --- a/bot/src/bot/modules/tempbans.ts +++ b/bot/src/bot/modules/tempbans.ts @@ -1,5 +1,5 @@ import { FindResult } from "monk"; -import { client } from "../.."; +import { client, dbs } from "../.."; import TempBan from "../../struct/TempBan"; import logger from "../logger"; @@ -8,7 +8,7 @@ let dontProcess: string[] = []; let expired: string[] = []; async function tick() { - let found: FindResult = await client.db.get('tempbans').find({ until: { $lt: Date.now() + 60000 } }); + let found = await dbs.TEMPBANS.find({ until: { $lt: Date.now() + 60000 } }); for (const ban of found) { if (!dontProcess.includes(ban.id)) @@ -36,12 +36,12 @@ async function processUnban(ban: TempBan) { let promises = [ server.unbanUser(ban.bannedUser), - client.db.get('tempbans').remove({ id: ban.id }), + dbs.TEMPBANS.remove({ id: ban.id }), ]; await Promise.allSettled(promises); } - else client.db.get('tempbans').remove({ id: ban.id }); + else dbs.TEMPBANS.remove({ id: ban.id }); } catch(e) { console.error(e) } } @@ -54,14 +54,15 @@ async function storeTempBan(ban: TempBan): Promise { }, ban.until - Date.now()); } - client.db.get('tempbans').insert(ban); + dbs.TEMPBANS.insert(ban); } async function removeTempBan(banID: string): Promise { - let ban: TempBan = await client.db.get('tempbans').findOneAndDelete({ id: banID }); + let ban = await dbs.TEMPBANS.findOneAndDelete({ id: banID }); + if (!ban) throw `Ban ${banID} does not exist; cannot delete`; if (Date.now() >= ban.until - 120000) { expired.push(ban.id); - expired = expired.filter(id => id != ban.id); + expired = expired.filter(id => id != ban!.id); }; return ban; } diff --git a/bot/src/bot/modules/user_scan.ts b/bot/src/bot/modules/user_scan.ts index 64475ec..d63a5c0 100644 --- a/bot/src/bot/modules/user_scan.ts +++ b/bot/src/bot/modules/user_scan.ts @@ -1,4 +1,4 @@ -import { client } from "../.."; +import { client, dbs } from "../.."; import fs from 'fs'; import { FindOneResult } from "monk"; import ScannedUser from "../../struct/ScannedUser"; @@ -18,13 +18,12 @@ let wordlist = USERSCAN_WORDLIST_PATH if (wordlist) logger.info("Found word list; user scanning enabled"); -let scannedUsers = client.db.get('scanned_users'); let serverConfig: Map = new Map(); let userScanTimeout: Map = new Map(); async function scanServer(id: string, userScanned: () => void, done: () => void) { if (!wordlist) return; - let conf: FindOneResult = await client.db.get('servers').findOne({ id: id }); + let conf = await dbs.SERVERS.findOne({ id: id }); serverConfig.set(id, conf as ServerConfig); if (!conf?.enableUserScan) return; @@ -50,7 +49,7 @@ async function scanUser(member: Member) { try { let dbEntry: FindOneResult - = await scannedUsers.findOne({ id: member._id.user, server: member.server?._id }); + = await dbs.SCANNED_USERS.findOne({ id: member._id.user, server: member.server?._id }); let user = member.user || await client.users.fetch(member._id.user); let profile = await user.fetchProfile(); let report = false; @@ -68,19 +67,19 @@ async function scanUser(member: Member) { if (report) { if (dbEntry) { - await scannedUsers.update({ _id: dbEntry._id }, { + await dbs.SCANNED_USERS.update({ _id: dbEntry._id }, { $set: { lastLog: Date.now(), lastLoggedProfile: { username: user.username, - nickname: member.nickname, + nickname: member.nickname || undefined, profile: profile.content, status: user.status?.text, } } }); } else { - await scannedUsers.insert({ + await dbs.SCANNED_USERS.insert({ approved: false, id: user._id, lastLog: Date.now(), @@ -153,7 +152,7 @@ new Promise((res: (value: void) => void) => client.user ? res() : client.once('r let server = client.servers.get(sid); if (!server) return; - let conf: FindOneResult = await client.db.get('servers').findOne({ id: server._id }); + let conf = await dbs.SERVERS.findOne({ id: server._id }); serverConfig.set(server._id, conf as ServerConfig); if (conf?.enableUserScan) { @@ -178,7 +177,7 @@ new Promise((res: (value: void) => void) => client.user ? res() : client.once('r let server = member.server || await client.servers.fetch(member._id.server); if (!server) return; - let conf: FindOneResult = await client.db.get('servers').findOne({ id: server._id }); + let conf: FindOneResult = await dbs.SERVERS.findOne({ id: server._id }); serverConfig.set(server._id, conf as ServerConfig); if (conf?.enableUserScan) { diff --git a/bot/src/bot/util.ts b/bot/src/bot/util.ts index 16953fe..c1113b3 100644 --- a/bot/src/bot/util.ts +++ b/bot/src/bot/util.ts @@ -1,6 +1,6 @@ import { Member } from "@janderedev/revolt.js/dist/maps/Members"; import { User } from "@janderedev/revolt.js/dist/maps/Users"; -import { client } from ".."; +import { client, dbs } from ".."; import Infraction from "../struct/antispam/Infraction"; import ServerConfig from "../struct/ServerConfig"; import FormData from 'form-data'; @@ -77,18 +77,31 @@ async function parseUserOrId(text: string): Promise { async function isModerator(message: Message) { let member = message.member!, server = message.channel!.server!; - return hasPerm(member, 'KickMembers') - || await isBotManager(message) - || (((await client.db.get('servers').findOne({ id: server._id }) || {}) as ServerConfig) - .moderators?.indexOf(member.user?._id!) ?? -1) > -1 - || await checkSudoPermission(message); + + if (hasPerm(member, 'KickMembers')) return true; + + const [ isManager, mods, isSudo ] = await Promise.all([ + isBotManager(message), + dbs.SERVERS.findOne({ id: server._id }), + checkSudoPermission(message), + ]); + + return isManager + || (mods?.moderators?.indexOf(member.user?._id!) ?? -1) > -1 + || isSudo; } async function isBotManager(message: Message) { let member = message.member!, server = message.channel!.server!; - return hasPerm(member, 'ManageServer') - || (((await client.db.get('servers').findOne({ id: server._id }) || {}) as ServerConfig) - .botManagers?.indexOf(member.user?._id!) ?? -1) > -1 - || await checkSudoPermission(message); + + if (hasPerm(member, 'ManageServer')) return true; + + const [ managers, isSudo ] = await Promise.all([ + dbs.SERVERS.findOne({ id: server._id }), + checkSudoPermission(message), + ]); + + return (managers?.botManagers?.indexOf(member.user?._id!) ?? -1) > -1 + || isSudo; } async function checkSudoPermission(message: Message): Promise { const hasPerm = isSudo(message.author!); @@ -107,10 +120,10 @@ async function getPermissionLevel(user: User|Member, server: Server): Promise<0| if (hasPerm(member, 'ManageServer')) return 3; - const config = (await client.db.get('servers').findOne({ id: server._id }) || {}) as ServerConfig; + const config = await dbs.SERVERS.findOne({ id: server._id }); - if (config.botManagers?.includes(user._id)) return 2; - if (config.moderators?.includes(user._id) || hasPerm(member, 'KickMembers')) return 1; + if (config?.botManagers?.includes(user._id)) return 2; + if (config?.moderators?.includes(user._id) || hasPerm(member, 'KickMembers')) return 1; return 0; } @@ -143,17 +156,14 @@ async function getOwnMemberInServer(server: Server): Promise { } async function storeInfraction(infraction: Infraction): Promise<{ userWarnCount: number }> { - let collection = client.db.get('infractions'); - let p = [ - collection.insert(infraction, { castIds: false }), - collection.find({ + let r = await Promise.all([ + dbs.INFRACTIONS.insert(infraction, { castIds: false }), + dbs.INFRACTIONS.find({ server: infraction.server, user: infraction.user, _id: { $not: { $eq: infraction._id } } }, ), - ]; - - let r = await Promise.all(p); + ]); return { userWarnCount: (r[1].length ?? 0) + 1 } } diff --git a/bot/src/index.ts b/bot/src/index.ts index 5520177..2722e22 100644 --- a/bot/src/index.ts +++ b/bot/src/index.ts @@ -4,6 +4,13 @@ config(); import logger from './bot/logger'; import AutomodClient, { login } from './struct/AutomodClient'; import MongoDB from './bot/db'; +import DbUser from './struct/DbUser'; +import ServerConfig from './struct/ServerConfig'; +import Infraction from './struct/antispam/Infraction'; +import PendingLogin from './struct/PendingLogin'; +import TempBan from './struct/TempBan'; +import { VoteEntry } from './bot/commands/votekick'; +import ScannedUser from './struct/ScannedUser'; logger.info('Initializing client'); @@ -16,7 +23,18 @@ let client = new AutomodClient({ }, db); login(client); -export { client } +const dbs = { + SERVERS: db.get('servers'), + USERS: db.get('users'), + INFRACTIONS: db.get('infractions'), + PENDING_LOGINS: db.get('pending_logins'), + SESSIONS: db.get('sessions'), + TEMPBANS: db.get('tempbans'), + VOTEKICKS: db.get('votekicks'), + SCANNED_USERS: db.get('scanned_users'), +} + +export { client, dbs } (async () => { // Wait for a database query to succeed before loading the rest diff --git a/bot/src/struct/DbUser.ts b/bot/src/struct/DbUser.ts new file mode 100644 index 0000000..5b869a3 --- /dev/null +++ b/bot/src/struct/DbUser.ts @@ -0,0 +1,11 @@ +// Stores global info about a particular user in the database +export default class DbUser { + // User ID + id: string; + + // Blacklists the user from interacting with the bot + ignore?: boolean; + + // Whether the user is globally marked as bad actor + globalBlacklist?: boolean; +} diff --git a/bot/src/struct/ServerConfig.ts b/bot/src/struct/ServerConfig.ts index f1f3260..c478680 100644 --- a/bot/src/struct/ServerConfig.ts +++ b/bot/src/struct/ServerConfig.ts @@ -2,29 +2,29 @@ import AutomodSettings from "./antispam/AutomodSettings"; import LogConfig from "./LogConfig"; class ServerConfig { - id: string | undefined; - prefix: string | undefined; - spaceAfterPrefix: boolean | undefined; - automodSettings: AutomodSettings | undefined; - botManagers: string[] | undefined; - moderators: string[] | undefined; - votekick: { + id: string; + prefix?: string; + spaceAfterPrefix?: boolean; + automodSettings?: AutomodSettings; + botManagers?: string[]; + moderators?: string[]; + votekick?: { enabled: boolean; votesRequired: number; banDuration: number; // -1: Only kick, 0: Permanent, >0: Ban duration in minutes trustedRoles: string[]; - } | undefined; - linkedServer: string | undefined; - whitelist: { - users: string[] | undefined, - roles: string[] | undefined, - managers: boolean | undefined, - } | undefined; - logs: { + }; + linkedServer?: string; + whitelist?: { + users?: string[], + roles?: string[], + managers?: boolean, + }; + logs?: { messageUpdate?: LogConfig, // Message edited or deleted modAction?: LogConfig, // User warned, kicked or banned userScan?: LogConfig // User profile matched word list - } | undefined; + }; enableUserScan?: boolean; }