3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-18 15:00:00 +00:00
zeppelin/backend/src/plugins/AntiRaid.ts

160 lines
5 KiB
TypeScript
Raw Normal View History

import { IPluginOptions, logger } from "knub";
import * as t from "io-ts";
import { ZeppelinPlugin } from "./ZeppelinPlugin";
import { GuildSavedMessages } from "../data/GuildSavedMessages";
import { SavedMessage } from "../data/entities/SavedMessage";
import { convertDelayStringToMS, MINUTES, sorter, stripObjectToScalars, tDelayString } from "../utils";
import { GuildLogs } from "../data/GuildLogs";
import { LogType } from "../data/LogType";
import moment from "moment-timezone";
const AntiRaidLevel = t.type({
on_join: t.type({
kick: t.boolean,
ban: t.boolean,
}),
});
const ConfigSchema = t.type({
enabled: t.boolean,
delay: tDelayString,
});
type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
interface IDeletionQueueItem {
deleteAt: number;
message: SavedMessage;
}
const MAX_DELAY = 5 * MINUTES;
export class AntiRaid extends ZeppelinPlugin<TConfigSchema> {
public static pluginName = "auto_delete";
public static showInDocs = true;
public static configSchema = ConfigSchema;
public static pluginInfo = {
prettyName: "Auto-delete",
description: "Allows Zeppelin to auto-delete messages from a channel after a delay",
configurationGuide: "Maximum deletion delay is currently 5 minutes",
};
protected guildSavedMessages: GuildSavedMessages;
protected guildLogs: GuildLogs;
protected onMessageCreateFn;
protected onMessageDeleteFn;
protected onMessageDeleteBulkFn;
protected deletionQueue: IDeletionQueueItem[];
protected nextDeletion: number;
protected nextDeletionTimeout;
protected maxDelayWarningSent = false;
public static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
return {
config: {
enabled: false,
delay: "5s",
},
};
}
protected onLoad() {
this.guildSavedMessages = GuildSavedMessages.getGuildInstance(this.guildId);
this.guildLogs = new GuildLogs(this.guildId);
this.deletionQueue = [];
this.onMessageCreateFn = this.onMessageCreate.bind(this);
this.onMessageDeleteFn = this.onMessageDelete.bind(this);
this.onMessageDeleteBulkFn = this.onMessageDeleteBulk.bind(this);
this.guildSavedMessages.events.on("create", this.onMessageCreateFn);
this.guildSavedMessages.events.on("delete", this.onMessageDeleteFn);
this.guildSavedMessages.events.on("deleteBulk", this.onMessageDeleteBulkFn);
}
protected onUnload() {
this.guildSavedMessages.events.off("create", this.onMessageCreateFn);
this.guildSavedMessages.events.off("delete", this.onMessageDeleteFn);
this.guildSavedMessages.events.off("deleteBulk", this.onMessageDeleteFn);
clearTimeout(this.nextDeletionTimeout);
}
protected addMessageToDeletionQueue(msg: SavedMessage, delay: number) {
const deleteAt = Date.now() + delay;
this.deletionQueue.push({ deleteAt, message: msg });
this.deletionQueue.sort(sorter("deleteAt"));
this.scheduleNextDeletion();
}
protected scheduleNextDeletion() {
if (this.deletionQueue.length === 0) {
clearTimeout(this.nextDeletionTimeout);
return;
}
const firstDeleteAt = this.deletionQueue[0].deleteAt;
clearTimeout(this.nextDeletionTimeout);
this.nextDeletionTimeout = setTimeout(() => this.deleteNextItem(), firstDeleteAt - Date.now());
}
protected async deleteNextItem() {
const [itemToDelete] = this.deletionQueue.splice(0, 1);
if (!itemToDelete) return;
this.guildLogs.ignoreLog(LogType.MESSAGE_DELETE, itemToDelete.message.id);
this.bot.deleteMessage(itemToDelete.message.channel_id, itemToDelete.message.id).catch(logger.warn);
this.scheduleNextDeletion();
const user = await this.resolveUser(itemToDelete.message.user_id);
const channel = this.guild.channels.get(itemToDelete.message.channel_id);
const messageDate = moment(itemToDelete.message.data.timestamp, "x").format("YYYY-MM-DD HH:mm:ss");
this.guildLogs.log(LogType.MESSAGE_DELETE_AUTO, {
message: itemToDelete.message,
user: stripObjectToScalars(user),
channel: stripObjectToScalars(channel),
messageDate,
});
}
protected onMessageCreate(msg: SavedMessage) {
const config = this.getConfigForMemberIdAndChannelId(msg.user_id, msg.channel_id);
if (config.enabled) {
let delay = convertDelayStringToMS(config.delay);
if (delay > MAX_DELAY) {
delay = MAX_DELAY;
if (!this.maxDelayWarningSent) {
this.guildLogs.log(LogType.BOT_ALERT, {
body: `Clamped auto-deletion delay in <#${msg.channel_id}> to 5 minutes`,
});
this.maxDelayWarningSent = true;
}
}
this.addMessageToDeletionQueue(msg, delay);
}
}
protected onMessageDelete(msg: SavedMessage) {
const indexToDelete = this.deletionQueue.findIndex(item => item.message.id === msg.id);
if (indexToDelete > -1) {
this.deletionQueue.splice(indexToDelete, 1);
this.scheduleNextDeletion();
}
}
protected onMessageDeleteBulk(messages: SavedMessage[]) {
for (const msg of messages) {
this.onMessageDelete(msg);
}
}
}