blob: d95d66cc4b2074b101f9ed6027de9f9bfba1634e [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
TheCodedProf680c4972023-04-23 15:14:08 -040011
pineafan63fc5e22022-08-04 22:04:10 +010012export const event = "messageCreate";
pineafan813bdf42022-07-24 10:39:10 +010013
TheCodedProfc7e8ef12023-04-22 22:28:11 -040014function checkUserForExceptions(user: GuildMember, exceptions: { roles: string[]; users: string[] }) {
15 if (exceptions.users.includes(user.id)) return true;
16 for (const role of user.roles.cache.values()) {
17 if (exceptions.roles.includes(role.id)) return true;
18 }
19 return false;
20}
21
PineaFan752af462022-12-31 21:59:38 +000022export async function callback(_client: NucleusClient, message: Message) {
Skyler Grey75ea9172022-08-06 10:22:23 +010023 if (!message.guild) return;
PineappleFan13892c62023-03-05 07:00:07 +000024 const config = await client.memory.readGuildInfo(message.guild.id);
Skyler9f5fca82023-03-05 09:12:03 +000025
Skyler Greyda16adf2023-03-05 10:22:12 +000026 if (
27 config.autoPublish.enabled &&
28 config.autoPublish.channels.includes(message.channel.id) &&
29 message.channel.type === ChannelType.GuildAnnouncement &&
30 message.reference === null
Skyler9f5fca82023-03-05 09:12:03 +000031 ) {
Skyler Grey67691762023-03-06 09:58:19 +000032 if (message.channel.permissionsFor(message.guild.members.me!)!.has("ManageMessages")) {
TheCodedProfb7a7b992023-03-05 16:11:59 -050033 await message.crosspost();
34 } else {
Skyler Greyf4f21c42023-03-08 14:36:29 +000035 await singleNotify(
36 `Nucleus does not have Manage Messages in <#${message.channel.id}>`,
37 message.guild.id,
38 true
39 );
TheCodedProfb7a7b992023-03-05 16:11:59 -050040 }
PineappleFan13892c62023-03-05 07:00:07 +000041 }
42
pineafan63fc5e22022-08-04 22:04:10 +010043 if (message.author.bot) return;
PineaFan538d3752023-01-12 21:48:23 +000044 if (message.channel.isDMBased()) return;
Skyler Grey75ea9172022-08-06 10:22:23 +010045 try {
pineafan6de4da52023-03-07 20:43:44 +000046 await statsChannelUpdate((await message.guild.members.fetch(message.author.id)).user, message.guild);
Skyler Grey75ea9172022-08-06 10:22:23 +010047 } catch (e) {
48 console.log(e);
49 }
pineafan813bdf42022-07-24 10:39:10 +010050
TheCodedProf6ec331b2023-02-20 12:13:06 -050051 const { log, isLogging, NucleusColors, entry, renderUser, renderDelta, renderChannel } = client.logger;
pineafan813bdf42022-07-24 10:39:10 +010052
pineafan63fc5e22022-08-04 22:04:10 +010053 const fileNames = await logAttachment(message);
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 = "";
TheCodedProf680c4972023-04-23 15:14:08 -040061 console.log(config.logging.attachments.saved)
Skyler Grey75ea9172022-08-06 10:22:23 +010062 if (config.logging.attachments.saved[message.channel.id + message.id]) {
Skyler Grey11236ba2022-08-08 21:13:33 +010063 attachmentJump = ` [[View attachments]](${config.logging.attachments.saved[message.channel.id + message.id]})`;
Skyler Grey75ea9172022-08-06 10:22:23 +010064 }
pineafan63fc5e22022-08-04 22:04:10 +010065 const list = {
pineafan813bdf42022-07-24 10:39:10 +010066 messageId: entry(message.id, `\`${message.id}\``),
67 sentBy: entry(message.author.id, renderUser(message.author)),
68 sentIn: entry(message.channel.id, renderChannel(message.channel)),
TheCodedProf6ec331b2023-02-20 12:13:06 -050069 deleted: entry(Date.now(), renderDelta(Date.now())),
pineafan813bdf42022-07-24 10:39:10 +010070 mentions: message.mentions.users.size,
Skyler Grey11236ba2022-08-08 21:13:33 +010071 attachments: entry(message.attachments.size, message.attachments.size + attachmentJump),
pineafan813bdf42022-07-24 10:39:10 +010072 repliedTo: entry(
PineaFan538d3752023-01-12 21:48:23 +000073 (message.reference ? message.reference.messageId : null) ?? null,
Skyler Grey75ea9172022-08-06 10:22:23 +010074 message.reference
75 ? `[[Jump to message]](https://discord.com/channels/${message.guild.id}/${message.channel.id}/${message.reference.messageId})`
76 : "None"
pineafan813bdf42022-07-24 10:39:10 +010077 )
pineafan63fc5e22022-08-04 22:04:10 +010078 };
pineafan813bdf42022-07-24 10:39:10 +010079
80 if (config.filters.invite.enabled) {
TheCodedProfc7e8ef12023-04-22 22:28:11 -040081 if (
82 !config.filters.invite.allowed.channels.includes(message.channel.id) ||
83 !checkUserForExceptions(message.member!, config.filters.invite.allowed)
84 ) {
Skyler Grey11236ba2022-08-08 21:13:33 +010085 if (/(?:https?:\/\/)?discord(?:app)?\.(?:com\/invite|gg)\/[a-zA-Z0-9]+\/?/.test(content)) {
PineaFan0d06edc2023-01-17 22:10:31 +000086 messageException(message.guild.id, message.channel.id, message.id);
Skyler Greyf4f21c42023-03-08 14:36:29 +000087 await message.delete();
pineafan63fc5e22022-08-04 22:04:10 +010088 const data = {
pineafan813bdf42022-07-24 10:39:10 +010089 meta: {
pineafan63fc5e22022-08-04 22:04:10 +010090 type: "messageDelete",
pineafanfa445992023-03-06 16:21:51 +000091 displayName: "Message Deleted",
pineafan63fc5e22022-08-04 22:04:10 +010092 calculateType: "autoModeratorDeleted",
pineafan813bdf42022-07-24 10:39:10 +010093 color: NucleusColors.red,
pineafan63fc5e22022-08-04 22:04:10 +010094 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -050095 timestamp: Date.now()
pineafan813bdf42022-07-24 10:39:10 +010096 },
97 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +010098 start:
99 filter +
100 " Contained invite\n\n" +
Skyler Grey11236ba2022-08-08 21:13:33 +0100101 (content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
pineafan813bdf42022-07-24 10:39:10 +0100102 },
103 list: list,
104 hidden: {
105 guild: message.channel.guild.id
106 }
pineafan63fc5e22022-08-04 22:04:10 +0100107 };
pineafan813bdf42022-07-24 10:39:10 +0100108 return log(data);
109 }
110 }
111 }
112
113 if (fileNames.files.length > 0) {
pineafan63fc5e22022-08-04 22:04:10 +0100114 for (const element of fileNames.files) {
pineafan63fc5e22022-08-04 22:04:10 +0100115 const url = element.url ? element.url : element.local;
Skyler Greyda16adf2023-03-05 10:22:12 +0000116 if (
Skyler Grey0d885222023-03-08 21:46:37 +0000117 /\.(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 +0000118 url.toLowerCase()
119 )
120 ) {
Skyler Grey0d885222023-03-08 21:46:37 +0000121 // j(pe?g|fif)|a?png|gifv?|w(eb[mp]|av)|mp([34]|eg-\d)|ogg|avi|h\.26(4|5)
122 // ^no
Skyler Grey75ea9172022-08-06 10:22:23 +0100123 if (
Skyler Greyc634e2b2022-08-06 17:50:48 +0100124 config.filters.images.NSFW &&
Skyler Grey0d885222023-03-08 21:46:37 +0000125 !(message.channel instanceof ThreadChannel ? message.channel.parent?.nsfw : message.channel.nsfw) &&
Skyler Grey74169642023-03-09 11:59:09 +0000126 (await NSFWCheck(element.url))
Skyler Grey75ea9172022-08-06 10:22:23 +0100127 ) {
Skyler Grey0d885222023-03-08 21:46:37 +0000128 messageException(message.guild.id, message.channel.id, message.id);
129 await message.delete();
130 const data = {
131 meta: {
132 type: "messageDelete",
133 displayName: "Message Deleted",
134 calculateType: "autoModeratorDeleted",
135 color: NucleusColors.red,
136 emoji: "MESSAGE.DELETE",
137 timestamp: Date.now()
138 },
139 separate: {
140 start:
141 filter +
142 " Image detected as NSFW\n\n" +
143 (content
144 ? `**Message:**\n\`\`\`${content}\`\`\``
145 : "**Message:** *Message had no content*")
146 },
147 list: list,
148 hidden: {
149 guild: message.channel.guild.id
150 }
151 };
152 return log(data);
pineafan813bdf42022-07-24 10:39:10 +0100153 }
Skyler Greyc634e2b2022-08-06 17:50:48 +0100154 if (config.filters.wordFilter.enabled) {
155 const text = await TestImage(url);
156 const check = TestString(
157 text ?? "",
158 config.filters.wordFilter.words.loose,
159 config.filters.wordFilter.words.strict
160 );
TheCodedProfc7e8ef12023-04-22 22:28:11 -0400161 if (
162 check !== null &&
163 (!checkUserForExceptions(message.member!, config.filters.wordFilter.allowed) ||
164 !config.filters.wordFilter.allowed.channels.includes(message.channel.id))
165 ) {
PineaFan0d06edc2023-01-17 22:10:31 +0000166 messageException(message.guild.id, message.channel.id, message.id);
Skyler Greyc634e2b2022-08-06 17:50:48 +0100167 await message.delete();
168 const data = {
169 meta: {
170 type: "messageDelete",
171 displayName: "Message Deleted",
172 calculateType: "autoModeratorDeleted",
173 color: NucleusColors.red,
174 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500175 timestamp: Date.now()
Skyler Greyc634e2b2022-08-06 17:50:48 +0100176 },
177 separate: {
178 start:
179 filter +
180 " Image contained filtered word\n\n" +
181 (content
182 ? `**Message:**\n\`\`\`${content}\`\`\``
183 : "**Message:** *Message had no content*")
184 },
185 list: list,
186 hidden: {
187 guild: message.channel.guild.id
188 }
189 };
190 return log(data);
191 }
192 }
193 if (config.filters.images.size) {
194 if (url.match(/\.+(webp|png|jpg)$/gi)) {
195 if (!(await SizeCheck(element))) {
PineaFan0d06edc2023-01-17 22:10:31 +0000196 messageException(message.guild.id, message.channel.id, message.id);
Skyler Greyc634e2b2022-08-06 17:50:48 +0100197 await message.delete();
198 const data = {
199 meta: {
200 type: "messageDelete",
201 displayName: "Message Deleted",
202 calculateType: "autoModeratorDeleted",
203 color: NucleusColors.red,
204 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500205 timestamp: Date.now()
Skyler Greyc634e2b2022-08-06 17:50:48 +0100206 },
207 separate: {
208 start:
209 filter +
210 " Image was too small\n\n" +
211 (content
212 ? `**Message:**\n\`\`\`${content}\`\`\``
213 : "**Message:** *Message had no content*")
214 },
215 list: list,
216 hidden: {
217 guild: message.channel.guild.id
218 }
219 };
220 return log(data);
221 }
222 }
223 }
224 }
Skyler Grey0d885222023-03-08 21:46:37 +0000225 if (config.filters.malware && (await MalwareCheck(url))) {
226 messageException(message.guild.id, message.channel.id, message.id);
227 await message.delete();
228 const data = {
229 meta: {
230 type: "messageDelete",
231 displayName: "Message Deleted",
232 calculateType: "autoModeratorDeleted",
233 color: NucleusColors.red,
234 emoji: "MESSAGE.DELETE",
235 timestamp: Date.now()
236 },
237 separate: {
238 start:
239 filter +
240 " File detected as malware\n\n" +
241 (content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
242 },
243 list: list,
244 hidden: {
245 guild: message.channel.guild.id
246 }
247 };
248 return log(data);
pineafan813bdf42022-07-24 10:39:10 +0100249 }
pineafan63fc5e22022-08-04 22:04:10 +0100250 }
pineafan813bdf42022-07-24 10:39:10 +0100251 }
pineafan813bdf42022-07-24 10:39:10 +0100252
pineafan63fc5e22022-08-04 22:04:10 +0100253 const linkDetectionTypes = await LinkCheck(message);
pineafan813bdf42022-07-24 10:39:10 +0100254 if (linkDetectionTypes.length > 0) {
PineaFan0d06edc2023-01-17 22:10:31 +0000255 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100256 await message.delete();
257 const data = {
pineafan813bdf42022-07-24 10:39:10 +0100258 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100259 type: "messageDelete",
260 displayName: "Message Deleted",
261 calculateType: "autoModeratorDeleted",
pineafan813bdf42022-07-24 10:39:10 +0100262 color: NucleusColors.red,
pineafan63fc5e22022-08-04 22:04:10 +0100263 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500264 timestamp: Date.now()
pineafan813bdf42022-07-24 10:39:10 +0100265 },
266 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100267 start:
268 filter +
269 ` Link filtered as ${linkDetectionTypes[0]?.toLowerCase()}\n\n` +
Skyler Grey11236ba2022-08-08 21:13:33 +0100270 (content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
pineafan813bdf42022-07-24 10:39:10 +0100271 },
272 list: list,
273 hidden: {
274 guild: message.channel.guild.id
275 }
pineafan63fc5e22022-08-04 22:04:10 +0100276 };
pineafan813bdf42022-07-24 10:39:10 +0100277 return log(data);
278 }
pineafane23c4ec2022-07-27 21:56:27 +0100279
TheCodedProfc7e8ef12023-04-22 22:28:11 -0400280 if (
281 config.filters.wordFilter.enabled &&
282 (!checkUserForExceptions(message.member!, config.filters.wordFilter.allowed) ||
283 !config.filters.wordFilter.allowed.channels.includes(message.channel.id))
284 ) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100285 const check = TestString(
286 content,
287 config.filters.wordFilter.words.loose,
TheCodedProf21d4b0f2023-04-22 21:02:51 -0400288 config.filters.wordFilter.words.strict
Skyler Grey75ea9172022-08-06 10:22:23 +0100289 );
290 if (check !== null) {
PineaFan0d06edc2023-01-17 22:10:31 +0000291 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100292 await message.delete();
293 const data = {
pineafan813bdf42022-07-24 10:39:10 +0100294 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100295 type: "messageDelete",
296 displayName: "Message Deleted",
297 calculateType: "autoModeratorDeleted",
pineafan813bdf42022-07-24 10:39:10 +0100298 color: NucleusColors.red,
pineafan63fc5e22022-08-04 22:04:10 +0100299 emoji: "MESSAGE.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500300 timestamp: Date.now()
pineafan813bdf42022-07-24 10:39:10 +0100301 },
302 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100303 start:
304 filter +
305 " Message contained filtered word\n\n" +
Skyler Grey11236ba2022-08-08 21:13:33 +0100306 (content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
pineafan813bdf42022-07-24 10:39:10 +0100307 },
308 list: list,
309 hidden: {
310 guild: message.channel.guild.id
311 }
pineafan63fc5e22022-08-04 22:04:10 +0100312 };
pineafan813bdf42022-07-24 10:39:10 +0100313 return log(data);
314 }
315 }
316
TheCodedProfc7e8ef12023-04-22 22:28:11 -0400317 if (
318 config.filters.pings.everyone &&
319 message.mentions.everyone &&
320 !checkUserForExceptions(message.member!, config.filters.pings.allowed)
321 ) {
Skyler Greyda16adf2023-03-05 10:22:12 +0000322 if (!(await isLogging(message.guild.id, "messageMassPing"))) return;
pineafan63fc5e22022-08-04 22:04:10 +0100323 const data = {
pineafane23c4ec2022-07-27 21:56:27 +0100324 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100325 type: "everyonePing",
326 displayName: "Everyone Pinged",
327 calculateType: "messageMassPing",
pineafane23c4ec2022-07-27 21:56:27 +0100328 color: NucleusColors.yellow,
pineafan63fc5e22022-08-04 22:04:10 +0100329 emoji: "MESSAGE.PING.EVERYONE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500330 timestamp: Date.now()
pineafane23c4ec2022-07-27 21:56:27 +0100331 },
332 separate: {
Skyler Grey11236ba2022-08-08 21:13:33 +0100333 start: content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*"
pineafane23c4ec2022-07-27 21:56:27 +0100334 },
335 list: list,
336 hidden: {
337 guild: message.channel.guild.id
pineafan813bdf42022-07-24 10:39:10 +0100338 }
pineafan63fc5e22022-08-04 22:04:10 +0100339 };
pineafane23c4ec2022-07-27 21:56:27 +0100340 return log(data);
341 }
TheCodedProfc7e8ef12023-04-22 22:28:11 -0400342 if (config.filters.pings.roles && !checkUserForExceptions(message.member!, config.filters.pings.allowed)) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100343 for (const roleId in message.mentions.roles) {
pineafan63fc5e22022-08-04 22:04:10 +0100344 if (!config.filters.pings.allowed.roles.includes(roleId)) {
PineaFan0d06edc2023-01-17 22:10:31 +0000345 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100346 await message.delete();
Skyler Greyda16adf2023-03-05 10:22:12 +0000347 if (!(await isLogging(message.guild.id, "messageMassPing"))) return;
pineafan63fc5e22022-08-04 22:04:10 +0100348 const data = {
pineafane23c4ec2022-07-27 21:56:27 +0100349 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100350 type: "rolePing",
351 displayName: "Role Pinged",
352 calculateType: "messageMassPing",
pineafane23c4ec2022-07-27 21:56:27 +0100353 color: NucleusColors.yellow,
pineafan63fc5e22022-08-04 22:04:10 +0100354 emoji: "MESSAGE.PING.ROLE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500355 timestamp: Date.now()
pineafane23c4ec2022-07-27 21:56:27 +0100356 },
357 separate: {
Skyler Grey75ea9172022-08-06 10:22:23 +0100358 start: content
359 ? `**Message:**\n\`\`\`${content}\`\`\``
360 : "**Message:** *Message had no content*"
pineafane23c4ec2022-07-27 21:56:27 +0100361 },
362 list: list,
363 hidden: {
364 guild: message.channel.guild.id
pineafan813bdf42022-07-24 10:39:10 +0100365 }
pineafan63fc5e22022-08-04 22:04:10 +0100366 };
pineafane23c4ec2022-07-27 21:56:27 +0100367 return log(data);
pineafan813bdf42022-07-24 10:39:10 +0100368 }
369 }
pineafane23c4ec2022-07-27 21:56:27 +0100370 }
TheCodedProfc7e8ef12023-04-22 22:28:11 -0400371 if (
372 message.mentions.users.size >= config.filters.pings.mass &&
373 config.filters.pings.mass &&
374 !checkUserForExceptions(message.member!, config.filters.pings.allowed)
375 ) {
PineaFan0d06edc2023-01-17 22:10:31 +0000376 messageException(message.guild.id, message.channel.id, message.id);
pineafan63fc5e22022-08-04 22:04:10 +0100377 await message.delete();
Skyler Greyda16adf2023-03-05 10:22:12 +0000378 if (!(await isLogging(message.guild.id, "messageMassPing"))) return;
pineafan63fc5e22022-08-04 22:04:10 +0100379 const data = {
pineafane23c4ec2022-07-27 21:56:27 +0100380 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100381 type: "massPing",
382 displayName: "Mass Ping",
383 calculateType: "messageMassPing",
pineafane23c4ec2022-07-27 21:56:27 +0100384 color: NucleusColors.yellow,
pineafan63fc5e22022-08-04 22:04:10 +0100385 emoji: "MESSAGE.PING.MASS",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500386 timestamp: Date.now()
pineafane23c4ec2022-07-27 21:56:27 +0100387 },
388 separate: {
Skyler Grey11236ba2022-08-08 21:13:33 +0100389 start: content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*"
pineafane23c4ec2022-07-27 21:56:27 +0100390 },
391 list: list,
392 hidden: {
393 guild: message.channel.guild.id
pineafan813bdf42022-07-24 10:39:10 +0100394 }
pineafan63fc5e22022-08-04 22:04:10 +0100395 };
pineafane23c4ec2022-07-27 21:56:27 +0100396 return log(data);
pineafan813bdf42022-07-24 10:39:10 +0100397 }
398}