Update bot tsconfig and apply knock on changes. Remove antispam enrollment notification for discover server owners.

This commit is contained in:
Declan Chidlow 2024-08-08 19:22:47 +08:00
parent 9eac9fffc8
commit 345eec93fc
20 changed files with 50 additions and 99 deletions

View file

@ -7,7 +7,7 @@ import fs from 'fs';
import path from 'path'; import path from 'path';
import { User } from "revolt.js"; import { User } from "revolt.js";
import CommandCategory from "../../../struct/commands/CommandCategory"; import CommandCategory from "../../../struct/commands/CommandCategory";
import { getMutualServers, parseUserOrId } from "../../util"; import { parseUserOrId } from "../../util";
const BLACKLIST_BAN_REASON = `This user is globally blacklisted and has been banned automatically. If you wish to opt out of the global blacklist, run '/botctl ignore_blacklist yes'.`; const BLACKLIST_BAN_REASON = `This user is globally blacklisted and has been banned automatically. If you wish to opt out of the global blacklist, run '/botctl ignore_blacklist yes'.`;
const BLACKLIST_MESSAGE = (username: string) => `\`@${username}\` has been banned automatically. Check the ban reason for more info.`; const BLACKLIST_MESSAGE = (username: string) => `\`@${username}\` has been banned automatically. Check the ban reason for more info.`;
@ -58,7 +58,7 @@ export default {
+ `Users: \`${client.users.size()}\`\n` + `Users: \`${client.users.size()}\`\n`
+ `### Misc\n` + `### Misc\n`
+ `Command count: \`${commands.length}\`\n` + `Command count: \`${commands.length}\`\n`
+ `Environment: \`${process.env.NODE_ENV || 'testing'}\`\n` + `Environment: \`${process.env['NODE_ENV'] || 'testing'}\`\n`
+ `Commit hash: \`${await getCommitHash() || 'Unknown'}\`\n` + `Commit hash: \`${await getCommitHash() || 'Unknown'}\`\n`
+ `### Packages\n` + `### Packages\n`
+ `revolt.js: \`${pjson.dependencies['revolt.js']}\`\n` + `revolt.js: \`${pjson.dependencies['revolt.js']}\`\n`

View file

@ -23,7 +23,7 @@ export default {
} }
m?.edit({ content: str }) m?.edit({ content: str })
.catch(e => console.warn('Failed to edit message')); .catch(e => console.warn('Failed to edit message', e));
} }
} }

View file

@ -1,5 +1,5 @@
import { FindOneResult } from "monk"; import { FindOneResult } from "monk";
import { client, dbs } from "../../.."; import { dbs } from "../../..";
import CommandCategory from "../../../struct/commands/CommandCategory"; import CommandCategory from "../../../struct/commands/CommandCategory";
import SimpleCommand from "../../../struct/commands/SimpleCommand"; import SimpleCommand from "../../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../../struct/MessageCommandContext"; import MessageCommandContext from "../../../struct/MessageCommandContext";
@ -17,7 +17,7 @@ export default {
const code = args.shift(); const code = args.shift();
if (!code) { if (!code) {
return message.reply(`If you're trying to log in, you can access the dashboard ` return message.reply(`If you're trying to log in, you can access the dashboard `
+ `[here](${process.env.WEB_UI_URL || 'https://automod.janderedev.xyz'}).\n\n` + `[here](${process.env['WEB_UI_URL'] || 'https://automod.janderedev.xyz'}).\n\n`
+ `If you already have a code, you can use \`${DEFAULT_PREFIX}login [Code]\`.`); + `If you already have a code, you can use \`${DEFAULT_PREFIX}login [Code]\`.`);
} }
@ -41,7 +41,7 @@ export default {
`# If someone told you to run this, stop!\n` + `# If someone told you to run this, stop!\n` +
`This could give an attacker access to all servers you're using AutoMod in.\n` + `This could give an attacker access to all servers you're using AutoMod in.\n` +
`If someone else told you to run this command, **block them and ignore this.**\n\n` + `If someone else told you to run this command, **block them and ignore this.**\n\n` +
`Otherwise, if this was you trying to log in from <${process.env.WEB_UI_URL || 'https://automod.janderedev.xyz'}>, \n` + `Otherwise, if this was you trying to log in from <${process.env['WEB_UI_URL'] || 'https://automod.janderedev.xyz'}>, \n` +
`you can run this command again to continue.\n` + `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!` `##### You're seeing this because this is the first time you're trying to log in. Stay safe!`
), ),

