src/automod/index.ts (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
import { hasManagerPermissions } from "@/utils/discord/permissions";
import type { Client, Message, Snowflake } from "discord.js";
type Pending = {
channels: Set<Snowflake>;
timer: NodeJS.Timeout;
};
const pendingReports = new Map<Snowflake, Pending>();
const cooldowns = new Map<Snowflake, NodeJS.Timeout>();
async function getLogChannel(client: Client) {
return client.channels.fetch("1478940790112915486");
}
type AutomodResult = { delete: true } | null;
type AutomodFunction = (
client: Client,
message: Message,
) => Promise<AutomodResult>;
export async function handleMessage(client: Client, message: Message) {
if (message.author.bot || !message.guildId) return;
const automodFunctions: AutomodFunction[] = [handleSpamLinks];
for (const func of automodFunctions) {
const result = await func(client, message);
if (result?.delete) {
await message.delete().catch(() => null);
break;
}
}
}
async function handleSpamLinks(
client: Client,
message: Message,
): Promise<AutomodResult> {
if (message.author.bot || !message.guildId || !message.member) return null;
if (await hasManagerPermissions(message.member)) return null;
if (message.channelId === "1478940790112915486") return null;
const { content } = message;
const blacklisted = [
"discord.gg/",
"discordapp.com/invite/",
"discord.com/invite/",
];
if (!blacklisted.some((link) => content.includes(link))) return null;
if (cooldowns.has(message.author.id)) {
return { delete: true };
}
const existing = pendingReports.get(message.author.id);
if (!existing) {
const content = [
`<@${message.author.id}>, your message contained an invite link and was deleted to prevent phishing attempts.`,
"Keep in mind, we don't allow advertising other servers here.",
];
await message.reply(content.join(" "));
const logChannel = await getLogChannel(client);
if (logChannel?.isSendable()) {
await message.forward(logChannel);
logChannel.send(
`Deleted a message from <@${message.author.id}> in <#${message.channelId}> containing a potential phishing link.`,
);
}
const timer = setTimeout(
() => flushReport(client, message.author.id),
30_000,
);
pendingReports.set(message.author.id, {
channels: new Set([message.channelId]),
timer,
});
return { delete: true };
}
existing.channels.add(message.channelId);
clearTimeout(existing.timer);
existing.timer = setTimeout(
() => flushReport(client, message.author.id),
30_000,
);
return { delete: true };
}
async function flushReport(client: Client, authorId: Snowflake) {
const pending = pendingReports.get(authorId);
if (!pending) return;
pendingReports.delete(authorId);
clearTimeout(pending.timer);
const logChannel = await getLogChannel(client);
if (!logChannel?.isSendable()) return;
const channels = Array.from(pending.channels);
const channelMentions = channels.map((c) => `<#${c}>`).join(", ");
logChannel.send(
`<@${authorId}> posted links in channels: ${channelMentions}`,
);
const cooldownTimer = setTimeout(
() => cooldowns.delete(authorId),
5 * 60 * 1000,
);
cooldowns.set(authorId, cooldownTimer);
}
|