blob: 4c85052a22559ffd5e76b83545ae6b7b49367e35 [file] [log] [blame]
PineaFan752af462022-12-31 21:59:38 +00001import type { NucleusClient } from "../utils/client.js";
Skyler Grey11236ba2022-08-08 21:13:33 +01002import { LinkCheck, MalwareCheck, NSFWCheck, SizeCheck, TestString, TestImage } from "../reflex/scanners.js";
pineafan63fc5e22022-08-04 22:04:10 +01003import logAttachment from "../premium/attachmentLogs.js";
PineaFan0d06edc2023-01-17 22:10:31 +00004import { messageException } from "../utils/createTemporaryStorage.js";
pineafan63fc5e22022-08-04 22:04:10 +01005import getEmojiByName from "../utils/getEmojiByName.js";
6import client from "../utils/client.js";
pineafan0f5cc782022-08-12 21:55:42 +01007import { callback as statsChannelUpdate } from "../reflex/statsChannelUpdate.js";
Skyler Grey3331c9f2023-03-05 07:34:15 +00008import { ChannelType, Message, ThreadChannel } from "discord.js";
TheCodedProfb7a7b992023-03-05 16:11:59 -05009import singleNotify from "../utils/singleNotify.js";
pineafan813bdf42022-07-24 10:39:10 +010010
pineafan63fc5e22022-08-04 22:04:10 +010011export const event = "messageCreate";
pineafan813bdf42022-07-24 10:39:10 +010012
PineaFan752af462022-12-31 21:59:38 +000013export async function callback(_client: NucleusClient, message: Message) {
Skyler Grey75ea9172022-08-06 10:22:23 +010014 if (!message.guild) return;
PineappleFan13892c62023-03-05 07:00:07 +000015 const config = await client.memory.readGuildInfo(message.guild.id);
Skyler9f5fca82023-03-05 09:12:03 +000016
Skyler Greyda16adf2023-03-05 10:22:12 +000017 if (
18 config.autoPublish.enabled &&
19 config.autoPublish.channels.includes(message.channel.id) &&
20 message.channel.type === ChannelType.GuildAnnouncement &&
21 message.reference === null
Skyler9f5fca82023-03-05 09:12:03 +000022 ) {
Skyler Grey67691762023-03-06 09:58:19 +000023 if (message.channel.permissionsFor(message.guild.members.me!)!.has("ManageMessages")) {
TheCodedProfb7a7b992023-03-05 16:11:59 -050024 await message.crosspost();
25 } else {
pineafanfa445992023-03-06 16:21:51 +000026 singleNotify(`Nucleus does not have Manage Messages in <#${message.channel.id}>`, message.guild.id, true);
TheCodedProfb7a7b992023-03-05 16:11:59 -050027 }
PineappleFan13892c62023-03-05 07:00:07 +000028 }
29
pineafan63fc5e22022-08-04 22:04:10 +010030 if (message.author.bot) return;
PineaFan538d3752023-01-12 21:48:23 +000031 if (message.channel.isDMBased()) return;
Skyler Grey75ea9172022-08-06 10:22:23 +010032 try {
pineafan0f5cc782022-08-12 21:55:42 +010033 await statsChannelUpdate(client, await message.guild.members.fetch(message.author.id));
Skyler Grey75ea9172022-08-06 10:22:23 +010034 } catch (e) {
35 console.log(e);
36 }
pineafan813bdf42022-07-24 10:39:10 +010037
TheCodedProf6ec331b2023-02-20 12:13:06 -050038 const { log, isLogging, NucleusColors, entry, renderUser, renderDelta, renderChannel } = client.logger;
pineafan813bdf42022-07-24 10:39:10 +010039
pineafan63fc5e22022-08-04 22:04:10 +010040 const fileNames = await logAttachment(message);
pineafan813bdf42022-07-24 10:39:10 +010041
pineafan63fc5e22022-08-04 22:04:10 +010042 const content = message.content.toLowerCase() || "";
Skyler Greyda16adf2023-03-05 10:22:12 +000043 if (config.filters.clean.channels.includes(message.channel.id)) {
44 const memberRoles = message.member!.roles.cache.map((role) => role.id);
45 const roleAllow = config.filters.clean.allowed.roles.some((role) => memberRoles.includes(role));
TheCodedProff8ef7942023-03-03 15:32:32 -050046 const userAllow = config.filters.clean.allowed.users.includes(message.author.id);
Skyler Greyda16adf2023-03-05 10:22:12 +000047 if (!roleAllow && !userAllow) return await message.delete();
TheCodedProfad0b8202023-02-14 14:27:09 -050048 }
TheCodedProfbaee2c12023-02-18 16:11:06 -050049
pineafan63fc5e22022-08-04 22:04:10 +010050 const filter = getEmojiByName("ICONS.FILTER");
51 let attachmentJump = "";
Skyler Grey75ea9172022-08-06 10:22:23 +010052 if (config.logging.attachments.saved[message.channel.id + message.id]) {
Skyler Grey11236ba2022-08-08 21:13:33 +010053 attachmentJump = ` [[View attachments]](${config.logging.attachments.saved[message.channel.id + message.id]})`;
Skyler Grey75ea9172022-08-06 10:22:23 +010054 }
pineafan63fc5e22022-08-04 22:04:10 +010055 const list = {
pineafan813bdf42022-07-24 10:39:10 +010056 messageId: entry(message.id, `\`${message.id}\``),
57 sentBy: entry(message.author.id, renderUser(message.author)),
58 sentIn: entry(message.channel.id, renderChannel(message.channel)),
TheCodedProf6ec331b2023-02-20 12:13:06 -050059 deleted: entry(Date.now(), renderDelta(Date.now())),
pineafan813bdf42022-07-24 10:39:10 +010060 mentions: message.mentions.users.size,
Skyler Grey11236ba2022-08-08 21:13:33 +010061 attachments: entry(message.attachments.size, message.attachments.size + attachmentJump),
pineafan813bdf42022-07-24 10:39:10 +010062 repliedTo: entry(
PineaFan538d3752023-01-12 21:48:23 +000063 (message.reference ? message.reference.messageId : null) ?? null,
Skyler Grey75ea9172022-08-06 10:22:23 +010064 message.reference
65 ? `[[Jump to message]](https://discord.com/channels/${message.guild.id}/${message.channel.id}/${message.reference.messageId})`
66 : "None"
pineafan813bdf42022-07-24 10:39:10 +010067 )
pineafan63fc5e22022-08-04 22:04:10 +010068 };
pineafan813bdf42022-07-24 10:39:10 +010069
70 if (config.filters.invite.enabled) {
Skyler Grey11236ba2022-08-08 21:13:33 +010071 if (!config.filters.invite.allowed.channels.includes(message.channel.id)) {
72 if (/(?:https?:\/\/)?discord(?:app)?\.(?:com\/invite|gg)\/[a-zA-Z0-9]+\/?/.test(content)) {
PineaFan0d06edc2023-01-17 22:10:31 +000073 messageException(message.guild.id, message.channel.id, message.id);
pineafan813bdf42022-07-24 10:39:10 +010074 message.delete();
pineafan63fc5e22022-08-04 22:04:10 +010075 const data = {
pineafan813bdf42022-07-24 10:39:10 +010076 meta: {
pineafan63fc5e22022-08-04 22:04:10 +010077 type: "messageDelete",
pineafanfa445992023-03-06 16:21:51 +000078 displayName: "Message Deleted",
pineafan63fc5e22022-08-04 22:04:10 +010079 calculateType: "autoModeratorDeleted",
pineafan813bdf42022-07-24 10:39:10 +010080 color: NucleusColors.red,
pineafan63fc5e22022-08-04 22:04:10 +010081 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -050082 timestamp: Date.now()
pineafan813bdf42022-07-24 10:39:10 +010083 },
84 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +010085 start:
86 filter +
87 " Contained invite\n\n" +
Skyler Grey11236ba2022-08-08 21:13:33 +010088 (content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
pineafan813bdf42022-07-24 10:39:10 +010089 },
90 list: list,
91 hidden: {
92 guild: message.channel.guild.id
93 }
pineafan63fc5e22022-08-04 22:04:10 +010094 };
pineafan813bdf42022-07-24 10:39:10 +010095 return log(data);
96 }
97 }
98 }
99
100 if (fileNames.files.length > 0) {
pineafan63fc5e22022-08-04 22:04:10 +0100101 for (const element of fileNames.files) {
pineafan63fc5e22022-08-04 22:04:10 +0100102 const url = element.url ? element.url : element.local;
Skyler Greyda16adf2023-03-05 10:22:12 +0000103 if (
104 /\.(j(pe?g|fif)|a?png|gifv?|w(eb[mp]|av)|mp([34]|eg-\d)|ogg|avi|h\.26(4|5)|cda)$/.test(
105 url.toLowerCase()
106 )
107 ) {
TheCodedProf16113672023-02-03 16:05:23 -0500108 // jpg|jpeg|png|apng|gif|gifv|webm|webp|mp4|wav|mp3|ogg|jfif|MPEG-#|avi|h.264|h.265
Skyler Grey75ea9172022-08-06 10:22:23 +0100109 if (
Skyler Greyc634e2b2022-08-06 17:50:48 +0100110 config.filters.images.NSFW &&
Skyler Grey11236ba2022-08-08 21:13:33 +0100111 !(message.channel instanceof ThreadChannel ? message.channel.parent?.nsfw : message.channel.nsfw)
Skyler Grey75ea9172022-08-06 10:22:23 +0100112 ) {
Skyler Greyc634e2b2022-08-06 17:50:48 +0100113 if (await NSFWCheck(url)) {
PineaFan0d06edc2023-01-17 22:10:31 +0000114 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100115 await message.delete();
116 const data = {
pineafan813bdf42022-07-24 10:39:10 +0100117 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100118 type: "messageDelete",
119 displayName: "Message Deleted",
120 calculateType: "autoModeratorDeleted",
pineafan813bdf42022-07-24 10:39:10 +0100121 color: NucleusColors.red,
pineafan63fc5e22022-08-04 22:04:10 +0100122 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500123 timestamp: Date.now()
pineafan813bdf42022-07-24 10:39:10 +0100124 },
125 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100126 start:
127 filter +
Skyler Greyc634e2b2022-08-06 17:50:48 +0100128 " Image detected as NSFW\n\n" +
Skyler Grey75ea9172022-08-06 10:22:23 +0100129 (content
130 ? `**Message:**\n\`\`\`${content}\`\`\``
131 : "**Message:** *Message had no content*")
pineafan813bdf42022-07-24 10:39:10 +0100132 },
133 list: list,
134 hidden: {
135 guild: message.channel.guild.id
136 }
pineafan63fc5e22022-08-04 22:04:10 +0100137 };
pineafan813bdf42022-07-24 10:39:10 +0100138 return log(data);
139 }
140 }
Skyler Greyc634e2b2022-08-06 17:50:48 +0100141 if (config.filters.wordFilter.enabled) {
142 const text = await TestImage(url);
143 const check = TestString(
144 text ?? "",
145 config.filters.wordFilter.words.loose,
146 config.filters.wordFilter.words.strict
147 );
148 if (check !== null) {
PineaFan0d06edc2023-01-17 22:10:31 +0000149 messageException(message.guild.id, message.channel.id, message.id);
Skyler Greyc634e2b2022-08-06 17:50:48 +0100150 await message.delete();
151 const data = {
152 meta: {
153 type: "messageDelete",
154 displayName: "Message Deleted",
155 calculateType: "autoModeratorDeleted",
156 color: NucleusColors.red,
157 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500158 timestamp: Date.now()
Skyler Greyc634e2b2022-08-06 17:50:48 +0100159 },
160 separate: {
161 start:
162 filter +
163 " Image contained filtered word\n\n" +
164 (content
165 ? `**Message:**\n\`\`\`${content}\`\`\``
166 : "**Message:** *Message had no content*")
167 },
168 list: list,
169 hidden: {
170 guild: message.channel.guild.id
171 }
172 };
173 return log(data);
174 }
175 }
176 if (config.filters.images.size) {
177 if (url.match(/\.+(webp|png|jpg)$/gi)) {
178 if (!(await SizeCheck(element))) {
PineaFan0d06edc2023-01-17 22:10:31 +0000179 messageException(message.guild.id, message.channel.id, message.id);
Skyler Greyc634e2b2022-08-06 17:50:48 +0100180 await message.delete();
181 const data = {
182 meta: {
183 type: "messageDelete",
184 displayName: "Message Deleted",
185 calculateType: "autoModeratorDeleted",
186 color: NucleusColors.red,
187 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500188 timestamp: Date.now()
Skyler Greyc634e2b2022-08-06 17:50:48 +0100189 },
190 separate: {
191 start:
192 filter +
193 " Image was too small\n\n" +
194 (content
195 ? `**Message:**\n\`\`\`${content}\`\`\``
196 : "**Message:** *Message had no content*")
197 },
198 list: list,
199 hidden: {
200 guild: message.channel.guild.id
201 }
202 };
203 return log(data);
204 }
205 }
206 }
207 }
208 if (config.filters.malware) {
209 if (!(await MalwareCheck(url))) {
PineaFan0d06edc2023-01-17 22:10:31 +0000210 messageException(message.guild.id, message.channel.id, message.id);
Skyler Greyc634e2b2022-08-06 17:50:48 +0100211 await message.delete();
212 const data = {
213 meta: {
214 type: "messageDelete",
215 displayName: "Message Deleted",
216 calculateType: "autoModeratorDeleted",
217 color: NucleusColors.red,
218 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500219 timestamp: Date.now()
Skyler Greyc634e2b2022-08-06 17:50:48 +0100220 },
221 separate: {
222 start:
223 filter +
224 " File detected as malware\n\n" +
225 (content
226 ? `**Message:**\n\`\`\`${content}\`\`\``
227 : "**Message:** *Message had no content*")
228 },
229 list: list,
230 hidden: {
231 guild: message.channel.guild.id
232 }
233 };
234 return log(data);
235 }
pineafan813bdf42022-07-24 10:39:10 +0100236 }
pineafan63fc5e22022-08-04 22:04:10 +0100237 }
pineafan813bdf42022-07-24 10:39:10 +0100238 }
pineafan813bdf42022-07-24 10:39:10 +0100239
pineafan63fc5e22022-08-04 22:04:10 +0100240 const linkDetectionTypes = await LinkCheck(message);
pineafan813bdf42022-07-24 10:39:10 +0100241 if (linkDetectionTypes.length > 0) {
PineaFan0d06edc2023-01-17 22:10:31 +0000242 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100243 await message.delete();
244 const data = {
pineafan813bdf42022-07-24 10:39:10 +0100245 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100246 type: "messageDelete",
247 displayName: "Message Deleted",
248 calculateType: "autoModeratorDeleted",
pineafan813bdf42022-07-24 10:39:10 +0100249 color: NucleusColors.red,
pineafan63fc5e22022-08-04 22:04:10 +0100250 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500251 timestamp: Date.now()
pineafan813bdf42022-07-24 10:39:10 +0100252 },
253 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100254 start:
255 filter +
256 ` Link filtered as ${linkDetectionTypes[0]?.toLowerCase()}\n\n` +
Skyler Grey11236ba2022-08-08 21:13:33 +0100257 (content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
pineafan813bdf42022-07-24 10:39:10 +0100258 },
259 list: list,
260 hidden: {
261 guild: message.channel.guild.id
262 }
pineafan63fc5e22022-08-04 22:04:10 +0100263 };
pineafan813bdf42022-07-24 10:39:10 +0100264 return log(data);
265 }
pineafane23c4ec2022-07-27 21:56:27 +0100266
pineafan813bdf42022-07-24 10:39:10 +0100267 if (config.filters.wordFilter.enabled) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100268 const check = TestString(
269 content,
270 config.filters.wordFilter.words.loose,
271 config.filters.wordFilter.words.strict
272 );
273 if (check !== null) {
PineaFan0d06edc2023-01-17 22:10:31 +0000274 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100275 await message.delete();
276 const data = {
pineafan813bdf42022-07-24 10:39:10 +0100277 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100278 type: "messageDelete",
279 displayName: "Message Deleted",
280 calculateType: "autoModeratorDeleted",
pineafan813bdf42022-07-24 10:39:10 +0100281 color: NucleusColors.red,
pineafan63fc5e22022-08-04 22:04:10 +0100282 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500283 timestamp: Date.now()
pineafan813bdf42022-07-24 10:39:10 +0100284 },
285 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100286 start:
287 filter +
288 " Message contained filtered word\n\n" +
Skyler Grey11236ba2022-08-08 21:13:33 +0100289 (content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
pineafan813bdf42022-07-24 10:39:10 +0100290 },
291 list: list,
292 hidden: {
293 guild: message.channel.guild.id
294 }
pineafan63fc5e22022-08-04 22:04:10 +0100295 };
pineafan813bdf42022-07-24 10:39:10 +0100296 return log(data);
297 }
298 }
299
pineafane23c4ec2022-07-27 21:56:27 +0100300 if (config.filters.pings.everyone && message.mentions.everyone) {
Skyler Greyda16adf2023-03-05 10:22:12 +0000301 if (!(await isLogging(message.guild.id, "messageMassPing"))) return;
pineafan63fc5e22022-08-04 22:04:10 +0100302 const data = {
pineafane23c4ec2022-07-27 21:56:27 +0100303 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100304 type: "everyonePing",
305 displayName: "Everyone Pinged",
306 calculateType: "messageMassPing",
pineafane23c4ec2022-07-27 21:56:27 +0100307 color: NucleusColors.yellow,
pineafan63fc5e22022-08-04 22:04:10 +0100308 emoji: "MESSAGE.PING.EVERYONE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500309 timestamp: Date.now()
pineafane23c4ec2022-07-27 21:56:27 +0100310 },
311 separate: {
Skyler Grey11236ba2022-08-08 21:13:33 +0100312 start: content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*"
pineafane23c4ec2022-07-27 21:56:27 +0100313 },
314 list: list,
315 hidden: {
316 guild: message.channel.guild.id
pineafan813bdf42022-07-24 10:39:10 +0100317 }
pineafan63fc5e22022-08-04 22:04:10 +0100318 };
pineafane23c4ec2022-07-27 21:56:27 +0100319 return log(data);
320 }
321 if (config.filters.pings.roles) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100322 for (const roleId in message.mentions.roles) {
pineafan63fc5e22022-08-04 22:04:10 +0100323 if (!config.filters.pings.allowed.roles.includes(roleId)) {
PineaFan0d06edc2023-01-17 22:10:31 +0000324 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100325 await message.delete();
Skyler Greyda16adf2023-03-05 10:22:12 +0000326 if (!(await isLogging(message.guild.id, "messageMassPing"))) return;
pineafan63fc5e22022-08-04 22:04:10 +0100327 const data = {
pineafane23c4ec2022-07-27 21:56:27 +0100328 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100329 type: "rolePing",
330 displayName: "Role Pinged",
331 calculateType: "messageMassPing",
pineafane23c4ec2022-07-27 21:56:27 +0100332 color: NucleusColors.yellow,
pineafan63fc5e22022-08-04 22:04:10 +0100333 emoji: "MESSAGE.PING.ROLE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500334 timestamp: Date.now()
pineafane23c4ec2022-07-27 21:56:27 +0100335 },
336 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100337 start: content
338 ? `**Message:**\n\`\`\`${content}\`\`\``
339 : "**Message:** *Message had no content*"
pineafane23c4ec2022-07-27 21:56:27 +0100340 },
341 list: list,
342 hidden: {
343 guild: message.channel.guild.id
pineafan813bdf42022-07-24 10:39:10 +0100344 }
pineafan63fc5e22022-08-04 22:04:10 +0100345 };
pineafane23c4ec2022-07-27 21:56:27 +0100346 return log(data);
pineafan813bdf42022-07-24 10:39:10 +0100347 }
348 }
pineafane23c4ec2022-07-27 21:56:27 +0100349 }
Skyler Grey11236ba2022-08-08 21:13:33 +0100350 if (message.mentions.users.size >= config.filters.pings.mass && config.filters.pings.mass) {
PineaFan0d06edc2023-01-17 22:10:31 +0000351 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100352 await message.delete();
Skyler Greyda16adf2023-03-05 10:22:12 +0000353 if (!(await isLogging(message.guild.id, "messageMassPing"))) return;
pineafan63fc5e22022-08-04 22:04:10 +0100354 const data = {
pineafane23c4ec2022-07-27 21:56:27 +0100355 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100356 type: "massPing",
357 displayName: "Mass Ping",
358 calculateType: "messageMassPing",
pineafane23c4ec2022-07-27 21:56:27 +0100359 color: NucleusColors.yellow,
pineafan63fc5e22022-08-04 22:04:10 +0100360 emoji: "MESSAGE.PING.MASS",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500361 timestamp: Date.now()
pineafane23c4ec2022-07-27 21:56:27 +0100362 },
363 separate: {
Skyler Grey11236ba2022-08-08 21:13:33 +0100364 start: content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*"
pineafane23c4ec2022-07-27 21:56:27 +0100365 },
366 list: list,
367 hidden: {
368 guild: message.channel.guild.id
pineafan813bdf42022-07-24 10:39:10 +0100369 }
pineafan63fc5e22022-08-04 22:04:10 +0100370 };
pineafane23c4ec2022-07-27 21:56:27 +0100371 return log(data);
pineafan813bdf42022-07-24 10:39:10 +0100372 }
373}