View file

@ -1,5 +1,5 @@
import SimpleCommand from "../../../struct/commands/SimpleCommand"; import SimpleCommand from "../../../struct/commands/SimpleCommand";
import { client, dbs } from "../../.."; import { dbs } from "../../..";
import { DEFAULT_PREFIX } from "../../modules/command_handler"; import { DEFAULT_PREFIX } from "../../modules/command_handler";
import { isBotManager, NO_MANAGER_MSG } from "../../util"; import { isBotManager, NO_MANAGER_MSG } from "../../util";
import MessageCommandContext from "../../../struct/MessageCommandContext"; import MessageCommandContext from "../../../struct/MessageCommandContext";

View file

@ -7,8 +7,8 @@ export default {
aliases: [ 'setting' ], aliases: [ 'setting' ],
description: 'Manage AutoMod\'s configuration', description: 'Manage AutoMod\'s configuration',
category: CommandCategory.Config, category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext) => {
await message.reply(`Bot configuration can be managed from ` await message.reply(`Bot configuration can be managed from `
+ `[here](<${process.env.WEB_UI_URL || 'https://automod.janderedev.xyz'}/dashboard>).`); + `[here](<${process.env['WEB_UI_URL'] || 'https://automod.janderedev.xyz'}/dashboard>).`);
} }
} as SimpleCommand; } as SimpleCommand;

View file

@ -8,6 +8,6 @@ export default {
description: 'Health check', description: 'Health check',
category: CommandCategory.Miscellaneous, category: CommandCategory.Miscellaneous,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
const msg = await message.reply('Health check success: ' + args.join(' ')); await message.reply('Health check success: ' + args.join(' '));
} }
} as SimpleCommand; } as SimpleCommand;

View file

