-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathspam.go
103 lines (90 loc) · 2.3 KB
/
spam.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package main
import (
"regexp"
"unicode"
"github.com/bwmarrin/discordgo"
)
// Check if the name matches any of the given patterns
func isNameSpam(name string, patterns []string) bool {
for _, pattern := range patterns {
matched, _ := regexp.MatchString(pattern, name)
if matched {
return true
}
}
return false
}
// Check for spam user or display name and terminate member if conditions are met
func checkSpamName(s *discordgo.Session, m *discordgo.GuildMemberAdd) bool {
patterns := []string{
`(?i)Admin`,
`(?i)Announcement`,
`(?i)[CС][aа][pр]t[cс]h[aа]`,
`(?i)FAQ`,
`(?i)Giveaway`,
`(?i)Helpdesk`,
`(?i)Manager`,
`(?i)MEE6`,
`(?i)Support`,
`\d{4}$`,
}
username := m.User.Username
displayName := m.User.GlobalName
if (isNameSpam(username, patterns) || isNameSpam(displayName, patterns)) && len(m.Roles) == 0 {
go turdifyMember(s, m, "Name spam")
return true
}
// Random-looking usernames with high entropy
if hasHighEntropy(username) {
go turdifyMember(s, m, "High entropy spam name")
return true
}
return false
}
// Calculate entropy of a string to detect random-looking usernames
func hasHighEntropy(s string) bool {
// Skip short strings
if len(s) < 10 {
return false
}
// Count character types (lowercase, uppercase, digits)
var lowerCount, upperCount, digitCount, otherCount int
for _, char := range s {
switch {
case unicode.IsLower(char):
lowerCount++
case unicode.IsUpper(char):
upperCount++
case unicode.IsDigit(char):
digitCount++
default:
otherCount++
}
}
// Check for high variance in character types (indicates randomness)
if lowerCount > 0 && digitCount > 0 && (float64(digitCount)/float64(len(s)) > 0.2) && (float64(lowerCount)/float64(len(s)) > 0.3) {
return true
}
// Calculate transitions between character types (more transitions = more random)
transitions := 0
lastType := -1
for _, char := range s {
currentType := -1
switch {
case unicode.IsLower(char):
currentType = 0
case unicode.IsUpper(char):
currentType = 1
case unicode.IsDigit(char):
currentType = 2
default:
currentType = 3
}
if lastType != -1 && currentType != lastType {
transitions++
}
lastType = currentType
}
// If we have many transitions between character types, it's likely random
return transitions > len(s)/3
}