refactoring

This commit is contained in:
janderedev 2022-04-09 13:03:12 +02:00
parent f5515a6716
commit a06c3547fb
Signed by: Lea
GPG key ID: 5D5E18ACB990F57A
22 changed files with 179 additions and 143 deletions

View file

@ -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;

View file

@ -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<ServerConfig> = await client.db.get('servers').findOne({ id: message.serverContext._id });
let serverConf: FindOneResult<ServerConfig> = 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.`);

View file

@ -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<PendingLogin> = await client.db.get('pending_logins').findOne({
const login: FindOneResult<PendingLogin> = 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);

View file

@ -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<PendingLogin> = 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<any> = 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.`);
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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<number> => {
let tempbans: FindResult<TempBan> = 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);

View file

@ -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<VoteEntry> = 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 }

View file

@ -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<Infraction> = await collection.find({
let infractions: Array<Infraction> = await dbs.INFRACTIONS.find({
server: message.serverContext._id,
});
let userInfractions: Map<string, Infraction[]> = 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
});

View file

@ -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`;

View file

@ -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<string, { users: any }> = new Map();
* @returns true if ok, false if spam rule triggered
*/
async function antispam(message: Message): Promise<boolean> {
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<boolean> {
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;

View file

@ -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 }

View file

@ -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,

View file

@ -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);

View file

@ -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',
});

View file

@ -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<void> {
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}** \``

View file

@ -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<TempBan> = 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<void> {
}, ban.until - Date.now());
}
client.db.get('tempbans').insert(ban);
dbs.TEMPBANS.insert(ban);
}
async function removeTempBan(banID: string): Promise<TempBan> {
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;
}

View file

@ -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<string, ServerConfig> = new Map();
let userScanTimeout: Map<string, number> = new Map();
async function scanServer(id: string, userScanned: () => void, done: () => void) {
if (!wordlist) return;
let conf: FindOneResult<ServerConfig> = 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<ScannedUser|undefined>
= 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<ServerConfig> = 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<ServerConfig> = await client.db.get('servers').findOne({ id: server._id });
let conf: FindOneResult<ServerConfig> = await dbs.SERVERS.findOne({ id: server._id });
serverConfig.set(server._id, conf as ServerConfig);
if (conf?.enableUserScan) {

View file

@ -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<User|{_id: string}|null> {
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<boolean> {
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<Member> {
}
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 }
}

View file

@ -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<ServerConfig>('servers'),
USERS: db.get<DbUser>('users'),
INFRACTIONS: db.get<Infraction>('infractions'),
PENDING_LOGINS: db.get<PendingLogin>('pending_logins'),
SESSIONS: db.get('sessions'),
TEMPBANS: db.get<TempBan>('tempbans'),
VOTEKICKS: db.get<VoteEntry>('votekicks'),
SCANNED_USERS: db.get<ScannedUser>('scanned_users'),
}
export { client, dbs }
(async () => {
// Wait for a database query to succeed before loading the rest

11
bot/src/struct/DbUser.ts Normal file
View file

@ -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;
}

View file

@ -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;
}