Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.

Commit 0287b96

Browse files
added changes from short message spam branch and uuid instead of strings
1 parent 76d0ee0 commit 0287b96

8 files changed

Lines changed: 95 additions & 82 deletions

File tree

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: 🧑‍🏭
1+
name: "🧑‍🏭"
22

33
on:
44
push:

.github/workflows/verify.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
name: 🧑‍🏭
1+
name: "🚔"
22

33
on:
44
push:
55
branches:
66
- '*'
77

88
jobs:
9-
release:
9+
verify:
1010
runs-on: ubuntu-latest
1111
steps:
1212

README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
## AntiSpam
2-
1+
# AntiSpam
32
[![discord](https://img.shields.io/discord/843551077759844362?logo=discord)](https://discord.gg/7tW8ZAtGr5)
43
[![reddit](https://img.shields.io/reddit/subreddit-subscribers/0b0t)](https://old.reddit.com/r/0b0t/)
5-
[![download](https://img.shields.io/github/downloads/zeroBzeroT/AntiSpam/latest/total.svg?label=download%20latest)](https://github.com/zeroBzeroT/AntiSpam/releases/latest)
6-
![last commit](https://img.shields.io/github/last-commit/zeroBzeroT/AntiSpam)
7-
![lines of code](https://tokei.rs/b1/github/zeroBzeroT/AntiSpam)
8-
![repo size](https://img.shields.io/github/languages/code-size/zeroBzeroT/AntiSpam.svg?label=repo%20size)
9-
10-
No chat until a block has been run and checked for spam over the Levenshtein distance and Unicode ranges.
4+
## Checks
5+
- recurring (levenshtein distance)
6+
- old spam
7+
- old messages
8+
- no blank spaces
9+
- not moved yet
10+
- flood
11+
- unicode ranges
12+
- short messages

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>org.zeroBzeroT</groupId>
88
<artifactId>0b0t_AntiSpam</artifactId>
9-
<version>1.11</version>
9+
<version>1.12</version>
1010
<packaging>jar</packaging>
1111
<description>No chat until a block is run and check for spam via Levenshtein distance.</description>
1212

@@ -63,13 +63,13 @@
6363
<dependency>
6464
<groupId>org.junit.jupiter</groupId>
6565
<artifactId>junit-jupiter-engine</artifactId>
66-
<version>5.7.2</version>
66+
<version>5.8.2</version>
6767
<scope>test</scope>
6868
</dependency>
6969
<dependency>
7070
<groupId>org.junit.vintage</groupId>
7171
<artifactId>junit-vintage-engine</artifactId>
72-
<version>5.7.2</version>
72+
<version>5.8.2</version>
7373
<scope>test</scope>
7474
</dependency>
7575
</dependencies>

src/main/java/org/zeroBzeroT/antispam/AntiSpam.java

Lines changed: 32 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,17 @@
1717
import org.bukkit.plugin.PluginManager;
1818
import org.bukkit.plugin.java.JavaPlugin;
1919

20-
import java.util.ArrayList;
20+
import java.util.HashSet;
2121
import java.util.LinkedList;
22-
import java.util.List;
22+
import java.util.Set;
23+
import java.util.UUID;
24+
import java.util.concurrent.ConcurrentHashMap;
25+
import java.util.stream.Collectors;
2326

2427
public class AntiSpam extends JavaPlugin implements Listener, CommandExecutor {
25-
public static List<String> bots = new ArrayList<>();
26-
static List<String> whisperCommands = new ArrayList<>();
27-
final ArrayList<Player> notMoved = new ArrayList<>();
28+
private static final Set<UUID> bots = new HashSet<>();
29+
private static final Set<String> whisperCommands = new HashSet<>();
30+
private final Set<UUID> notMoved = ConcurrentHashMap.newKeySet();
2831

2932
FileConfiguration config;
3033

@@ -46,8 +49,8 @@ public void onEnable() {
4649
saveDefaultConfig();
4750
config = this.getConfig();
4851

49-
bots = config.getStringList("bots");
50-
whisperCommands = config.getStringList("whisperCommands");
52+
bots.addAll(config.getStringList("bots").stream().map(UUID::fromString).collect(Collectors.toSet()));
53+
whisperCommands.addAll(config.getStringList("whisperCommands"));
5154
notMovedCheckEnabled = config.getBoolean("not-moved-check-enabled");
5255
messageCannotTalk = getConfig().getString("cannot-talk");
5356
messageSpamTalk = getConfig().getString("spam-talk-message");
@@ -73,7 +76,8 @@ public void onEnable() {
7376
isSpam = false;
7477

7578
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> {
76-
int threshold = config.getInt("maximum-characters-per-minute") * Bukkit.getOnlinePlayers().size() / 2;
79+
// assume that only 10% of the players ever chat ;)
80+
int threshold = config.getInt("maximum-characters-per-minute") * Bukkit.getOnlinePlayers().size() / 10;
7781
isSpam = cumulatedMessageSize > threshold;
7882

7983
log("isSpam", "Spam: " + isSpam + " Size: " + cumulatedMessageSize + " Threshold: " + threshold);
@@ -158,8 +162,7 @@ public void onPlayerDeath(PlayerDeathEvent e) {
158162
@EventHandler
159163
public void onPlayerLeaveEvent(PlayerQuitEvent event) {
160164
if (notMovedCheckEnabled) {
161-
Player player = event.getPlayer();
162-
notMovedRemove(player);
165+
notMoved.remove(event.getPlayer().getUniqueId());
163166
}
164167

165168
spamBotCheck.setPlayerCount(getServer().getOnlinePlayers().size());
@@ -175,10 +178,7 @@ public void onPlayerLeaveEvent(PlayerQuitEvent event) {
175178
public void onPlayerChat(AsyncPlayerChatEvent event) {
176179
cumulatedMessageSize += event.getMessage().length();
177180

178-
Player player = event.getPlayer();
179-
String message = event.getMessage();
180-
181-
if (isSpam(player, message, false)) {
181+
if (isSpam(event.getPlayer(), event.getMessage(), false)) {
182182
event.setCancelled(true);
183183
}
184184
}
@@ -191,7 +191,6 @@ public void onPlayerChat(AsyncPlayerChatEvent event) {
191191
*/
192192
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
193193
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
194-
Player player = event.getPlayer();
195194
String message = event.getMessage();
196195

197196
if (whisperCommands.stream().anyMatch(cmd -> message.toLowerCase().startsWith("/" + cmd + " "))) {
@@ -200,7 +199,7 @@ public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
200199
if (messagePart.length == 3) {
201200
cumulatedMessageSize += event.getMessage().length();
202201

203-
if (isSpam(player, messagePart[2], true)) {
202+
if (isSpam(event.getPlayer(), messagePart[2], true)) {
204203
event.setCancelled(true);
205204
}
206205
}
@@ -222,9 +221,7 @@ public void onPlayerMove(PlayerMoveEvent e) {
222221

223222
Player player = e.getPlayer();
224223

225-
if (this.notMoved.contains(player)) {
226-
notMovedRemove(player);
227-
}
224+
notMoved.remove(e.getPlayer().getUniqueId());
228225
}
229226

230227
/**
@@ -245,7 +242,7 @@ private boolean isSpam(Player player, String message, boolean isWhispering) {
245242
return false;
246243
}
247244

248-
if (notMovedCheckEnabled && this.notMoved.contains(player)) {
245+
if (notMovedCheckEnabled && this.notMoved.contains(player.getUniqueId())) {
249246
player.sendMessage(ChatColor.translateAlternateColorCodes('&', messageCannotTalk));
250247
return true;
251248
}
@@ -260,7 +257,7 @@ private boolean isSpam(Player player, String message, boolean isWhispering) {
260257
// cooldown for the new message is added even on violation
261258
isSpam = true;
262259
failedTest = "Flood";
263-
} else if (spamBotCheck.isNoBlanksSpam(message)) {
260+
} else if (spamBotCheck.isNoBlanksSpam(player.getUniqueId(), message)) {
264261
// checks the frequency of whitespaces
265262
isSpam = true;
266263
failedTest = "No Blanks";
@@ -288,22 +285,22 @@ private boolean isSpam(Player player, String message, boolean isWhispering) {
288285

289286
/**
290287
* Checks, if a certain player is in the bot whitelist
291-
* TODO: add UUID check
292288
*
293289
* @param player
294290
* @return
295291
*/
296292
private boolean isBot(Player player) {
297-
for (String bot : AntiSpam.bots) {
298-
if (player.getName().toLowerCase().contentEquals(bot.toLowerCase())) {
299-
return true;
300-
}
301-
//if(player.getUniqueId().equals(UUID.fromString(bot))) {
302-
// return true;
303-
//}
304-
}
293+
return isBot(player.getUniqueId());
294+
}
305295

306-
return false;
296+
/**
297+
* Checks, if a certain uuid is in the bot whitelist
298+
*
299+
* @param uuid
300+
* @return
301+
*/
302+
private boolean isBot(UUID uuid) {
303+
return bots.contains(uuid);
307304
}
308305

309306
/**
@@ -312,27 +309,16 @@ private boolean isBot(Player player) {
312309
* @param player
313310
*/
314311
private void notMovedAdd(Player player) {
315-
for (String bot : bots) {
316-
if (bot.toLowerCase().contentEquals(player.getName().toLowerCase())) {
317-
log("Bot", player.getName());
318-
return;
319-
}
312+
if (bots.contains(player.getUniqueId())) {
313+
log("Bot", player.getName());
314+
return;
320315
}
321316

322317
if (!player.hasPermission("move.bypass")) {
323-
this.notMoved.add(player);
318+
this.notMoved.add(player.getUniqueId());
324319
}
325320
}
326321

327-
/**
328-
* remove "not moved" flag
329-
*
330-
* @param player
331-
*/
332-
private void notMovedRemove(Player player) {
333-
this.notMoved.remove(player);
334-
}
335-
336322
/**
337323
* print a log message
338324
*

src/main/java/org/zeroBzeroT/antispam/SpamCheck.java

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ public class SpamCheck {
4646
// time at which the player is allowed to chat again
4747
private final ConcurrentHashMap<UUID, Long> momentNextChatAllowed = new ConcurrentHashMap<>();
4848

49+
// time at which the player is allowed to chat again
50+
private final ConcurrentHashMap<UUID, Integer> shortMessageCount = new ConcurrentHashMap<>();
51+
4952
// sanitizing message from chars that are from unicode ranges that are only used a few times in that message
5053
private UnicodeRanges unicodeRanges;
5154

@@ -212,11 +215,28 @@ public boolean isRecurringSpam(String message) {
212215
* @param message
213216
* @return
214217
*/
215-
public boolean isNoBlanksSpam(String message) {
218+
public boolean isNoBlanksSpam(UUID uuid, String message) {
216219
// assume that the end of the text corresponds to one whitespace (+1)
217-
float whitespace = (message.length() - message.replaceAll(" ", "").length() + 1f);
220+
float whitespaceCount = (message.length() - message.replaceAll(" ", "").length());
221+
222+
if (whitespaceCount < 2) {
223+
// sentence has 2 or less whitespaces - temporary
224+
// TODO: maybe add a bucket cooldown thing here instead of that hardcoded crap
225+
shortMessageCount.putIfAbsent(uuid, 0);
226+
227+
Integer count = shortMessageCount.get(uuid);
228+
229+
if (count < 3) {
230+
shortMessageCount.put(uuid, count + 1);
231+
} else {
232+
return true;
233+
}
234+
} else {
235+
shortMessageCount.remove(uuid);
236+
}
218237

219-
return (whitespace / message.length()) < whitespaceFrequency;
238+
// Percentage of whitespace needed in long messages
239+
return ((whitespaceCount + 1f) / message.length()) < whitespaceFrequency;
220240
}
221241

222242
/**
@@ -269,9 +289,10 @@ public void setPlayerCount(int count) {
269289
/**
270290
* Removes a player from
271291
*
272-
* @param player
292+
* @param uuid
273293
*/
274-
public void onPlayerLeave(UUID player) {
275-
momentNextChatAllowed.remove(player);
294+
public void onPlayerLeave(UUID uuid) {
295+
momentNextChatAllowed.remove(uuid);
296+
shortMessageCount.remove(uuid);
276297
}
277298
}

src/main/resources/config.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,9 @@ whisperCommands:
1919
- "msg"
2020
- "whisper"
2121
bots:
22-
- "moooomoooo"
23-
- "6259c4b5-759f-4252-a6f7-d77818e125eb"
22+
- "6259c4b5-759f-4252-a6f7-d77818e125eb" # AnarchyB0T
23+
- "ddac1529-0729-4791-aa72-d82960ed8580" # moooomoooo
24+
- "f4e4573e-0bfa-4ae8-9f4c-c1d935e0b050" # Leeunderscore
25+
- "6a11762d-6d74-4a99-9980-3d9212b3bc7b" # Omega19
26+
- "ab504f4f-82a5-4129-809a-58aececcd328" # bierdosenhalter
27+
- "8aeaa92e-6a9f-400a-94d5-22b31c96f0d5" # 0Bot

src/test/java/org/zeroBzeroT/antispam/SpamCheckTest.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ boolean runTests(String message, boolean testFlood) {
3232
if (testFlood && spamCheck.isFloodSpam(uuid, message)) {
3333
//System.out.println("Failed Flood " + message);
3434
return true;
35-
} else if (spamCheck.isNoBlanksSpam(message)) {
35+
} else if (spamCheck.isNoBlanksSpam(uuid, message)) {
3636
//System.out.println("Failed No Blanks " + message);
3737
return true;
3838
} else if (spamCheck.isUnicodeRangeSpam(message)) {
@@ -60,11 +60,11 @@ void testSimple() {
6060
cnt++;
6161
Assertions.assertTrue(runTests("testtesttest"));
6262
cnt++;
63-
Assertions.assertFalse(runTests(""));
63+
Assertions.assertTrue(runTests(""));
6464
cnt++;
65-
Assertions.assertFalse(runTests("testtest"));
65+
Assertions.assertTrue(runTests("testtest"));
6666
cnt++;
67-
Assertions.assertFalse(runTests(""));
67+
Assertions.assertTrue(runTests(""));
6868
cnt++;
6969

7070

@@ -111,7 +111,7 @@ void testAlphanumericNonsense() {
111111
cnt++;
112112
Assertions.assertTrue(runTests("E01IDZxvl1G6KAMovPj1aegbsjd6FYTAvE0rRzYHN4fXJbxhc2glS1iADpuSKeNyOYlLnqJMxW6B0u7PNebFLxd4ru22vg7QSeZ6ZNJbViAmK6KhJ400Q54H8qTQ37NkpAEQ1kFbn8kKa2Bd2WQrEFNnnlng9nhA3C8mppNbbiRYWXo2daNH8FaKOCfGoMtbMJno8NYW"));
113113
cnt++;
114-
Assertions.assertFalse(runTests(""));
114+
Assertions.assertTrue(runTests(""));
115115
cnt++;
116116

117117
final long end = System.currentTimeMillis() - start;
@@ -133,9 +133,9 @@ void testShortWordSpam() {
133133
cnt++;
134134
Assertions.assertTrue(runTests("testtesttest"));
135135
cnt++;
136-
Assertions.assertFalse(runTests(""));
136+
Assertions.assertTrue(runTests(""));
137137
cnt++;
138-
Assertions.assertFalse(runTests("testtest"));
138+
Assertions.assertTrue(runTests("testtest"));
139139
cnt++;
140140

141141
final long end = System.currentTimeMillis() - start;
@@ -251,9 +251,9 @@ void testNormalChat() {
251251
cnt++;
252252
Assertions.assertFalse(runTests("gg"));
253253
cnt++;
254-
Assertions.assertFalse(runTests("\\ban nnhtrrt"));
254+
Assertions.assertTrue(runTests("\\ban nnhtrrt"));
255255
cnt++;
256-
Assertions.assertFalse(runTests("done :D"));
256+
Assertions.assertTrue(runTests("done :D"));
257257
cnt++;
258258
Assertions.assertFalse(runTests("gg im mainhanding tho"));
259259
cnt++;
@@ -269,13 +269,13 @@ void testNormalChat() {
269269
cnt++;
270270
Assertions.assertFalse(runTests("nnhtrrt"));
271271
cnt++;
272-
Assertions.assertFalse(runTests("ofc"));
272+
Assertions.assertTrue(runTests("ofc"));
273273
cnt++;
274-
Assertions.assertFalse(runTests("tp"));
274+
Assertions.assertTrue(runTests("tp"));
275275
cnt++;
276-
Assertions.assertFalse(runTests("no you"));
276+
Assertions.assertTrue(runTests("no you"));
277277
cnt++;
278-
Assertions.assertFalse(runTests("!reports"));
278+
Assertions.assertTrue(runTests("!reports"));
279279
cnt++;
280280
Assertions.assertFalse(runTests("You didn't say a playername to report."));
281281
cnt++;
@@ -291,7 +291,7 @@ void testNormalChat() {
291291
cnt++;
292292
Assertions.assertFalse(runTests("!quote"));
293293
cnt++;
294-
Assertions.assertFalse(runTests("OMGOMGOMG"));
294+
Assertions.assertTrue(runTests("OMGOMGOMG"));
295295
cnt++;
296296
Assertions.assertFalse(runTests("i ate achocolate odughnut and put it in teh trash can in my bathroom so someone will go in an say who wuped shit on the napkin teehee when its really icing teehee"));
297297
cnt++;

0 commit comments

Comments
 (0)