blob: 798678de0aa47580d130751a84e59cfd4bf8ad61 [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";
TheCodedProfc7e8ef12023-04-22 22:28:11 -04008import { ChannelType, GuildMember, 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
TheCodedProfc7e8ef12023-04-22 22:28:11 -040013function checkUserForExceptions(user: GuildMember, exceptions: { roles: string[]; users: string[] }) {
14 if (exceptions.users.includes(user.id)) return true;
15 for (const role of user.roles.cache.values()) {
16 if (exceptions.roles.includes(role.id)) return true;
17 }
18 return false;
19}
20
PineaFan752af462022-12-31 21:59:38 +000021export async function callback(_client: NucleusClient, message: Message) {
Skyler Grey75ea9172022-08-06 10:22:23 +010022 if (!message.guild) return;
PineappleFan13892c62023-03-05 07:00:07 +000023 const config = await client.memory.readGuildInfo(message.guild.id);
Skyler9f5fca82023-03-05 09:12:03 +000024
Skyler Greyda16adf2023-03-05 10:22:12 +000025 if (
26 config.autoPublish.enabled &&
27 config.autoPublish.channels.includes(message.channel.id) &&
28 message.channel.type === ChannelType.GuildAnnouncement &&
29 message.reference === null
Skyler9f5fca82023-03-05 09:12:03 +000030 ) {
Skyler Grey67691762023-03-06 09:58:19 +000031 if (message.channel.permissionsFor(message.guild.members.me!)!.has("ManageMessages")) {
TheCodedProfb7a7b992023-03-05 16:11:59 -050032 await message.crosspost();
33 } else {
Skyler Greyf4f21c42023-03-08 14:36:29 +000034 await singleNotify(
35 `Nucleus does not have Manage Messages in <#${message.channel.id}>`,
36 message.guild.id,
37 true
38 );
TheCodedProfb7a7b992023-03-05 16:11:59 -050039 }
PineappleFan13892c62023-03-05 07:00:07 +000040 }
41
pineafan63fc5e22022-08-04 22:04:10 +010042 if (message.author.bot) return;
PineaFan538d3752023-01-12 21:48:23 +000043 if (message.channel.isDMBased()) return;
Skyler Grey75ea9172022-08-06 10:22:23 +010044 try {
pineafan6de4da52023-03-07 20:43:44 +000045 await statsChannelUpdate((await message.guild.members.fetch(message.author.id)).user, message.guild);
Skyler Grey75ea9172022-08-06 10:22:23 +010046 } catch (e) {
47 console.log(e);
48 }
pineafan813bdf42022-07-24 10:39:10 +010049
TheCodedProf6ec331b2023-02-20 12:13:06 -050050 const { log, isLogging, NucleusColors, entry, renderUser, renderDelta, renderChannel } = client.logger;
pineafan813bdf42022-07-24 10:39:10 +010051
pineafan63fc5e22022-08-04 22:04:10 +010052 const fileNames = await logAttachment(message);
pineafan813bdf42022-07-24 10:39:10 +010053
pineafan63fc5e22022-08-04 22:04:10 +010054 const content = message.content.toLowerCase() || "";
Skyler Greyda16adf2023-03-05 10:22:12 +000055 if (config.filters.clean.channels.includes(message.channel.id)) {
TheCodedProfc7e8ef12023-04-22 22:28:11 -040056 if (!checkUserForExceptions(message.member!, config.filters.clean.allowed)) return await message.delete();
TheCodedProfad0b8202023-02-14 14:27:09 -050057 }
TheCodedProfbaee2c12023-02-18 16:11:06 -050058
pineafan63fc5e22022-08-04 22:04:10 +010059 const filter = getEmojiByName("ICONS.FILTER");
60 let attachmentJump = "";
Skyler Grey75ea9172022-08-06 10:22:23 +010061 if (config.logging.attachments.saved[message.channel.id + message.id]) {
Skyler Grey11236ba2022-08-08 21:13:33 +010062 attachmentJump = ` [[View attachments]](${config.logging.attachments.saved[message.channel.id + message.id]})`;
Skyler Grey75ea9172022-08-06 10:22:23 +010063 }
pineafan63fc5e22022-08-04 22:04:10 +010064 const list = {
pineafan813bdf42022-07-24 10:39:10 +010065 messageId: entry(message.id, `\`${message.id}\``),
66 sentBy: entry(message.author.id, renderUser(message.author)),
67 sentIn: entry(message.channel.id, renderChannel(message.channel)),
TheCodedProf6ec331b2023-02-20 12:13:06 -050068 deleted: entry(Date.now(), renderDelta(Date.now())),
pineafan813bdf42022-07-24 10:39:10 +010069 mentions: message.mentions.users.size,
Skyler Grey11236ba2022-08-08 21:13:33 +010070 attachments: entry(message.attachments.size, message.attachments.size + attachmentJump),
pineafan813bdf42022-07-24 10:39:10 +010071 repliedTo: entry(
PineaFan538d3752023-01-12 21:48:23 +000072 (message.reference ? message.reference.messageId : null) ?? null,
Skyler Grey75ea9172022-08-06 10:22:23 +010073 message.reference
74 ? `[[Jump to message]](https://discord.com/channels/${message.guild.id}/${message.channel.id}/${message.reference.messageId})`
75 : "None"
pineafan813bdf42022-07-24 10:39:10 +010076 )
pineafan63fc5e22022-08-04 22:04:10 +010077 };
pineafan813bdf42022-07-24 10:39:10 +010078
79 if (config.filters.invite.enabled) {
TheCodedProfc7e8ef12023-04-22 22:28:11 -040080 if (
81 !config.filters.invite.allowed.channels.includes(message.channel.id) ||
82 !checkUserForExceptions(message.member!, config.filters.invite.allowed)
83 ) {
Skyler Grey11236ba2022-08-08 21:13:33 +010084 if (/(?:https?:\/\/)?discord(?:app)?\.(?:com\/invite|gg)\/[a-zA-Z0-9]+\/?/.test(content)) {
PineaFan0d06edc2023-01-17 22:10:31 +000085 messageException(message.guild.id, message.channel.id, message.id);
Skyler Greyf4f21c42023-03-08 14:36:29 +000086 await message.delete();
pineafan63fc5e22022-08-04 22:04:10 +010087 const data = {
pineafan813bdf42022-07-24 10:39:10 +010088 meta: {
pineafan63fc5e22022-08-04 22:04:10 +010089 type: "messageDelete",
pineafanfa445992023-03-06 16:21:51 +000090 displayName: "Message Deleted",
pineafan63fc5e22022-08-04 22:04:10 +010091 calculateType: "autoModeratorDeleted",
pineafan813bdf42022-07-24 10:39:10 +010092 color: NucleusColors.red,
pineafan63fc5e22022-08-04 22:04:10 +010093 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -050094 timestamp: Date.now()
pineafan813bdf42022-07-24 10:39:10 +010095 },
96 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +010097 start:
98 filter +
99 " Contained invite\n\n" +
Skyler Grey11236ba2022-08-08 21:13:33 +0100100 (content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
pineafan813bdf42022-07-24 10:39:10 +0100101 },
102 list: list,
103 hidden: {
104 guild: message.channel.guild.id
105 }
pineafan63fc5e22022-08-04 22:04:10 +0100106 };
pineafan813bdf42022-07-24 10:39:10 +0100107 return log(data);
108 }
109 }
110 }
111
112 if (fileNames.files.length > 0) {
pineafan63fc5e22022-08-04 22:04:10 +0100113 for (const element of fileNames.files) {
pineafan63fc5e22022-08-04 22:04:10 +0100114 const url = element.url ? element.url : element.local;
Skyler Greyda16adf2023-03-05 10:22:12 +0000115 if (
Skyler Grey0d885222023-03-08 21:46:37 +0000116 /\.(jpg|jpeg|png|apng|gif|gifv|webm|webp|mp4|wav|mp3|ogg|jfif|mpeg-\d|avi|h\.264|h\.265)$/.test(
Skyler Greyda16adf2023-03-05 10:22:12 +0000117 url.toLowerCase()
118 )
119 ) {
Skyler Grey0d885222023-03-08 21:46:37 +0000120 // j(pe?g|fif)|a?png|gifv?|w(eb[mp]|av)|mp([34]|eg-\d)|ogg|avi|h\.26(4|5)
121 // ^no
Skyler Grey75ea9172022-08-06 10:22:23 +0100122 if (
Skyler Greyc634e2b2022-08-06 17:50:48 +0100123 config.filters.images.NSFW &&
Skyler Grey0d885222023-03-08 21:46:37 +0000124 !(message.channel instanceof ThreadChannel ? message.channel.parent?.nsfw : message.channel.nsfw) &&
Skyler Grey74169642023-03-09 11:59:09 +0000125 (await NSFWCheck(element.url))
Skyler Grey75ea9172022-08-06 10:22:23 +0100126 ) {
Skyler Grey0d885222023-03-08 21:46:37 +0000127 messageException(message.guild.id, message.channel.id, message.id);
128 await message.delete();
129 const data = {
130 meta: {
131 type: "messageDelete",
132 displayName: "Message Deleted",
133 calculateType: "autoModeratorDeleted",
134 color: NucleusColors.red,
135 emoji: "MESSAGE.DELETE",
136 timestamp: Date.now()
137 },
138 separate: {
139 start:
140 filter +
141 " Image detected as NSFW\n\n" +
142 (content
143 ? `**Message:**\n\`\`\`${content}\`\`\``
144 : "**Message:** *Message had no content*")
145 },
146 list: list,
147 hidden: {
148 guild: message.channel.guild.id
149 }
150 };
151 return log(data);
pineafan813bdf42022-07-24 10:39:10 +0100152 }
Skyler Greyc634e2b2022-08-06 17:50:48 +0100153 if (config.filters.wordFilter.enabled) {
154 const text = await TestImage(url);
155 const check = TestString(
156 text ?? "",
157 config.filters.wordFilter.words.loose,
158 config.filters.wordFilter.words.strict
159 );
TheCodedProfc7e8ef12023-04-22 22:28:11 -0400160 if (
161 check !== null &&
162 (!checkUserForExceptions(message.member!, config.filters.wordFilter.allowed) ||
163 !config.filters.wordFilter.allowed.channels.includes(message.channel.id))
164 ) {
PineaFan0d06edc2023-01-17 22:10:31 +0000165 messageException(message.guild.id, message.channel.id, message.id);
Skyler Greyc634e2b2022-08-06 17:50:48 +0100166 await message.delete();
167 const data = {
168 meta: {
169 type: "messageDelete",
170 displayName: "Message Deleted",
171 calculateType: "autoModeratorDeleted",
172 color: NucleusColors.red,
173 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500174 timestamp: Date.now()
Skyler Greyc634e2b2022-08-06 17:50:48 +0100175 },
176 separate: {
177 start:
178 filter +
179 " Image contained filtered word\n\n" +
180 (content
181 ? `**Message:**\n\`\`\`${content}\`\`\``
182 : "**Message:** *Message had no content*")
183 },
184 list: list,
185 hidden: {
186 guild: message.channel.guild.id
187 }
188 };
189 return log(data);
190 }
191 }
192 if (config.filters.images.size) {
193 if (url.match(/\.+(webp|png|jpg)$/gi)) {
194 if (!(await SizeCheck(element))) {
PineaFan0d06edc2023-01-17 22:10:31 +0000195 messageException(message.guild.id, message.channel.id, message.id);
Skyler Greyc634e2b2022-08-06 17:50:48 +0100196 await message.delete();
197 const data = {
198 meta: {
199 type: "messageDelete",
200 displayName: "Message Deleted",
201 calculateType: "autoModeratorDeleted",
202 color: NucleusColors.red,
203 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500204 timestamp: Date.now()
Skyler Greyc634e2b2022-08-06 17:50:48 +0100205 },
206 separate: {
207 start:
208 filter +
209 " Image was too small\n\n" +
210 (content
211 ? `**Message:**\n\`\`\`${content}\`\`\``
212 : "**Message:** *Message had no content*")
213 },
214 list: list,
215 hidden: {
216 guild: message.channel.guild.id
217 }
218 };
219 return log(data);
220 }
221 }
222 }
223 }
Skyler Grey0d885222023-03-08 21:46:37 +0000224 if (config.filters.malware && (await MalwareCheck(url))) {
225 messageException(message.guild.id, message.channel.id, message.id);
226 await message.delete();
227 const data = {
228 meta: {
229 type: "messageDelete",
230 displayName: "Message Deleted",
231 calculateType: "autoModeratorDeleted",
232 color: NucleusColors.red,
233 emoji: "MESSAGE.DELETE",
234 timestamp: Date.now()
235 },
236 separate: {
237 start:
238 filter +
239 " File detected as malware\n\n" +
240 (content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
241 },
242 list: list,
243 hidden: {
244 guild: message.channel.guild.id
245 }
246 };
247 return log(data);
pineafan813bdf42022-07-24 10:39:10 +0100248 }
pineafan63fc5e22022-08-04 22:04:10 +0100249 }
pineafan813bdf42022-07-24 10:39:10 +0100250 }
pineafan813bdf42022-07-24 10:39:10 +0100251
pineafan63fc5e22022-08-04 22:04:10 +0100252 const linkDetectionTypes = await LinkCheck(message);
pineafan813bdf42022-07-24 10:39:10 +0100253 if (linkDetectionTypes.length > 0) {
PineaFan0d06edc2023-01-17 22:10:31 +0000254 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100255 await message.delete();
256 const data = {
pineafan813bdf42022-07-24 10:39:10 +0100257 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100258 type: "messageDelete",
259 displayName: "Message Deleted",
260 calculateType: "autoModeratorDeleted",
pineafan813bdf42022-07-24 10:39:10 +0100261 color: NucleusColors.red,
pineafan63fc5e22022-08-04 22:04:10 +0100262 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500263 timestamp: Date.now()
pineafan813bdf42022-07-24 10:39:10 +0100264 },
265 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100266 start:
267 filter +
268 ` Link filtered as ${linkDetectionTypes[0]?.toLowerCase()}\n\n` +
Skyler Grey11236ba2022-08-08 21:13:33 +0100269 (content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
pineafan813bdf42022-07-24 10:39:10 +0100270 },
271 list: list,
272 hidden: {
273 guild: message.channel.guild.id
274 }
pineafan63fc5e22022-08-04 22:04:10 +0100275 };
pineafan813bdf42022-07-24 10:39:10 +0100276 return log(data);
277 }
pineafane23c4ec2022-07-27 21:56:27 +0100278
TheCodedProfc7e8ef12023-04-22 22:28:11 -0400279 if (
280 config.filters.wordFilter.enabled &&
281 (!checkUserForExceptions(message.member!, config.filters.wordFilter.allowed) ||
282 !config.filters.wordFilter.allowed.channels.includes(message.channel.id))
283 ) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100284 const check = TestString(
285 content,
286 config.filters.wordFilter.words.loose,
TheCodedProf21d4b0f2023-04-22 21:02:51 -0400287 config.filters.wordFilter.words.strict
Skyler Grey75ea9172022-08-06 10:22:23 +0100288 );
289 if (check !== null) {
PineaFan0d06edc2023-01-17 22:10:31 +0000290 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100291 await message.delete();
292 const data = {
pineafan813bdf42022-07-24 10:39:10 +0100293 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100294 type: "messageDelete",
295 displayName: "Message Deleted",
296 calculateType: "autoModeratorDeleted",
pineafan813bdf42022-07-24 10:39:10 +0100297 color: NucleusColors.red,
pineafan63fc5e22022-08-04 22:04:10 +0100298 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500299 timestamp: Date.now()
pineafan813bdf42022-07-24 10:39:10 +0100300 },
301 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100302 start:
303 filter +
304 " Message contained filtered word\n\n" +
Skyler Grey11236ba2022-08-08 21:13:33 +0100305 (content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
pineafan813bdf42022-07-24 10:39:10 +0100306 },
307 list: list,
308 hidden: {
309 guild: message.channel.guild.id
310 }
pineafan63fc5e22022-08-04 22:04:10 +0100311 };
pineafan813bdf42022-07-24 10:39:10 +0100312 return log(data);
313 }
314 }
315
TheCodedProfc7e8ef12023-04-22 22:28:11 -0400316 if (
317 config.filters.pings.everyone &&
318 message.mentions.everyone &&
319 !checkUserForExceptions(message.member!, config.filters.pings.allowed)
320 ) {
Skyler Greyda16adf2023-03-05 10:22:12 +0000321 if (!(await isLogging(message.guild.id, "messageMassPing"))) return;
pineafan63fc5e22022-08-04 22:04:10 +0100322 const data = {
pineafane23c4ec2022-07-27 21:56:27 +0100323 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100324 type: "everyonePing",
325 displayName: "Everyone Pinged",
326 calculateType: "messageMassPing",
pineafane23c4ec2022-07-27 21:56:27 +0100327 color: NucleusColors.yellow,
pineafan63fc5e22022-08-04 22:04:10 +0100328 emoji: "MESSAGE.PING.EVERYONE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500329 timestamp: Date.now()
pineafane23c4ec2022-07-27 21:56:27 +0100330 },
331 separate: {
Skyler Grey11236ba2022-08-08 21:13:33 +0100332 start: content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*"
pineafane23c4ec2022-07-27 21:56:27 +0100333 },
334 list: list,
335 hidden: {
336 guild: message.channel.guild.id
pineafan813bdf42022-07-24 10:39:10 +0100337 }
pineafan63fc5e22022-08-04 22:04:10 +0100338 };
pineafane23c4ec2022-07-27 21:56:27 +0100339 return log(data);
340 }
TheCodedProfc7e8ef12023-04-22 22:28:11 -0400341 if (config.filters.pings.roles && !checkUserForExceptions(message.member!, config.filters.pings.allowed)) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100342 for (const roleId in message.mentions.roles) {
pineafan63fc5e22022-08-04 22:04:10 +0100343 if (!config.filters.pings.allowed.roles.includes(roleId)) {
PineaFan0d06edc2023-01-17 22:10:31 +0000344 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100345 await message.delete();
Skyler Greyda16adf2023-03-05 10:22:12 +0000346 if (!(await isLogging(message.guild.id, "messageMassPing"))) return;
pineafan63fc5e22022-08-04 22:04:10 +0100347 const data = {
pineafane23c4ec2022-07-27 21:56:27 +0100348 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100349 type: "rolePing",
350 displayName: "Role Pinged",
351 calculateType: "messageMassPing",
pineafane23c4ec2022-07-27 21:56:27 +0100352 color: NucleusColors.yellow,
pineafan63fc5e22022-08-04 22:04:10 +0100353 emoji: "MESSAGE.PING.ROLE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500354 timestamp: Date.now()
pineafane23c4ec2022-07-27 21:56:27 +0100355 },
356 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100357 start: content
358 ? `**Message:**\n\`\`\`${content}\`\`\``
359 : "**Message:** *Message had no content*"
pineafane23c4ec2022-07-27 21:56:27 +0100360 },
361 list: list,
362 hidden: {
363 guild: message.channel.guild.id
pineafan813bdf42022-07-24 10:39:10 +0100364 }
pineafan63fc5e22022-08-04 22:04:10 +0100365 };
pineafane23c4ec2022-07-27 21:56:27 +0100366 return log(data);
pineafan813bdf42022-07-24 10:39:10 +0100367 }
368 }
pineafane23c4ec2022-07-27 21:56:27 +0100369 }
TheCodedProfc7e8ef12023-04-22 22:28:11 -0400370 if (
371 message.mentions.users.size >= config.filters.pings.mass &&
372 config.filters.pings.mass &&
373 !checkUserForExceptions(message.member!, config.filters.pings.allowed)
374 ) {
PineaFan0d06edc2023-01-17 22:10:31 +0000375 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100376 await message.delete();
Skyler Greyda16adf2023-03-05 10:22:12 +0000377 if (!(await isLogging(message.guild.id, "messageMassPing"))) return;
pineafan63fc5e22022-08-04 22:04:10 +0100378 const data = {
pineafane23c4ec2022-07-27 21:56:27 +0100379 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100380 type: "massPing",
381 displayName: "Mass Ping",
382 calculateType: "messageMassPing",
pineafane23c4ec2022-07-27 21:56:27 +0100383 color: NucleusColors.yellow,
pineafan63fc5e22022-08-04 22:04:10 +0100384 emoji: "MESSAGE.PING.MASS",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500385 timestamp: Date.now()
pineafane23c4ec2022-07-27 21:56:27 +0100386 },
387 separate: {
Skyler Grey11236ba2022-08-08 21:13:33 +0100388 start: content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*"
pineafane23c4ec2022-07-27 21:56:27 +0100389 },
390 list: list,
391 hidden: {
392 guild: message.channel.guild.id
pineafan813bdf42022-07-24 10:39:10 +0100393 }
pineafan63fc5e22022-08-04 22:04:10 +0100394 };
pineafane23c4ec2022-07-27 21:56:27 +0100395 return log(data);
pineafan813bdf42022-07-24 10:39:10 +0100396 }
397}