From 6a45ce67faf3bd599e9b2cbe528b7d7598b24556 Mon Sep 17 00:00:00 2001 From: Hiroyuki Date: Sat, 4 Sep 2021 12:18:33 -0400 Subject: [PATCH] feat(automod): MIME type trigger (#247) --- backend/src/plugins/Automod/AutomodPlugin.ts | 15 ++++ .../Automod/triggers/availableTriggers.ts | 3 + .../plugins/Automod/triggers/matchMimeType.ts | 79 +++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 backend/src/plugins/Automod/triggers/matchMimeType.ts diff --git a/backend/src/plugins/Automod/AutomodPlugin.ts b/backend/src/plugins/Automod/AutomodPlugin.ts index 80d160e3..60f55296 100644 --- a/backend/src/plugins/Automod/AutomodPlugin.ts +++ b/backend/src/plugins/Automod/AutomodPlugin.ts @@ -114,6 +114,21 @@ const configPreprocessor: ConfigPreprocessorFn = options => { ]); } } + + if (triggerObj[triggerName].match_mime_type) { + const white = triggerObj[triggerName].match_mime_type.whitelist_enabled; + const black = triggerObj[triggerName].match_mime_type.blacklist_enabled; + + if (white && black) { + throw new StrictValidationError([ + `Cannot have both blacklist and whitelist enabled at rule <${rule.name}/match_mime_type>`, + ]); + } else if (!white && !black) { + throw new StrictValidationError([ + `Must have either blacklist or whitelist enabled at rule <${rule.name}/match_mime_type>`, + ]); + } + } } } } diff --git a/backend/src/plugins/Automod/triggers/availableTriggers.ts b/backend/src/plugins/Automod/triggers/availableTriggers.ts index e62e811d..22c63cd9 100644 --- a/backend/src/plugins/Automod/triggers/availableTriggers.ts +++ b/backend/src/plugins/Automod/triggers/availableTriggers.ts @@ -11,6 +11,7 @@ import { KickTrigger } from "./kick"; import { LineSpamTrigger } from "./lineSpam"; import { LinkSpamTrigger } from "./linkSpam"; import { MatchAttachmentTypeTrigger } from "./matchAttachmentType"; +import { MatchMimeTypeTrigger } from "./matchMimeType"; import { MatchInvitesTrigger } from "./matchInvites"; import { MatchLinksTrigger } from "./matchLinks"; import { MatchRegexTrigger } from "./matchRegex"; @@ -37,6 +38,7 @@ export const availableTriggers: Record match_invites: MatchInvitesTrigger, match_links: MatchLinksTrigger, match_attachment_type: MatchAttachmentTypeTrigger, + match_mime_type: MatchMimeTypeTrigger, member_join: MemberJoinTrigger, role_added: RoleAddedTrigger, role_removed: RoleRemovedTrigger, @@ -72,6 +74,7 @@ export const AvailableTriggers = t.type({ match_invites: MatchInvitesTrigger.configType, match_links: MatchLinksTrigger.configType, match_attachment_type: MatchAttachmentTypeTrigger.configType, + match_mime_type: MatchMimeTypeTrigger.configType, member_join: MemberJoinTrigger.configType, member_leave: MemberLeaveTrigger.configType, role_added: RoleAddedTrigger.configType, diff --git a/backend/src/plugins/Automod/triggers/matchMimeType.ts b/backend/src/plugins/Automod/triggers/matchMimeType.ts new file mode 100644 index 00000000..f38bb8fa --- /dev/null +++ b/backend/src/plugins/Automod/triggers/matchMimeType.ts @@ -0,0 +1,79 @@ +import { automodTrigger } from "../helpers"; +import * as t from "io-ts"; +import { asSingleLine, messageSummary, verboseChannelMention } from "../../../utils"; +import { GuildChannel, Util } from "discord.js"; + +interface MatchResultType { + matchedType: string; + mode: "blacklist" | "whitelist"; +} + +export const MatchMimeTypeTrigger = automodTrigger()({ + configType: t.type({ + mime_type_blacklist: t.array(t.string), + blacklist_enabled: t.boolean, + mime_type_whitelist: t.array(t.string), + whitelist_enabled: t.boolean, + }), + + defaultConfig: { + mime_type_blacklist: [], + blacklist_enabled: false, + mime_type_whitelist: [], + whitelist_enabled: false, + }, + + async match({ context, triggerConfig: trigger }) { + if (!context.message) return; + + const { attachments } = context.message.data; + if (!attachments) return null; + + for (const attachment of attachments) { + const { contentType } = attachment; + + const blacklist = trigger.blacklist_enabled + ? (trigger.mime_type_blacklist ?? []).map(_t => _t.toLowerCase()) + : null; + + if (contentType && blacklist?.includes(contentType)) { + return { + extra: { + matchedType: contentType, + mode: "blacklist", + }, + }; + } + + const whitelist = trigger.whitelist_enabled + ? (trigger.mime_type_whitelist ?? []).map(_t => _t.toLowerCase()) + : null; + + if (whitelist && (!contentType || !whitelist.includes(contentType))) { + return { + extra: { + matchedType: contentType || "", + mode: "whitelist", + }, + }; + } + + return null; + } + }, + + renderMatchInformation({ pluginData, contexts, matchResult }) { + const { message } = contexts[0]; + const channel = pluginData.guild.channels.resolve(message!.channel_id); + const prettyChannel = verboseChannelMention(channel as GuildChannel); + const { matchedType, mode } = matchResult.extra; + + return ( + asSingleLine(` + Matched MIME type \`${Util.escapeInlineCode(matchedType)}\` + (${mode === "blacklist" ? "blacklisted" : "not in whitelist"}) + in message (\`${message!.id}\`) in ${prettyChannel} + `) + messageSummary(message!) + ); + }, +});