2020-10-01 01:43:38 +03:00
|
|
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
2020-07-27 20:42:10 +03:00
|
|
|
import { AutomodPluginType, ConfigSchema } from "./types";
|
|
|
|
import { RunAutomodOnJoinEvt } from "./events/RunAutomodOnJoinEvt";
|
|
|
|
import { GuildLogs } from "../../data/GuildLogs";
|
|
|
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
|
|
|
import { runAutomodOnMessage } from "./events/runAutomodOnMessage";
|
|
|
|
import { Queue } from "../../Queue";
|
2020-07-30 01:54:18 +03:00
|
|
|
import { configUtils, CooldownManager } from "knub";
|
2020-07-27 20:42:10 +03:00
|
|
|
import { availableTriggers } from "./triggers/availableTriggers";
|
|
|
|
import { StrictValidationError } from "../../validatorUtils";
|
|
|
|
import { ConfigPreprocessorFn } from "knub/dist/config/configTypes";
|
|
|
|
import { availableActions } from "./actions/availableActions";
|
|
|
|
import { clearOldRecentActions } from "./functions/clearOldRecentActions";
|
2020-08-05 01:15:36 +03:00
|
|
|
import { disableCodeBlocks, MINUTES, SECONDS } from "../../utils";
|
2020-07-27 20:42:10 +03:00
|
|
|
import { clearOldRecentSpam } from "./functions/clearOldRecentSpam";
|
|
|
|
import { GuildAntiraidLevels } from "../../data/GuildAntiraidLevels";
|
|
|
|
import { GuildArchives } from "../../data/GuildArchives";
|
2020-07-28 21:34:01 +03:00
|
|
|
import { clearOldRecentNicknameChanges } from "./functions/clearOldNicknameChanges";
|
2020-07-28 21:51:58 +03:00
|
|
|
import { LogsPlugin } from "../Logs/LogsPlugin";
|
|
|
|
import { ModActionsPlugin } from "../ModActions/ModActionsPlugin";
|
|
|
|
import { MutesPlugin } from "../Mutes/MutesPlugin";
|
2020-07-30 00:58:34 +03:00
|
|
|
import { AntiraidClearCmd } from "./commands/AntiraidClearCmd";
|
|
|
|
import { SetAntiraidCmd } from "./commands/SetAntiraidCmd";
|
|
|
|
import { ViewAntiraidCmd } from "./commands/ViewAntiraidCmd";
|
2020-07-30 13:08:06 +03:00
|
|
|
import { pluginInfo } from "./info";
|
2020-08-05 01:15:36 +03:00
|
|
|
import { RegExpRunner } from "../../RegExpRunner";
|
|
|
|
import { LogType } from "../../data/LogType";
|
|
|
|
import { logger } from "../../logger";
|
|
|
|
import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners";
|
2020-08-10 02:22:39 +03:00
|
|
|
import { RunAutomodOnMemberUpdate } from "./events/RunAutomodOnMemberUpdate";
|
2021-02-13 17:29:10 +02:00
|
|
|
import { CountersPlugin } from "../Counters/CountersPlugin";
|
|
|
|
import { parseCondition } from "../../data/GuildCounters";
|
|
|
|
import { runAutomodOnCounterTrigger } from "./events/runAutomodOnCounterTrigger";
|
2021-02-14 16:58:02 +02:00
|
|
|
import { runAutomodOnModAction } from "./events/runAutomodOnModAction";
|
|
|
|
import { registerEventListenersFromMap } from "../../utils/registerEventListenersFromMap";
|
|
|
|
import { unregisterEventListenersFromMap } from "../../utils/unregisterEventListenersFromMap";
|
2020-07-27 20:42:10 +03:00
|
|
|
|
|
|
|
const defaultOptions = {
|
|
|
|
config: {
|
|
|
|
rules: {},
|
|
|
|
antiraid_levels: ["low", "medium", "high"],
|
|
|
|
can_set_antiraid: false,
|
|
|
|
can_view_antiraid: false,
|
|
|
|
},
|
|
|
|
overrides: [
|
|
|
|
{
|
|
|
|
level: ">=50",
|
|
|
|
config: {
|
|
|
|
can_view_antiraid: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
level: ">=100",
|
|
|
|
config: {
|
|
|
|
can_set_antiraid: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2021-02-13 17:29:10 +02:00
|
|
|
* Config preprocessor to set default values for triggers and perform extra validation
|
2020-07-27 20:42:10 +03:00
|
|
|
*/
|
|
|
|
const configPreprocessor: ConfigPreprocessorFn<AutomodPluginType> = options => {
|
|
|
|
if (options.config?.rules) {
|
|
|
|
// Loop through each rule
|
|
|
|
for (const [name, rule] of Object.entries(options.config.rules)) {
|
2020-07-30 11:05:03 +03:00
|
|
|
if (rule == null) {
|
|
|
|
delete options.config.rules[name];
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-07-27 20:42:10 +03:00
|
|
|
rule["name"] = name;
|
|
|
|
|
|
|
|
// If the rule doesn't have an explicitly set "enabled" property, set it to true
|
|
|
|
if (rule["enabled"] == null) {
|
|
|
|
rule["enabled"] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule["affects_bots"] == null) {
|
|
|
|
rule["affects_bots"] = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Loop through the rule's triggers
|
|
|
|
if (rule["triggers"]) {
|
|
|
|
for (const triggerObj of rule["triggers"]) {
|
|
|
|
for (const triggerName in triggerObj) {
|
|
|
|
if (!availableTriggers[triggerName]) {
|
|
|
|
throw new StrictValidationError([`Unknown trigger '${triggerName}' in rule '${rule.name}'`]);
|
|
|
|
}
|
|
|
|
|
|
|
|
const triggerBlueprint = availableTriggers[triggerName];
|
2020-08-10 02:22:39 +03:00
|
|
|
|
|
|
|
if (typeof triggerBlueprint.defaultConfig === "object" && triggerBlueprint.defaultConfig != null) {
|
|
|
|
triggerObj[triggerName] = configUtils.mergeConfig(
|
|
|
|
triggerBlueprint.defaultConfig,
|
|
|
|
triggerObj[triggerName] || {},
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
triggerObj[triggerName] = triggerObj[triggerName] || triggerBlueprint.defaultConfig;
|
|
|
|
}
|
2020-07-27 20:42:10 +03:00
|
|
|
|
|
|
|
if (triggerObj[triggerName].match_attachment_type) {
|
|
|
|
const white = triggerObj[triggerName].match_attachment_type.whitelist_enabled;
|
|
|
|
const black = triggerObj[triggerName].match_attachment_type.blacklist_enabled;
|
|
|
|
|
|
|
|
if (white && black) {
|
|
|
|
throw new StrictValidationError([
|
|
|
|
`Cannot have both blacklist and whitelist enabled at rule <${rule.name}/match_attachment_type>`,
|
|
|
|
]);
|
|
|
|
} else if (!white && !black) {
|
|
|
|
throw new StrictValidationError([
|
|
|
|
`Must have either blacklist or whitelist enabled at rule <${rule.name}/match_attachment_type>`,
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
}
|
2021-02-13 17:29:10 +02:00
|
|
|
|
|
|
|
if (triggerName === "counter") {
|
|
|
|
const parsedCondition = parseCondition(triggerObj[triggerName]!.condition);
|
|
|
|
if (parsedCondition == null) {
|
|
|
|
throw new StrictValidationError([
|
|
|
|
`Invalid counter condition '${triggerObj[triggerName]!.condition}' in rule <${rule.name}>`,
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
}
|
2020-07-27 20:42:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-30 01:45:14 +03:00
|
|
|
if (rule["actions"]) {
|
|
|
|
for (const actionName in rule["actions"]) {
|
|
|
|
if (!availableActions[actionName]) {
|
|
|
|
throw new StrictValidationError([`Unknown action '${actionName}' in rule '${rule.name}'`]);
|
|
|
|
}
|
|
|
|
|
|
|
|
const actionBlueprint = availableActions[actionName];
|
|
|
|
const actionConfig = rule["actions"][actionName];
|
|
|
|
|
|
|
|
if (typeof actionConfig !== "object" || Array.isArray(actionConfig) || actionConfig == null) {
|
|
|
|
rule["actions"][actionName] = actionConfig;
|
|
|
|
} else {
|
|
|
|
rule["actions"][actionName] = configUtils.mergeConfig(actionBlueprint.defaultConfig, actionConfig);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-27 20:42:10 +03:00
|
|
|
// Enable logging of automod actions by default
|
|
|
|
if (rule["actions"]) {
|
|
|
|
for (const actionName in rule.actions) {
|
|
|
|
if (!availableActions[actionName]) {
|
|
|
|
throw new StrictValidationError([`Unknown action '${actionName}' in rule '${rule.name}'`]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-28 21:34:01 +03:00
|
|
|
if (rule["actions"]["log"] == null) {
|
|
|
|
rule["actions"]["log"] = true;
|
|
|
|
}
|
2020-07-27 20:42:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return options;
|
|
|
|
};
|
|
|
|
|
2020-10-01 01:43:38 +03:00
|
|
|
export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()("automod", {
|
2020-07-30 13:08:06 +03:00
|
|
|
showInDocs: true,
|
|
|
|
info: pluginInfo,
|
|
|
|
|
2021-02-14 16:58:02 +02:00
|
|
|
// prettier-ignore
|
|
|
|
dependencies: [
|
|
|
|
LogsPlugin,
|
|
|
|
ModActionsPlugin,
|
|
|
|
MutesPlugin,
|
|
|
|
CountersPlugin,
|
|
|
|
],
|
2020-07-28 21:51:58 +03:00
|
|
|
|
2020-07-27 20:42:10 +03:00
|
|
|
configSchema: ConfigSchema,
|
|
|
|
defaultOptions,
|
|
|
|
configPreprocessor,
|
|
|
|
|
2020-07-28 21:51:58 +03:00
|
|
|
customOverrideMatcher(pluginData, criteria, matchParams) {
|
2020-11-09 20:03:57 +02:00
|
|
|
return criteria?.antiraid_level ? criteria.antiraid_level === pluginData.state.cachedAntiraidLevel : false;
|
2020-07-28 21:51:58 +03:00
|
|
|
},
|
|
|
|
|
2021-02-14 16:58:02 +02:00
|
|
|
// prettier-ignore
|
2020-07-27 20:42:10 +03:00
|
|
|
events: [
|
|
|
|
RunAutomodOnJoinEvt,
|
2020-08-10 02:22:39 +03:00
|
|
|
RunAutomodOnMemberUpdate,
|
2020-07-27 20:42:10 +03:00
|
|
|
// Messages use message events from SavedMessages, see onLoad below
|
|
|
|
],
|
|
|
|
|
2020-07-30 00:58:34 +03:00
|
|
|
commands: [AntiraidClearCmd, SetAntiraidCmd, ViewAntiraidCmd],
|
|
|
|
|
2020-07-28 21:51:58 +03:00
|
|
|
async onLoad(pluginData) {
|
2020-07-27 20:42:10 +03:00
|
|
|
pluginData.state.queue = new Queue();
|
|
|
|
|
2020-08-05 01:15:36 +03:00
|
|
|
pluginData.state.regexRunner = getRegExpRunner(`guild-${pluginData.guild.id}`);
|
|
|
|
|
2020-07-27 20:42:10 +03:00
|
|
|
pluginData.state.recentActions = [];
|
|
|
|
pluginData.state.clearRecentActionsInterval = setInterval(() => clearOldRecentActions(pluginData), 1 * MINUTES);
|
|
|
|
|
|
|
|
pluginData.state.recentSpam = [];
|
|
|
|
pluginData.state.clearRecentSpamInterval = setInterval(() => clearOldRecentSpam(pluginData), 1 * SECONDS);
|
|
|
|
|
2020-07-28 21:34:01 +03:00
|
|
|
pluginData.state.recentNicknameChanges = new Map();
|
|
|
|
pluginData.state.clearRecentNicknameChangesInterval = setInterval(
|
|
|
|
() => clearOldRecentNicknameChanges(pluginData),
|
|
|
|
30 * SECONDS,
|
|
|
|
);
|
|
|
|
|
2020-08-10 02:22:39 +03:00
|
|
|
pluginData.state.ignoredRoleChanges = new Set();
|
|
|
|
|
2020-07-30 01:54:18 +03:00
|
|
|
pluginData.state.cooldownManager = new CooldownManager();
|
|
|
|
|
2020-07-27 20:42:10 +03:00
|
|
|
pluginData.state.logs = new GuildLogs(pluginData.guild.id);
|
|
|
|
pluginData.state.savedMessages = GuildSavedMessages.getGuildInstance(pluginData.guild.id);
|
|
|
|
pluginData.state.antiraidLevels = GuildAntiraidLevels.getGuildInstance(pluginData.guild.id);
|
|
|
|
pluginData.state.archives = GuildArchives.getGuildInstance(pluginData.guild.id);
|
|
|
|
|
|
|
|
pluginData.state.onMessageCreateFn = message => runAutomodOnMessage(pluginData, message, false);
|
|
|
|
pluginData.state.savedMessages.events.on("create", pluginData.state.onMessageCreateFn);
|
|
|
|
|
|
|
|
pluginData.state.onMessageUpdateFn = message => runAutomodOnMessage(pluginData, message, true);
|
|
|
|
pluginData.state.savedMessages.events.on("update", pluginData.state.onMessageUpdateFn);
|
2020-07-28 21:51:58 +03:00
|
|
|
|
|
|
|
pluginData.state.cachedAntiraidLevel = await pluginData.state.antiraidLevels.get();
|
2020-07-27 20:42:10 +03:00
|
|
|
},
|
|
|
|
|
2021-02-13 17:29:10 +02:00
|
|
|
async onAfterLoad(pluginData) {
|
|
|
|
const countersPlugin = pluginData.getPlugin(CountersPlugin);
|
|
|
|
|
|
|
|
pluginData.state.onCounterTrigger = (name, condition, channelId, userId) => {
|
|
|
|
runAutomodOnCounterTrigger(pluginData, name, condition, channelId, userId, false);
|
|
|
|
};
|
|
|
|
|
|
|
|
pluginData.state.onCounterReverseTrigger = (name, condition, channelId, userId) => {
|
|
|
|
runAutomodOnCounterTrigger(pluginData, name, condition, channelId, userId, true);
|
|
|
|
};
|
|
|
|
|
|
|
|
const config = pluginData.config.get();
|
|
|
|
for (const rule of Object.values(config.rules)) {
|
|
|
|
for (const trigger of rule.triggers) {
|
|
|
|
if (trigger.counter) {
|
|
|
|
await countersPlugin.initCounterTrigger(trigger.counter.name, trigger.counter.condition);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
countersPlugin.onCounterEvent("trigger", pluginData.state.onCounterTrigger);
|
|
|
|
countersPlugin.onCounterEvent("reverseTrigger", pluginData.state.onCounterReverseTrigger);
|
2021-02-14 16:58:02 +02:00
|
|
|
|
|
|
|
const modActionsEvents = pluginData.getPlugin(ModActionsPlugin).getEventEmitter();
|
|
|
|
pluginData.state.modActionsListeners = new Map();
|
|
|
|
pluginData.state.modActionsListeners.set("note", (userId: string) =>
|
|
|
|
runAutomodOnModAction(pluginData, "note", userId),
|
|
|
|
);
|
|
|
|
pluginData.state.modActionsListeners.set("warn", (userId: string) =>
|
|
|
|
runAutomodOnModAction(pluginData, "warn", userId),
|
|
|
|
);
|
|
|
|
pluginData.state.modActionsListeners.set("kick", (userId: string) =>
|
|
|
|
runAutomodOnModAction(pluginData, "kick", userId),
|
|
|
|
);
|
|
|
|
pluginData.state.modActionsListeners.set("ban", (userId: string) =>
|
|
|
|
runAutomodOnModAction(pluginData, "ban", userId),
|
|
|
|
);
|
|
|
|
pluginData.state.modActionsListeners.set("unban", (userId: string) =>
|
|
|
|
runAutomodOnModAction(pluginData, "unban", userId),
|
|
|
|
);
|
|
|
|
registerEventListenersFromMap(modActionsEvents, pluginData.state.modActionsListeners);
|
|
|
|
|
|
|
|
const mutesEvents = pluginData.getPlugin(MutesPlugin).getEventEmitter();
|
|
|
|
pluginData.state.mutesListeners = new Map();
|
|
|
|
pluginData.state.mutesListeners.set("mute", (userId: string) => runAutomodOnModAction(pluginData, "mute", userId));
|
|
|
|
pluginData.state.mutesListeners.set("unmute", (userId: string) =>
|
|
|
|
runAutomodOnModAction(pluginData, "unmute", userId),
|
|
|
|
);
|
|
|
|
registerEventListenersFromMap(mutesEvents, pluginData.state.mutesListeners);
|
2021-02-13 17:29:10 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
async onBeforeUnload(pluginData) {
|
|
|
|
const countersPlugin = pluginData.getPlugin(CountersPlugin);
|
|
|
|
countersPlugin.offCounterEvent("trigger", pluginData.state.onCounterTrigger);
|
|
|
|
countersPlugin.offCounterEvent("reverseTrigger", pluginData.state.onCounterReverseTrigger);
|
2021-02-14 16:58:02 +02:00
|
|
|
|
|
|
|
const modActionsEvents = pluginData.getPlugin(ModActionsPlugin).getEventEmitter();
|
|
|
|
unregisterEventListenersFromMap(modActionsEvents, pluginData.state.modActionsListeners);
|
|
|
|
|
|
|
|
const mutesEvents = pluginData.getPlugin(MutesPlugin).getEventEmitter();
|
|
|
|
unregisterEventListenersFromMap(mutesEvents, pluginData.state.mutesListeners);
|
2021-02-13 17:29:10 +02:00
|
|
|
},
|
|
|
|
|
2020-08-05 01:15:36 +03:00
|
|
|
async onUnload(pluginData) {
|
2020-07-27 20:42:10 +03:00
|
|
|
pluginData.state.queue.clear();
|
|
|
|
|
2020-08-05 01:15:36 +03:00
|
|
|
discardRegExpRunner(`guild-${pluginData.guild.id}`);
|
|
|
|
|
2020-07-27 20:42:10 +03:00
|
|
|
clearInterval(pluginData.state.clearRecentActionsInterval);
|
|
|
|
|
|
|
|
clearInterval(pluginData.state.clearRecentSpamInterval);
|
|
|
|
|
2020-07-28 21:34:01 +03:00
|
|
|
clearInterval(pluginData.state.clearRecentNicknameChangesInterval);
|
|
|
|
|
2020-07-27 20:42:10 +03:00
|
|
|
pluginData.state.savedMessages.events.off("create", pluginData.state.onMessageCreateFn);
|
|
|
|
pluginData.state.savedMessages.events.off("update", pluginData.state.onMessageUpdateFn);
|
|
|
|
},
|
|
|
|
});
|