-
Notifications
You must be signed in to change notification settings - Fork 1
AntiScam Checks #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
62825bd
541bdb0
62b594a
75201e6
0864ae0
2c69b94
2a17bcb
dfad828
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,11 +2,62 @@ import {EmbedBuilder, Events, Message, PermissionFlagsBits} from "discord.js"; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import {guildDB} from "../db"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Colors from "../util/colors"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type Patterns = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| regex: RegExp, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| whitelist: string[], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| predicate: (links: RegExpMatchArray[], self: Patterns) => boolean, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reason: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maxCount?: number, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fakeDiscordRegex = new RegExp(`([a-zA-Z-\\.]+)?d[il][il]?scorr?(cl|[ldb])([a-zA-Z-\\.]+)?\\.(com|net|app|gift|ru|uk)`, "ig"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const okayDiscordRegex = new RegExp(`([a-zA-Z-\\.]+\\.)?discord((?:app)|(?:status))?\\.(com|net|app)`, "i"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fakeSteamRegex = new RegExp(`str?e[ea]?mcomm?m?un[un]?[un]?[tl]?[il][tl]?ty\\.(com|net|ru|us)`, "ig"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const sketchyRuRegex = new RegExp(`([a-zA-Z-\\.]+).ru.com`, "ig"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const phishingPatterns = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| regex: /([a-zA-Z-\\.]+)?d[il][il]?scorr?(cl|[ldb])([a-zA-Z-\\.]+)?\.(com|net|app|gift|ru|uk)/ig, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| whitelist: ['discord.com', 'discordapp.com'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| whitelist: ['discord.com', 'discordapp.com'], | |
| whitelist: ['discord.com', 'discordapp.com', 'betterdiscord.app'], |
zrodevkaan marked this conversation as resolved.
Show resolved
Hide resolved
zrodevkaan marked this conversation as resolved.
Show resolved
Hide resolved
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whitelist check should use the full hostname, not just the host. URL.parse().host may include the port number, which could cause legitimate URLs with ports to be flagged. Consider comparing against hostname instead or normalize the comparison.
zrodevkaan marked this conversation as resolved.
Show resolved
Hide resolved
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing error handling for URL parsing. If the URL is malformed, URL.parse or new URL() will throw an error. Wrap the URL parsing in a try-catch block to prevent the entire spam detection from failing on malformed URLs.
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This predicate function is duplicated in the second pattern (lines 30-37). Consider extracting this into a shared helper function to reduce code duplication and improve maintainability.
| const phishingPatterns = [ | |
| { | |
| regex: /([a-zA-Z-\\.]+)?d[il][il]?scorr?(cl|[ldb])([a-zA-Z-\\.]+)?\.(com|net|app|gift|ru|uk)/ig, | |
| whitelist: ['discord.com', 'discordapp.com'], | |
| predicate: (links, self) => { | |
| const hosts = links.map(match => { | |
| const url = match[0]; | |
| const fullUrl = url.startsWith('http') ? url : `https://${url}`; | |
| return URL.parse(fullUrl)?.host; | |
| }).filter(Boolean); | |
| return hosts.some(host => !self.whitelist.includes(host)); | |
| }, | |
| reason: 'Fake Discord Domain' | |
| }, | |
| { | |
| regex: /str?e[ea]?mcomm?m?un[un]?[un]?[tl]?[il][tl]?ty\.(com|net|ru|us)/ig, | |
| whitelist: ['steamcommunity.com'], | |
| predicate: (links, self) => { | |
| const hosts = links.map(match => { | |
| const url = match[0]; | |
| const fullUrl = url.startsWith('http') ? url : `https://${url}`; | |
| return URL.parse(fullUrl)?.host; | |
| }).filter(Boolean); | |
| return hosts.some(host => !self.whitelist.includes(host)); | |
| }, | |
| function hasNonWhitelistedHost(links: RegExpMatchArray[], whitelist: string[]): boolean { | |
| const hosts = links.map(match => { | |
| const url = match[0]; | |
| const fullUrl = url.startsWith('http') ? url : `https://${url}`; | |
| return URL.parse(fullUrl)?.host; | |
| }).filter(Boolean); | |
| return hosts.some(host => !whitelist.includes(host as string)); | |
| } | |
| const phishingPatterns = [ | |
| { | |
| regex: /([a-zA-Z-\\.]+)?d[il][il]?scorr?(cl|[ldb])([a-zA-Z-\\.]+)?\.(com|net|app|gift|ru|uk)/ig, | |
| whitelist: ['discord.com', 'discordapp.com'], | |
| predicate: (links, self) => hasNonWhitelistedHost(links, self.whitelist), | |
| reason: 'Fake Discord Domain' | |
| }, | |
| { | |
| regex: /str?e[ea]?mcomm?m?un[un]?[un]?[tl]?[il][tl]?ty\.(com|net|ru|us)/ig, | |
| whitelist: ['steamcommunity.com'], | |
| predicate: (links, self) => hasNonWhitelistedHost(links, self.whitelist), |
zrodevkaan marked this conversation as resolved.
Show resolved
Hide resolved
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The equality check should use strict equality. Replace '==' with '===' to avoid type coercion issues and follow JavaScript best practices.
| predicate: (links, self) => links.length == self.maxCount, // this should probably be more than 4 later on. | |
| predicate: (links, self) => links.length === self.maxCount, // this should probably be more than 4 later on. |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This generic URL regex pattern is too broad and will match many legitimate URLs. It will trigger on any message containing 4+ URLs regardless of their legitimacy. Consider adding common legitimate domains to the whitelist or refining this pattern to avoid false positives.
| whitelist: [], | |
| predicate: (links, self) => links.length == self.maxCount, // this should probably be more than 4 later on. | |
| whitelist: [ | |
| 'discord.com', | |
| 'discordapp.com', | |
| 'steamcommunity.com', | |
| 'github.com', | |
| 'gitlab.com', | |
| 'bitbucket.org', | |
| 'google.com', | |
| 'youtube.com', | |
| 'youtu.be', | |
| 'twitch.tv', | |
| 'twitter.com', | |
| 'x.com', | |
| 'reddit.com' | |
| ], | |
| predicate: (links, self) => { | |
| const suspiciousLinks = links.filter(match => { | |
| const url = match[0].toLowerCase(); | |
| return !self.whitelist.some(domain => url.includes(domain)); | |
| }); | |
| return suspiciousLinks.length === self.maxCount; // this should probably be more than 4 later on. | |
| }, |
Uh oh!
There was an error while loading. Please reload this page.