Skip to content

Commit c33d235

Browse files
authored
Ignore "scam" send by trusted users (#1282)
* Ignore "scam" send by trusted users * added extra "trustedUserRolePattern" config entry
1 parent e6522be commit c33d235

File tree

4 files changed

+62
-1
lines changed

4 files changed

+62
-1
lines changed

application/config.json.template

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"mode": "AUTO_DELETE_BUT_APPROVE_QUARANTINE",
2323
"reportChannelPattern": "commands",
2424
"botTrapChannelPattern": "bot-trap",
25+
"trustedUserRolePattern": "Top Helpers .+|Moderator|Community Ambassador|Expert",
2526
"suspiciousKeywords": [
2627
"nitro",
2728
"boob",

application/src/main/java/org/togetherjava/tjbot/config/ScamBlockerConfig.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public final class ScamBlockerConfig {
1818
private final Mode mode;
1919
private final String reportChannelPattern;
2020
private final String botTrapChannelPattern;
21+
private final String trustedUserRolePattern;
2122
private final Set<String> suspiciousKeywords;
2223
private final Set<String> hostWhitelist;
2324
private final Set<String> hostBlacklist;
@@ -32,6 +33,8 @@ private ScamBlockerConfig(@JsonProperty(value = "mode", required = true) Mode mo
3233
required = true) String reportChannelPattern,
3334
@JsonProperty(value = "botTrapChannelPattern",
3435
required = true) String botTrapChannelPattern,
36+
@JsonProperty(value = "trustedUserRolePattern",
37+
required = true) String trustedUserRolePattern,
3538
@JsonProperty(value = "suspiciousKeywords",
3639
required = true) Set<String> suspiciousKeywords,
3740
@JsonProperty(value = "hostWhitelist", required = true) Set<String> hostWhitelist,
@@ -47,6 +50,7 @@ private ScamBlockerConfig(@JsonProperty(value = "mode", required = true) Mode mo
4750
this.mode = Objects.requireNonNull(mode);
4851
this.reportChannelPattern = Objects.requireNonNull(reportChannelPattern);
4952
this.botTrapChannelPattern = Objects.requireNonNull(botTrapChannelPattern);
53+
this.trustedUserRolePattern = Objects.requireNonNull(trustedUserRolePattern);
5054
this.suspiciousKeywords = new HashSet<>(Objects.requireNonNull(suspiciousKeywords));
5155
this.hostWhitelist = new HashSet<>(Objects.requireNonNull(hostWhitelist));
5256
this.hostBlacklist = new HashSet<>(Objects.requireNonNull(hostBlacklist));
@@ -86,6 +90,15 @@ public String getBotTrapChannelPattern() {
8690
return botTrapChannelPattern;
8791
}
8892

93+
/**
94+
* Gets the REGEX pattern used to identify roles that will be ignored for scam detection.
95+
*
96+
* @return the REGEX pattern
97+
*/
98+
public String getTrustedUserRolePattern() {
99+
return trustedUserRolePattern;
100+
}
101+
89102
/**
90103
* Gets the set of keywords that are considered suspicious if they appear in a message.
91104
*

application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamDetector.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.togetherjava.tjbot.features.moderation.scam;
22

3+
import net.dv8tion.jda.api.entities.Member;
34
import net.dv8tion.jda.api.entities.Message;
5+
import net.dv8tion.jda.api.entities.Role;
46

57
import org.togetherjava.tjbot.config.Config;
68
import org.togetherjava.tjbot.config.ScamBlockerConfig;
@@ -25,6 +27,7 @@ public final class ScamDetector {
2527
private static final Pattern TOKENIZER = Pattern.compile("[\\s,]");
2628
private final ScamBlockerConfig config;
2729
private final Predicate<String> isSuspiciousAttachmentName;
30+
private final Predicate<String> hasTrustedRole;
2831

2932
/**
3033
* Creates a new instance with the given configuration
@@ -33,9 +36,12 @@ public final class ScamDetector {
3336
*/
3437
public ScamDetector(Config config) {
3538
this.config = config.getScamBlocker();
39+
3640
isSuspiciousAttachmentName =
37-
Pattern.compile(config.getScamBlocker().getSuspiciousAttachmentNamePattern())
41+
Pattern.compile(this.config.getSuspiciousAttachmentNamePattern())
3842
.asMatchPredicate();
43+
hasTrustedRole =
44+
Pattern.compile(this.config.getTrustedUserRolePattern()).asMatchPredicate();
3945
}
4046

4147
/**
@@ -45,6 +51,13 @@ public ScamDetector(Config config) {
4551
* @return Whether the message classifies as scam
4652
*/
4753
public boolean isScam(Message message) {
54+
Member author = message.getMember();
55+
boolean isTrustedUser = author != null
56+
&& author.getRoles().stream().map(Role::getName).noneMatch(hasTrustedRole);
57+
if (isTrustedUser) {
58+
return false;
59+
}
60+
4861
String content = message.getContentDisplay();
4962
List<Message.Attachment> attachments = message.getAttachments();
5063

application/src/test/java/org/togetherjava/tjbot/features/moderation/scam/ScamDetectorTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.togetherjava.tjbot.features.moderation.scam;
22

3+
import net.dv8tion.jda.api.entities.Member;
34
import net.dv8tion.jda.api.entities.Message;
5+
import net.dv8tion.jda.api.entities.Role;
46
import org.junit.jupiter.api.BeforeEach;
57
import org.junit.jupiter.api.DisplayName;
68
import org.junit.jupiter.api.Test;
@@ -50,6 +52,8 @@ void setUp() {
5052
when(scamConfig.getSuspiciousAttachmentNamePattern())
5153
.thenReturn(SUSPICIOUS_ATTACHMENT_NAME);
5254

55+
when(scamConfig.getTrustedUserRolePattern()).thenReturn("Moderator");
56+
5357
scamDetector = new ScamDetector(config);
5458
}
5559

@@ -205,6 +209,23 @@ void ignoresHarmlessAttachments() {
205209
assertFalse(isScamResult);
206210
}
207211

212+
@Test
213+
@DisplayName("Suspicious messages send by trusted users are not flagged")
214+
void ignoreTrustedUser() {
215+
// GIVEN a scam message send by a trusted user
216+
String content = "Checkout https://bit.ly/3IhcLiO to get your free nitro !";
217+
Member trustedUser = createAuthorMock(List.of("Moderator"));
218+
Message message = createMessageMock(content, List.of());
219+
220+
when(message.getMember()).thenReturn(trustedUser);
221+
222+
// WHEN analyzing it
223+
boolean isScamResult = scamDetector.isScam(message);
224+
225+
// THEN flags it as harmless
226+
assertTrue(isScamResult);
227+
}
228+
208229
private static Message createMessageMock(String content, List<Message.Attachment> attachments) {
209230
Message message = mock(Message.class);
210231
when(message.getContentRaw()).thenReturn(content);
@@ -220,6 +241,19 @@ private static Message.Attachment createImageAttachmentMock(String name) {
220241
return attachment;
221242
}
222243

244+
private static Member createAuthorMock(List<String> roleNames) {
245+
List<Role> roles = new ArrayList<>();
246+
for (String roleName : roleNames) {
247+
Role role = mock(Role.class);
248+
when(role.getName()).thenReturn(roleName);
249+
roles.add(role);
250+
}
251+
252+
Member member = mock(Member.class);
253+
when(member.getRoles()).thenReturn(roles);
254+
return member;
255+
}
256+
223257
private static List<String> provideRealScamMessages() {
224258
return List.of("""
225259
🤩bro steam gived nitro - https://nitro-ds.online/LfgUfMzqYyx12""",

0 commit comments

Comments
 (0)