import client from "../client"; import { AuditLogEvent, Events, GuildAuditLogsEntry, PermissionFlagsBits, User } from "discord.js"; import { getGuildSetting } from "../tools/data"; import { Badword, database } from "../data"; import { IsNull } from "typeorm"; import getDefaultEmbed, { getFailedEmbed, getUserReportEmbed } from "../tools/defaultEmbeds"; import { getGuildChannel } from "../tools/discord"; import { Color, Emoji } from "../tools/design"; client.on(Events.ChannelUpdate, async (oldChannel, newChannel) => { if (oldChannel.isDMBased() || newChannel.isDMBased()) return; const name = newChannel.name.toLowerCase(); const guild = oldChannel.guild; const settings = await getGuildSetting(guild.id); const globalBlocklist = await database.getRepository(Badword).find({ where: { guildID: IsNull() } }); const localBlocklist = await database.getRepository(Badword).find({ where: { guildID: guild.id } }); const blocklist = [...globalBlocklist, ...localBlocklist]; let found: string | null = null; for (let i = 0; i < blocklist.length; i++) { const word = blocklist[i]; if (!word) continue; if (!name.includes(word.value)) continue; found = word.value; break; } if (found === null) return; let responsibleUser: User | null; try { const clientMember = await guild.members.fetchMe(); const canSeeAuditLog = clientMember.permissions.has(PermissionFlagsBits.ViewAuditLog); const auditLogs = canSeeAuditLog ? await guild.fetchAuditLogs({ type: AuditLogEvent.ChannelUpdate, limit: 50 }) : undefined; const change = auditLogs?.entries.filter((entry) => { if (entry.target.id !== newChannel.id) return false; return entry.changes.filter((change) => { return change.key === "name" && change.new === newChannel.name; }).length > 0; }).reduce>((unknown, curr) => { if (!unknown) return curr; const prev = unknown as GuildAuditLogsEntry return curr.createdTimestamp > prev.createdTimestamp ? curr : prev; }, null); responsibleUser = change?.executor || null; } catch (error) { responsibleUser = null; } const logChannel = settings.notificationChannelID ? await getGuildChannel(guild.id, settings.notificationChannelID) : null; try { if (!newChannel.deletable) throw new Error("Missing permissions to delete channel"); await newChannel.delete("[Automated] Detected blocked word in channel name"); } catch (error) { if (!logChannel || !logChannel.isTextBased()) return; const embed = getFailedEmbed(); embed.setDescription(`Couldn't delete <#${newChannel.id}> (${newChannel.id}): ${error instanceof Error ? error.message : error}`); embed.addFields({ name: "Detected banned word:", value: `||${found}||` }, { name: "Channel renamed by:", value: responsibleUser ? `${responsibleUser.tag} (${responsibleUser.id})` : "`Couldn't detect responsible user :(`" }); logChannel.send({ embeds: [embed] }).catch(() => {}); return; } if (responsibleUser) { const embed = getUserReportEmbed(guild.name, newChannel.name); responsibleUser.send({ embeds: [embed] }).catch(() => {}); } if (!logChannel || !logChannel.isTextBased()) return; const embed = getDefaultEmbed(); embed.setTitle(`${Emoji.SECURITY_CHALLENGE_FAILED} Blocked word detected`); embed.setDescription(`||#${newChannel.name}|| (${newChannel.id}) has been deleted because its name contained a blocked word.`); embed.setColor(Color.WARNING_YELLOW); embed.addFields({ name: "Detected banned word:", value: `||${found}||`, inline: true }, { name: "Channel renamed by:", value: responsibleUser ? `${responsibleUser.tag} (${responsibleUser.id})` : "`Couldn't detect responsible user :(`" }); logChannel.send({ embeds: [embed] }).catch(() => {}); });