import { hasManagerPermissions } from "@/utils/discord/permissions"; import type { Client, Message, Snowflake } from "discord.js"; type UserId = Snowflake; type Pending = { channels: Set; timer: NodeJS.Timeout; }; const pendingReports = new Map(); const cooldowns = new Map(); async function getLogChannel(client: Client) { return client.channels.fetch("1477508937287864431"); } export async function handleMessage(client: Client, message: Message) { if (message.author.bot || !message.guildId) return; handleSpamLinks(client, message); } async function handleSpamLinks(client: Client, message: Message) { if (message.author.bot || !message.guildId || !message.member) return; if (await hasManagerPermissions(message.member)) return; if (message.channelId === "1378529224192819250") return; const { content } = message; const blacklisted = [ "discord.gg/", "discordapp.com/invite/", "discord.com/invite/", ]; if (!blacklisted.some((link) => content.includes(link))) return; if (message.channel.isSendable()) { message.reply( `<@${message.author.id}> your message contained an invite link and was deleted to prevent phishing attempts.`, ); } const logChannel = await getLogChannel(client); if (cooldowns.has(message.author.id)) { if (message.deletable) message.delete(); return; } const existing = pendingReports.get(message.author.id); if (!existing) { if (logChannel?.isSendable()) { await message.forward(logChannel); logChannel.send( `Deleted a message from <@${message.author.id}> in <#${message.channelId}> containing a potential phishing link.`, ); message.delete(); } const timer = setTimeout( () => flushReport(client, message.author.id), 30_000, ); pendingReports.set(message.author.id, { channels: new Set([message.channelId]), timer, }); return; } existing.channels.add(message.channelId); clearTimeout(existing.timer); existing.timer = setTimeout( () => flushReport(client, message.author.id), 30_000, ); } async function flushReport(client: Client, authorId: UserId) { 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(", "); await logChannel.send( `<@${authorId}> posted invite/phishing links across ${channels.length} channel(s): ${channelMentions}`, ); const cooldownTimer = setTimeout( () => cooldowns.delete(authorId), 5 * 60 * 1000, ); cooldowns.set(authorId, cooldownTimer); }