11import * as Sentry from "@sentry/bun" ;
22import type { GuildMember , Message } from "discord.js" ;
33import ExpiryMap from "expiry-map" ;
4+ import { config } from "../../Config.js" ;
45import { logger } from "../../logging.js" ;
56import { getOrCreateUserById } from "../../store/models/DDUser.js" ;
67import { getMember } from "../../util/member.js" ;
@@ -18,31 +19,13 @@ const invitePatterns = [
1819
1920const whitelistDomains : string [ ] = [ ] ; // For any .gg domains that are not discord.gg
2021
21- interface InviteSpamConfig {
22- /** Max violations before auto-ban (default: 4) */
23- maxViolations : number ;
24- /** Max unique channels before auto-ban (default: 3) */
25- maxChannels : number ;
26- /** Time window in ms for tracking violations (default: 30s) */
27- violationWindowMs : number ;
28- /** Only auto-ban accounts that joined the server less than X days ago. 0 = disabled (everyone is considered) */
29- accountAgeDays : number ;
30- }
31-
32- const inviteSpamConfig : InviteSpamConfig = {
33- maxViolations : 4 ,
34- maxChannels : 3 ,
35- violationWindowMs : 30_000 ,
36- accountAgeDays : 0 ,
37- } ;
38-
3922interface InviteViolation {
4023 count : number ;
4124 channels : Set < string > ;
4225}
4326
4427const inviteViolationCache = new ExpiryMap < string , InviteViolation > (
45- inviteSpamConfig . violationWindowMs ,
28+ config . inviteSpam . violationWindowMs ,
4629) ;
4730
4831const isAllowedToSendDiscordInvites = async ( member : GuildMember ) => {
@@ -51,14 +34,14 @@ const isAllowedToSendDiscordInvites = async (member: GuildMember) => {
5134} ;
5235
5336const isSubjectToAutoban = ( member : GuildMember ) : boolean => {
54- if ( inviteSpamConfig . accountAgeDays === 0 ) return true ;
37+ if ( config . inviteSpam . accountAgeDays === 0 ) return true ;
5538
5639 const joinedAt = member . joinedAt ;
5740 if ( ! joinedAt ) return true ;
5841
5942 const daysSinceJoin =
6043 ( Date . now ( ) - joinedAt . getTime ( ) ) / ( 1000 * 60 * 60 * 24 ) ;
61- return daysSinceJoin < inviteSpamConfig . accountAgeDays ;
44+ return daysSinceJoin < config . inviteSpam . accountAgeDays ;
6245} ;
6346
6447export function parseInvites ( message : Message < true > ) {
@@ -101,7 +84,9 @@ async function banForInviteSpam(
10184 violation : InviteViolation ,
10285) {
10386 const triggerReason =
104- violation . channels . size >= 3 ? "cross_channel" : "same_channel" ;
87+ violation . channels . size >= config . inviteSpam . maxChannels
88+ ? "cross_channel"
89+ : "same_channel" ;
10590
10691 try {
10792 await member
@@ -160,8 +145,8 @@ async function handleInvite(
160145 inviteViolationCache . set ( member . id , violation ) ;
161146
162147 const shouldBan =
163- violation . count >= inviteSpamConfig . maxViolations ||
164- violation . channels . size >= inviteSpamConfig . maxChannels ;
148+ violation . count >= config . inviteSpam . maxViolations ||
149+ violation . channels . size >= config . inviteSpam . maxChannels ;
165150
166151 if ( shouldBan && isSubjectToAutoban ( member ) ) {
167152 await banForInviteSpam ( message , member , violation ) ;
0 commit comments