disable sudo alert on antispam rules, add trycatch

This commit is contained in:
janderedev 2022-04-09 17:42:59 +02:00
parent 3b64fbb587
commit b1612824dd
Signed by: Lea
GPG key ID: 5D5E18ACB990F57A
4 changed files with 114 additions and 106 deletions

View file

@ -1,11 +1,10 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { ulid } from "ulid"; import { ulid } from "ulid";
import { client, dbs } from "../.."; import { dbs } from "../..";
import AntispamRule from "../../struct/antispam/AntispamRule"; import AntispamRule from "../../struct/antispam/AntispamRule";
import Infraction from "../../struct/antispam/Infraction"; import Infraction from "../../struct/antispam/Infraction";
import InfractionType from "../../struct/antispam/InfractionType"; import InfractionType from "../../struct/antispam/InfractionType";
import ModerationAction from "../../struct/antispam/ModerationAction"; import ModerationAction from "../../struct/antispam/ModerationAction";
import ServerConfig from "../../struct/ServerConfig";
import logger from "../logger"; import logger from "../logger";
import { isModerator, storeInfraction } from "../util"; import { isModerator, storeInfraction } from "../util";
@ -17,81 +16,86 @@ let msgCountStore: Map<string, { users: any }> = new Map();
* @returns true if ok, false if spam rule triggered * @returns true if ok, false if spam rule triggered
*/ */
async function antispam(message: Message): Promise<boolean> { async function antispam(message: Message): Promise<boolean> {
let serverRules = await dbs.SERVERS.findOne({ id: message.channel!.server_id! }); try {
if (!serverRules?.automodSettings) return true; let serverRules = await dbs.SERVERS.findOne({ id: message.channel!.server_id! });
if (!serverRules?.automodSettings) return true;
let ruleTriggered = false; let ruleTriggered = false;
for (const rule of serverRules.automodSettings.spam) { for (const rule of serverRules.automodSettings.spam) {
if (msgCountStore.get(rule.id) == null) { if (msgCountStore.get(rule.id) == null) {
msgCountStore.set(rule.id, { users: {} }); msgCountStore.set(rule.id, { users: {} });
} }
if (message.author?.bot != null) break; if (message.author?.bot != null) break;
if (serverRules.whitelist?.users?.includes(message.author_id)) 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 (serverRules.whitelist?.managers !== false && await isModerator(message, false)) break;
if (rule.channels?.length && rule.channels.indexOf(message.channel_id) == -1) break; if (rule.channels?.length && rule.channels.indexOf(message.channel_id) == -1) break;
let store = msgCountStore.get(rule.id)!; let store = msgCountStore.get(rule.id)!;
if (!store.users[message.channel_id]) store.users[message.channel_id] = {} if (!store.users[message.channel_id]) store.users[message.channel_id] = {}
let userStore = store.users[message.channel_id]; let userStore = store.users[message.channel_id];
if (!userStore.count) userStore.count = 1; if (!userStore.count) userStore.count = 1;
else userStore.count++; else userStore.count++;
setTimeout(() => userStore.count--, rule.timeframe * 1000); setTimeout(() => userStore.count--, rule.timeframe * 1000);
if (userStore.count > rule.max_msg) { if (userStore.count > rule.max_msg) {
logger.info(`Antispam rule triggered: ${rule.max_msg}/${rule.timeframe} -> ${ModerationAction[rule.action]}`); logger.info(`Antispam rule triggered: ${rule.max_msg}/${rule.timeframe} -> ${ModerationAction[rule.action]}`);
ruleTriggered = true; ruleTriggered = true;
switch(Number(rule.action)) { switch(Number(rule.action)) {
case ModerationAction.Delete: case ModerationAction.Delete:
message.delete() message.delete()
.catch(() => logger.warn('Antispam: Failed to delete message') ); .catch(() => logger.warn('Antispam: Failed to delete message') );
break; break;
case ModerationAction.Message: case ModerationAction.Message:
if (!userStore.warnTriggered) { if (!userStore.warnTriggered) {
userStore.warnTriggered = true; userStore.warnTriggered = true;
setTimeout(() => userStore.warnTriggered = false, 5000); setTimeout(() => userStore.warnTriggered = false, 5000);
message.channel?.sendMessage(getWarnMsg(rule, message)) message.channel?.sendMessage(getWarnMsg(rule, message))
.catch(() => logger.warn('Antispam: Failed to send message')); .catch(() => logger.warn('Antispam: Failed to send message'));
} }
break; break;
case ModerationAction.Warn: case ModerationAction.Warn:
if (!userStore.warnTriggered) { if (!userStore.warnTriggered) {
userStore.warnTriggered = true; userStore.warnTriggered = true;
setTimeout(() => userStore.warnTriggered = false, 5000); setTimeout(() => userStore.warnTriggered = false, 5000);
let inf = { let inf = {
_id: ulid(), _id: ulid(),
createdBy: null, createdBy: null,
date: Date.now(), date: Date.now(),
reason: `Automatic moderation rule triggered: More than ${rule.max_msg} messages per ${rule.timeframe} seconds.`, reason: `Automatic moderation rule triggered: More than ${rule.max_msg} messages per ${rule.timeframe} seconds.`,
server: message.channel?.server_id, server: message.channel?.server_id,
type: InfractionType.Automatic, type: InfractionType.Automatic,
user: message.author_id, user: message.author_id,
} as Infraction; } as Infraction;
message.channel?.sendMessage('## User has been warned.\n\u200b\n' + getWarnMsg(rule, message)) message.channel?.sendMessage('## User has been warned.\n\u200b\n' + getWarnMsg(rule, message))
.catch(() => logger.warn('Antispam: Failed to send warn message')); .catch(() => logger.warn('Antispam: Failed to send warn message'));
await storeInfraction(inf); await storeInfraction(inf);
} }
break; break;
case ModerationAction.Kick: case ModerationAction.Kick:
message.reply('(Kick user)'); message.reply('(Kick user)');
break; break;
case ModerationAction.Ban: case ModerationAction.Ban:
message.reply('(Ban user)'); message.reply('(Ban user)');
break; break;
default: logger.warn(`Unknown Moderation Action: ${rule.action}`); default: logger.warn(`Unknown Moderation Action: ${rule.action}`);
}
} }
} }
}
return !ruleTriggered; return !ruleTriggered;
} catch(e) {
console.error(''+e);
return true;
}
} }
function getWarnMsg(rule: AntispamRule, message: Message) { function getWarnMsg(rule: AntispamRule, message: Message) {

View file

@ -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}`); 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 // Create document for server in DB, if not already present
if (JSON.stringify(config) == '{}') await dbs.SERVERS.insert({ id: message.channel!.server_id! }); if (JSON.stringify(config) == '{}' || !config) await dbs.SERVERS.insert({ id: message.channel!.server_id! });
if (cmd.removeEmptyArgs !== false) { if (cmd.removeEmptyArgs !== false) {
args = args.filter(a => a.length > 0); args = args.filter(a => a.length > 0);

View file

@ -1,6 +1,5 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { client } from "../../.."; import { dbs } from "../../..";
import ServerConfig from "../../../struct/ServerConfig";
import logger from "../../logger"; import logger from "../../logger";
import messageContentTrigger from "./message_content_trigger"; import messageContentTrigger from "./message_content_trigger";
@ -8,47 +7,50 @@ import custom_sendMessage from "./actions/sendMessage";
import custom_delete from "./actions/delete"; import custom_delete from "./actions/delete";
import custom_warn from "./actions/warn"; import custom_warn from "./actions/warn";
import { getOwnMemberInServer, hasPermForChannel } from "../../util"; import { getOwnMemberInServer, hasPermForChannel } from "../../util";
import MessageCommandContext from "../../../struct/MessageCommandContext";
async function checkCustomRules(message: Message, isEdit: boolean = false) { async function checkCustomRules(message: Message, isEdit: boolean = false) {
let serverConfig: ServerConfig = await client.db.get('servers').findOne({ id: message.channel?.server_id }) ?? {}; try {
let rules = serverConfig?.automodSettings?.custom; let serverConfig = await dbs.SERVERS.findOne({ id: message.channel!.server_id! });
if (!rules) return; let rules = serverConfig?.automodSettings?.custom;
if (!rules) return;
for (let rule of rules) { for (let rule of rules) {
if (!rule?.trigger?.on) continue; if (!rule?.trigger?.on) continue;
let onEdit = rule.trigger.on.includes('message/update'); let onEdit = rule.trigger.on.includes('message/update');
let onNew = rule.trigger.on.includes('message/create'); let onNew = rule.trigger.on.includes('message/create');
// tired // tired
if (!((onEdit && isEdit) || (onNew && !isEdit) || (onNew && onEdit))) break; if (!((onEdit && isEdit) || (onNew && !isEdit) || (onNew && onEdit))) break;
if (await messageContentTrigger(message, rule.trigger)) { if (await messageContentTrigger(message, rule.trigger)) {
for (const action of rule.action) { for (const action of rule.action) {
switch(action.action) { switch(action.action) {
case 'sendMessage': case 'sendMessage':
if (hasPermForChannel(await getOwnMemberInServer(message.channel!.server!), message.channel!, 'SendMessage')) if (hasPermForChannel(await getOwnMemberInServer(message.channel!.server!), message.channel!, 'SendMessage'))
await custom_sendMessage(message, action); await custom_sendMessage(message, action);
else else
logger.warn(`Custom rule ${rule._id}: 'sendMessage' action lacks permission`); logger.warn(`Custom rule ${rule._id}: 'sendMessage' action lacks permission`);
break; break;
case 'delete': case 'delete':
if (hasPermForChannel(await getOwnMemberInServer(message.channel!.server!), message.channel!, 'ManageMessages')) if (hasPermForChannel(await getOwnMemberInServer(message.channel!.server!), message.channel!, 'ManageMessages'))
await custom_delete(message, action); await custom_delete(message, action);
else else
logger.warn(`Custom rule ${rule._id}: 'delete' action lacks permission`); logger.warn(`Custom rule ${rule._id}: 'delete' action lacks permission`);
break; break;
case 'warn': case 'warn':
if (hasPermForChannel(await getOwnMemberInServer(message.channel!.server!), message.channel!, 'SendMessage')) if (hasPermForChannel(await getOwnMemberInServer(message.channel!.server!), message.channel!, 'SendMessage'))
await custom_warn(message, action); await custom_warn(message, action);
else else
logger.warn(`Custom rule ${rule._id}: 'warn' action lacks permission`); logger.warn(`Custom rule ${rule._id}: 'warn' action lacks permission`);
break; break;
default: default:
logger.warn(`Unknown action ${action.action} in custom rule ${rule._id} in server ${message.channel?.server_id}`); logger.warn(`Unknown action ${action.action} in custom rule ${rule._id} in server ${message.channel?.server_id}`);
}
} }
} }
} }
} catch(e) {
console.error(''+e);
} }
} }

View file

@ -75,7 +75,7 @@ async function parseUserOrId(text: string): Promise<User|{_id: string}|null> {
return null; return null;
} }
async function isModerator(message: Message) { async function isModerator(message: Message, announceSudo?: boolean) {
let member = message.member!, server = message.channel!.server!; let member = message.member!, server = message.channel!.server!;
if (hasPerm(member, 'KickMembers')) return true; if (hasPerm(member, 'KickMembers')) return true;
@ -83,32 +83,34 @@ async function isModerator(message: Message) {
const [ isManager, mods, isSudo ] = await Promise.all([ const [ isManager, mods, isSudo ] = await Promise.all([
isBotManager(message), isBotManager(message),
dbs.SERVERS.findOne({ id: server._id }), dbs.SERVERS.findOne({ id: server._id }),
checkSudoPermission(message), checkSudoPermission(message, announceSudo),
]); ]);
return isManager return isManager
|| (mods?.moderators?.indexOf(member.user?._id!) ?? -1) > -1 || (mods?.moderators?.indexOf(member.user?._id!) ?? -1) > -1
|| isSudo; || isSudo;
} }
async function isBotManager(message: Message) { async function isBotManager(message: Message, announceSudo?: boolean) {
let member = message.member!, server = message.channel!.server!; let member = message.member!, server = message.channel!.server!;
if (hasPerm(member, 'ManageServer')) return true; if (hasPerm(member, 'ManageServer')) return true;
const [ managers, isSudo ] = await Promise.all([ const [ managers, isSudo ] = await Promise.all([
dbs.SERVERS.findOne({ id: server._id }), dbs.SERVERS.findOne({ id: server._id }),
checkSudoPermission(message), checkSudoPermission(message, announceSudo),
]); ]);
return (managers?.botManagers?.indexOf(member.user?._id!) ?? -1) > -1 return (managers?.botManagers?.indexOf(member.user?._id!) ?? -1) > -1
|| isSudo; || isSudo;
} }
async function checkSudoPermission(message: Message): Promise<boolean> { async function checkSudoPermission(message: Message, announce?: boolean): Promise<boolean> {
const hasPerm = isSudo(message.author!); const hasPerm = isSudo(message.author!);
if (!hasPerm) return false; if (!hasPerm) return false;
else { else {
await message.reply(`# :unlock: Bypassed permission check\n` if (announce !== false) {
+ `Sudo mode is enabled for @${message.author!.username}.\n`); await message.reply(`# :unlock: Bypassed permission check\n`
+ `Sudo mode is enabled for @${message.author!.username}.\n`);
}
return true; return true;
} }
} }