@ -53,7 +53,7 @@ export default {
`## AutoMod Help\n` + `## AutoMod Help\n` +
`Type **${prefix}help [category]** to view see all commands or **${prefix}help [command]** to learn more about a command.\n\n` + `Type **${prefix}help [category]** to view see all commands or **${prefix}help [command]** to learn more about a command.\n\n` +
`### [Open Server Settings]` + `### [Open Server Settings]` +
`(<${process.env.WEB_UI_URL || "https://automod.vale.rocks"}/dashboard/${message.channel?.serverId}>)\n\n`; `(<${process.env['WEB_UI_URL'] || "https://automod.vale.rocks"}/dashboard/${message.channel?.serverId}>)\n\n`;
let total = 0; let total = 0;

View file

@ -7,7 +7,7 @@ export default {
aliases: ["testalias"], aliases: ["testalias"],
description: "Test command", description: "Test command",
category: CommandCategory.Miscellaneous, category: CommandCategory.Miscellaneous,
run: (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext) => {
message.reply({ message.reply({
content: "Beep boop.", content: "Beep boop.",
embeds: [ embeds: [

View file

@ -1,11 +1,7 @@
import { ServerMember } from "revolt.js";
import axios from "axios";
import CommandCategory from "../../../struct/commands/CommandCategory"; import CommandCategory from "../../../struct/commands/CommandCategory";
import SimpleCommand from "../../../struct/commands/SimpleCommand"; import SimpleCommand from "../../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../../struct/MessageCommandContext"; import MessageCommandContext from "../../../struct/MessageCommandContext";
import { isModerator, NO_MANAGER_MSG, parseUser } from "../../util"; import { isModerator, NO_MANAGER_MSG, parseUser } from "../../util";
import AutomodClient from "../../../struct/AutomodClient";
import { client } from "../../..";
export default { export default {
name: 'avatar', name: 'avatar',

View file

@ -17,7 +17,6 @@ import {
getMembers, getMembers,
isModerator, isModerator,
NO_MANAGER_MSG, NO_MANAGER_MSG,
parseUser,
parseUserOrId, parseUserOrId,
sanitizeMessageContent, sanitizeMessageContent,
storeInfraction, storeInfraction,

View file

@ -1,6 +1,5 @@
import { FindResult } from "monk";
import { ulid } from "ulid"; import { ulid } from "ulid";
import { client, dbs } from "../../../"; import { dbs } from "../../../";
import CommandCategory from "../../../struct/commands/CommandCategory"; import CommandCategory from "../../../struct/commands/CommandCategory";
import SimpleCommand from "../../../struct/commands/SimpleCommand"; import SimpleCommand from "../../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../../struct/MessageCommandContext"; import MessageCommandContext from "../../../struct/MessageCommandContext";

View file

@ -1,6 +1,6 @@
import Log75, { LogLevel } from 'log75'; import Log75, { LogLevel } from 'log75';
// Thanks to being forced to switch to ESM this broke somehow? // Thanks to being forced to switch to ESM this broke somehow?
let logger: Log75 = new (Log75 as any).default(process.env.NODE_ENV == 'production' ? LogLevel.Standard : LogLevel.Debug); let logger: Log75 = new (Log75 as any).default(process.env['NODE_ENV'] == 'production' ? LogLevel.Standard : LogLevel.Debug);
export default logger; export default logger;

View file

@ -1,12 +1,12 @@
import { Message } from "revolt.js"; import { Message } from "revolt.js";
import { ulid } from "ulid"; import { ulid } from "ulid";
import { client, dbs } from "../.."; import { dbs } from "../..";
import AntispamRule from "automod/dist/types/antispam/AntispamRule"; import AntispamRule from "automod/dist/types/antispam/AntispamRule";
import Infraction from "automod/dist/types/antispam/Infraction"; import Infraction from "automod/dist/types/antispam/Infraction";
import InfractionType from "automod/dist/types/antispam/InfractionType"; import InfractionType from "automod/dist/types/antispam/InfractionType";
import ModerationAction from "automod/dist/types/antispam/ModerationAction"; import ModerationAction from "automod/dist/types/antispam/ModerationAction";
import logger from "../logger"; import logger from "../logger";
import { awaitClient, generateInfractionDMEmbed, isModerator, sendLogMessage, storeInfraction } from "../util"; import { generateInfractionDMEmbed, isModerator, sendLogMessage, storeInfraction } from "../util";
import { getDmChannel, sanitizeMessageContent } from "../util"; import { getDmChannel, sanitizeMessageContent } from "../util";
import ServerConfig from "automod/dist/types/ServerConfig"; import ServerConfig from "automod/dist/types/ServerConfig";
import { WORDLIST_DEFAULT_MESSAGE } from "../commands/configuration/botctl"; import { WORDLIST_DEFAULT_MESSAGE } from "../commands/configuration/botctl";
@ -124,7 +124,6 @@ async function wordFilterCheck(message: Message, config: ServerConfig) {
console.log('Message matched word filter!'); console.log('Message matched word filter!');
// Lack of `break` is intended here
switch (config.wordlistAction?.action) { switch (config.wordlistAction?.action) {
case 'WARN': { case 'WARN': {
try { try {
@ -149,8 +148,10 @@ async function wordFilterCheck(message: Message, config: ServerConfig) {
} }
else logger.warn('Missing permission to DM user.'); else logger.warn('Missing permission to DM user.');
} }
break;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
break;
} }
} }
case 'DELETE': { case 'DELETE': {
@ -164,7 +165,9 @@ async function wordFilterCheck(message: Message, config: ServerConfig) {
await message.channel.sendMessage((config.wordlistAction.message || WORDLIST_DEFAULT_MESSAGE) await message.channel.sendMessage((config.wordlistAction.message || WORDLIST_DEFAULT_MESSAGE)
.replaceAll('{{user_id}}', message.authorId!)); .replaceAll('{{user_id}}', message.authorId!));
} }
break;
} }
break;
} }
case 'LOG': case 'LOG':
default: { default: {
@ -177,8 +180,8 @@ async function wordFilterCheck(message: Message, config: ServerConfig) {
`>${sanitizeMessageContent(message.content.substring(0, 1000)).trim().replace(/\n/g, '\n>')}`, `>${sanitizeMessageContent(message.content.substring(0, 1000)).trim().replace(/\n/g, '\n>')}`,
color: '#ff557f', color: '#ff557f',
}); });
break;
} }
} }
} catch (e) { } catch (e) {
console.error(e); console.error(e);
@ -251,51 +254,4 @@ function checkMessageForFilteredWords(message: string, config: ServerConfig): bo
return false; return false;
} }
// Scan all servers for the `discoverable` flag and notify their owners that antispam is forcefully enabled
const notifyPublicServers = async () => {
logger.info('Sending antispam notification to public servers');
const servers = Array.from(client.servers.values())
.filter(server => server.discoverable);
const res = await dbs.SERVERS.find({
id: { $in: servers.map(s => s.id) },
discoverAutospamNotify: { $in: [ undefined, false ] },
});
for (const serverConfig of res) {
try {
logger.info(`Sending notification to owner of server ${serverConfig.id}`);
if (serverConfig.discoverAutospamNotify) {
logger.warn('This server already received the message');
continue;
}
await dbs.SERVERS.update(
{ id: serverConfig.id },
{ $set: { discoverAutospamNotify: true, antispamEnabled: true, allowBlacklistedUsers: false } },
);
const server = client.servers.get(serverConfig.id);
const channel = await getDmChannel(server!.ownerId);
await channel.sendMessage(`Hi there,
It looks like your server, **${sanitizeMessageContent(server!.name).trim()}**, has been added to server discovery. Congratulations!
In order to keep Revolt free of spam, AutoMod enables spam protection by default on public servers.
You are receiving this message to inform you that said features have been enabled automatically in your server.
Please ensure that AutoMod has appropriate permissions to kick and ban users.
You may also want to set up a logging channel by running \`/botctl logs modaction #yourchannel\` to receive details about antispam events if you haven't done so already.
Thanks for being part of Revolt!`);
} catch(e) {
console.error(e);
}
}
}
// awaitClient().then(() => notifyPublicServers());
export { antispam, wordFilterCheck, checkMessageForFilteredWords } export { antispam, wordFilterCheck, checkMessageForFilteredWords }

View file

@ -39,7 +39,7 @@ async function messageContentTrigger(message: Message, trigger: CustomRuleTrigge
let script = new VM.Script('matchedStrings = content.match(regex);', { timeout: 2 }); let script = new VM.Script('matchedStrings = content.match(regex);', { timeout: 2 });
script.runInContext(ctx); script.runInContext(ctx);
if (ctx.matchedStrings?.length) matched = true; if (ctx['matchedStrings']?.length) matched = true;
} catch(e) { } catch(e) {
console.error('Exception thrown while parsing RegEx: ' + e); console.error('Exception thrown while parsing RegEx: ' + e);
} }

View file

@ -3,7 +3,7 @@ import http from 'http';
import logger from '../logger'; import logger from '../logger';
import { client } from '../..'; import { client } from '../..';
const PORT = Number(process.env.BOT_METRICS_PORT); const PORT = Number(process.env['BOT_METRICS_PORT']);
prom.collectDefaultMetrics({ prefix: 'automod_' }); prom.collectDefaultMetrics({ prefix: 'automod_' });
@ -45,11 +45,11 @@ if (!isNaN(PORT)) {
measureLatency(); measureLatency();
setInterval(measureLatency, 10000); setInterval(measureLatency, 10000);
if (process.env.BOT_METRICS_MSG_PING_CHANNEL) { if (process.env['BOT_METRICS_MSG_PING_CHANNEL']) {
logger.info('BOT_METRICS_MSG_PING_CHANNEL is set, enabling message latency measuring'); logger.info('BOT_METRICS_MSG_PING_CHANNEL is set, enabling message latency measuring');
const getMsgPing = async () => { const getMsgPing = async () => {
const channel = client.channels.get(process.env.BOT_METRICS_MSG_PING_CHANNEL!); const channel = client.channels.get(process.env['BOT_METRICS_MSG_PING_CHANNEL']!);
try { try {
const now = Date.now(); const now = Date.now();
const msg = await channel?.sendMessage('Ping?'); const msg = await channel?.sendMessage('Ping?');

View file

@ -56,7 +56,6 @@ client.on('messageUpdate', async (message, oldMessage) => {
client.on('messageDelete', async (message) => { client.on('messageDelete', async (message) => {
try { try {
let channel = client.channels.get(message.channelId); let channel = client.channels.get(message.channelId);
let author = message.authorId ? client.users.get(message.authorId) : null;
if (!channel) return; if (!channel) return;
let msgRaw = String(message.content ?? '(Unknown)'); let msgRaw = String(message.content ?? '(Unknown)');
@ -114,7 +113,6 @@ client.on('messageDeleteBulk', async (messages) => {
]); ]);
} }
const sheet = Xlsx.utils.aoa_to_sheet(data);
const csv = Xlsx.utils.sheet_to_csv(data); const csv = Xlsx.utils.sheet_to_csv(data);
let embed: LogMessage = { let embed: LogMessage = {

View file

@ -5,5 +5,5 @@ import logger from '../logger';
if (process.env['AUTOMOD_LOAD_SPAM_DETECTION']) { if (process.env['AUTOMOD_LOAD_SPAM_DETECTION']) {
logger.info('Importing spam detection'); logger.info('Importing spam detection');
import(path.join(process.cwd(), '..', 'private', 'automod-spam-detection', 'dist', 'index.js')) import(path.join(process.cwd(), '..', 'private', 'automod-spam-detection', 'dist', 'index.js'))
.then(mod => mod.raidDetection(client as any, logger, client.db, process.env.REDIS_URL)); .then(mod => mod.raidDetection(client as any, logger, client.db, process.env['REDIS_URL']));
} }

View file

@ -1,4 +1,3 @@
import { FindResult } from "monk";
import { client, dbs } from "../.."; import { client, dbs } from "../..";
import TempBan from "automod/dist/types/TempBan"; import TempBan from "automod/dist/types/TempBan";
import logger from "../logger"; import logger from "../logger";

View file

@ -8,7 +8,6 @@ import { Server } from "revolt.js";
import LogConfig from "automod/dist/types/LogConfig"; import LogConfig from "automod/dist/types/LogConfig";
import LogMessage from "automod/dist/types/LogMessage"; import LogMessage from "automod/dist/types/LogMessage";
import logger from "./logger"; import logger from "./logger";
import { ulid } from "ulid";
import { Channel } from "revolt.js"; import { Channel } from "revolt.js";
import { Message } from "revolt.js"; import { Message } from "revolt.js";
import { isSudo } from "./commands/admin/botadm"; import { isSudo } from "./commands/admin/botadm";

View file

@ -1,25 +1,30 @@
{ {
"compilerOptions": { "compilerOptions": {
// Enable latest features // Enable latest features
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"target": "ESNext", "target": "ESNext",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleDetection": "force",
"allowJs": true,
// Bundler mode // Bundler mode
"declaration": true, "moduleResolution": "node",
"sourceMap": true,
"rootDir": "./src",
"outDir": "./dist",
// Interop
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
// Best practices // Best practices
"strict": true, "strict": true,
"strictPropertyInitialization": false,
"skipLibCheck": true, "skipLibCheck": true,
}, "strictPropertyInitialization": false,
"include": ["src/**/*"], "noFallthroughCasesInSwitch": true,
"exclude": ["node_modules", "dist"] // Some stricter flags (enabled)
"noUnusedLocals": true,
"noUnusedParameters": true,
"noPropertyAccessFromIndexSignature": true,
"declaration": true,
"declarationMap": true,
// Additional improvements
"esModuleInterop": true,
"resolveJsonModule": true,
"forceConsistentCasingInFileNames": true,
"useDefineForClassFields": true,
"rootDir": "./src",
"outDir": "./dist"
}
} }