FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feature/handle-similar-messages-as-scam by Alathreon · Pull Request #1292 · Together-Java/TJ-Bot · GitHub

feature/handle-similar-messages-as-scam - #1292

Open
Alathreon wants to merge 2 commits into
developfrom
feature/handle-similar-messages-as-scam
Open

feature/handle-similar-messages-as-scam#1292
Alathreon wants to merge 2 commits into
developfrom
feature/handle-similar-messages-as-scam

Conversation

Alathreon commented Jul 31, 2025
edited
Loading

Copy link
Copy Markdown
Contributor

From in #1283 with those differences:

  • Whole feature uses its own class
  • I used a local cache
  • I didn't use caffeeine
  • 4 new config variables
  • A few fail safes
  • Hash is based on SHA

Alathreon requested a review from a team as a code owner July 31, 2025 21:32
Alathreon linked an issue Jul 31, 2025 that may be closed by this pull request
Alathreon force-pushed the feature/handle-similar-messages-as-scam branch from 2842442 to c160a4d Compare July 31, 2025 21:33
SquidXTV added enhancement New feature or request config-changes if your PR contains any changes related to config file labels Aug 1, 2025

Zabuzard left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Good stuff, thanks! I got some remarks regarding readability mostly 👍

Comment thread gradlew.bat Outdated
Alathreon force-pushed the feature/handle-similar-messages-as-scam branch from c160a4d to 70375f7 Compare August 3, 2025 21:52

sonarqubecloud Bot commented Aug 3, 2025

Copy link
Copy Markdown

Comment on lines +88 to +99
if (alreadyFlaggedUsers.contains(userId)) {
return true;
}
if (shouldIgnore(event.getMessage())) {
return false;
}
String hash = addToMessageCache(event).messageHash();
if (hasPostedTooManySimilarMessages(userId, hash)) {
alreadyFlaggedUsers.add(userId);
return true;
} else {
return false;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

i am not sure if that alreadyFlaggedUsers user thing really works.. the bot has a really long uptime usually, sometimes many months.
the way i read the code is that if a user got flagged once, they will then be immune to this check until the bot is restarted again. u could argue that its probably not an issue in practice but it smells a bit. you would need a time based cleanup for alreadyFlaggedUsers as well.

at which point u have like 30 lines of code dealing with what caffeeine gets done in one line, i guess.

private final Cache<String, Instant> userIdToAskedAtCache = Caffeine.newBuilder()
  .maximumSize(1_000)
  .expireAfterWrite(Duration.of(10, ChronoUnit.SECONDS))
  .build();

the interface is essentially that of a Map, so you have various get and put variants. internally its a LRU map, so it kicks out the entries that werent touched the longest when it reaches the max limit.

Alathreon Aug 5, 2025
edited
Loading

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

how do i make it a set ? if the cache already handles he cleanup, then storing the instant is pointless.
edit: i saw your other comment, i'll see that

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

caffeine only has a Map. sometimes in the past we also only needed a Set and then mapped it to something. for example to itself, i.e. key == value.

* @param text the UTF 8 text to hash
* @return the computed hash
*/
public static byte[] hashUTF8(String method, String text) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

NIT: should probably be renamed into hashUtf8 for better camelCase readability

Comment on lines +47 to +54
private MessageInfo addToMessageCache(MessageReceivedEvent event) {
long userId = event.getAuthor().getIdLong();
long channelId = event.getChannel().getIdLong();
String messageHash = getHash(event.getMessage());
Instant timestamp = event.getMessage().getTimeCreated().toInstant();
MessageInfo messageInfo = new MessageInfo(userId, channelId, messageHash, timestamp);
messageCache.add(messageInfo);
return messageInfo;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

id still refactor this and move all the stuff dealing with MessageInfo into the record. so:

record MessageInfo(...) {
  static MessageInfo fromMessageEvent(MessageReceivedEvent event) {...}
}

then this addToMessageCache method becomes obsolete and can be replaced with just messageCache.add(MessageInfo.fromMessageEvent(event)); at the call-site

the hash creation would then also move into the records fromMessageEvent method (or as private static helper in the record)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I don't quite like adding a unnecessary dependencies to a record, and even less logic like how to create a hash or how to create it from an event imo.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

mh... but its a factory to create instances of this record. so imo this is exactly the place it should be. what do others here think?

* @param event the message event
* @return true if the user spammed the message in several channels, false otherwise
*/
public boolean doSimilarMessageCheck(MessageReceivedEvent event) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

could u do some reordering so the flow reads top to bottom. this method would then be at the top, as entry-point. and the private methods then below it in the order they are used. the runRoutine can stay at the very bottom, i guess, since its a detached flow.

"suspiciousAttachmentNamePattern": "(image|\\d{1,2})\\.[^.]{0,5}"
"suspiciousAttachmentNamePattern": "(image|\\d{1,2})\\.[^.]{0,5}",
"maxAllowedSimilarMessages": 2,
"similarMessagesWindow": 1,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

missing time unit. please add it to the name.

"maxAllowedSimilarMessages": 2,
"similarMessagesWindow": 1,
"similarMessageLengthIgnore": 10,
"similarMessagesWhitelist": []

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

i dont think we need that, please remove.

the UX for it for maintainers would be really weird, having to bloat the config with 100 character long messages and whatnot. and then it didnt work bc of a smiley or other stuff that ends up slightly different.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

All 4? or just the whitelist ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

sorry, the preview didnt turn out the way i wanted. i was referring to the message whitelist.

isSafe = false;
}

if (isSafe && similarMessagesDetector.doSimilarMessageCheck(event)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

doSimilarMessageCheck should be renamed. maybe hasPostedSimilarMessageTooOften(event)

if you dont want it to start with a question-word bc of the side effects, maybe handleHasPostedSimilarMessagesTooOften(event).

but the name should clarify what the boolean it returns means and how it fits into the logic of ScamBlocker

/**
* Has to be called often to clear the cache.
*/
public void runRoutine() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

rename to clearCache or cleanupCache or something.

return similarMessageCount > scamBlockerConfig.getMaxAllowedSimilarMessages();
}

private boolean isObsolete(MessageInfo messageInfo) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

rename to isOutdated or isExpired

return true;
}
return scamBlockerConfig.getSimilarMessagesWhitelist()
.contains(message.getContentRaw().toLowerCase());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

.toLowerCase needs Locale.US

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

config-changes if your PR contains any changes related to config file enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auto ban/quarantine based on similar messages

3 participants


Back | FazBrowse Home | New Git URL