From 23e7c5733329f67a66d16bbc66ef84630bd3132d Mon Sep 17 00:00:00 2001 From: Teriuihi Date: Sun, 27 Feb 2022 18:29:41 +0100 Subject: [PATCH] Use exceptions for filters, highlight words that were filtered --- .../com/alttd/chat/managers/RegexManager.java | 23 ++++----- .../com/alttd/chat/objects/ChatFilter.java | 47 ++++++++++++++----- .../alttd/chat/objects/ModifiableString.java | 17 +++++++ .../com/alttd/chat/handler/ChatHandler.java | 35 ++++++++++---- .../alttd/chat/listeners/ChatListener.java | 14 +++--- .../alttd/chat/listeners/PlayerListener.java | 13 +++-- .../com/alttd/chat/util/GalaxyUtility.java | 11 ++--- .../velocitychat/handlers/ChatHandler.java | 12 +++-- 8 files changed, 118 insertions(+), 54 deletions(-) create mode 100644 api/src/main/java/com/alttd/chat/objects/ModifiableString.java diff --git a/api/src/main/java/com/alttd/chat/managers/RegexManager.java b/api/src/main/java/com/alttd/chat/managers/RegexManager.java index 7939560..61dac32 100755 --- a/api/src/main/java/com/alttd/chat/managers/RegexManager.java +++ b/api/src/main/java/com/alttd/chat/managers/RegexManager.java @@ -3,15 +3,14 @@ package com.alttd.chat.managers; import com.alttd.chat.ChatAPI; import com.alttd.chat.config.RegexConfig; import com.alttd.chat.objects.ChatFilter; +import com.alttd.chat.objects.ModifiableString; import com.alttd.chat.util.ALogger; -import net.luckperms.api.LuckPerms; import net.luckperms.api.cacheddata.CachedPermissionData; import net.luckperms.api.model.user.User; import java.util.ArrayList; import java.util.List; import java.util.UUID; -import java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexManager { @@ -29,15 +28,15 @@ public class RegexManager { chatFilters.add(filter); } - public static String replaceText(String playerName, UUID uuid, String text) { // TODO loop all objects in the list and check if they violate based on the MATCHER - return replaceText(playerName, uuid, text, true); + public static boolean filterText(String playerName, UUID uuid, ModifiableString modifiableString, String channel) { // TODO loop all objects in the list and check if they violate based on the MATCHER + return filterText(playerName, uuid, modifiableString, true, channel); } - public static String replaceText(String playerName, UUID uuid, String text, boolean matcher) { + public static boolean filterText(String playerName, UUID uuid, ModifiableString modifiableString, boolean matcher, String channel) { User user = ChatAPI.get().getLuckPerms().getUserManager().getUser(uuid); if (user == null) { ALogger.warn("Tried to check chat filters for a user who doesn't exist in LuckPerms"); - return null; + return false; } CachedPermissionData permissionData = user.getCachedData().getPermissionData(); for(ChatFilter chatFilter : chatFilters) { @@ -45,22 +44,24 @@ public class RegexManager { case CHAT: break; case REPLACE: - text = chatFilter.replaceText(text); + chatFilter.replaceText(modifiableString); break; case BLOCK: - if(chatFilter.matches(text) && !permissionData.checkPermission("chat.bypass-filter." + chatFilter.getName()).asBoolean()) { // todo find a better way to do this? + if(!permissionData.checkPermission("chat.bypass-filter-channel." + channel).asBoolean() && + !permissionData.checkPermission("chat.bypass-filter." + chatFilter.getName()).asBoolean() && + chatFilter.matches(modifiableString)) { // todo find a better way to do this? ALogger.info(playerName + " triggered the chat filter for " + chatFilter.getName() + "."); - return null; + return false; } break; case REPLACEMATCHER: if(matcher) { - text = chatFilter.replaceMatcher(text); + chatFilter.replaceMatcher(modifiableString); } break; } } - return text; + return true; } } diff --git a/api/src/main/java/com/alttd/chat/objects/ChatFilter.java b/api/src/main/java/com/alttd/chat/objects/ChatFilter.java index 352ff79..33f5953 100755 --- a/api/src/main/java/com/alttd/chat/objects/ChatFilter.java +++ b/api/src/main/java/com/alttd/chat/objects/ChatFilter.java @@ -42,34 +42,57 @@ public class ChatFilter { return this.exclusions; } - public boolean matches(String input) { + public boolean matches(ModifiableString filterableString) { + String input = filterableString.string(); Matcher matcher = pattern.matcher(input); - return (matcher.find() || matcher.matches()); + while (matcher.find()) + if (!isException(input, matcher.start())) { + filterableString.string(filterableString.string().replaceFirst(matcher.group(), "" + matcher.group() + "")); + return true; + } + return matcher.matches(); } - public String replaceText(String input) { + public boolean isException(String string, int start) + { + char[] chars = string.toCharArray(); + if (start != 0) { //go to start of word if not at start of string + while (chars[start] != ' ' && start > 0) + start--; + start += 1; //go past the space + } + + String match = string.substring(start); + for (String s : getExclusions()) { + if (match.toLowerCase().startsWith(s.toLowerCase())) + return true; + } + return false; + } + + public void replaceText(ModifiableString modifiableString) { + String input = modifiableString.string(); Matcher matcher = pattern.matcher(input); while (matcher.find()) { String group = matcher.group(); // todo debug - if(getExclusions().stream().noneMatch(s -> s.equalsIgnoreCase(group))) { // idk how heavy this is:/ - input = input.replace(group, getReplacement()); + if (getExclusions().stream().noneMatch(s -> s.equalsIgnoreCase(group))) { // idk how heavy this is:/ + modifiableString.string(input.replace(group, getReplacement())); } } - return input; } - public String replaceMatcher(String input) { - int lenght; + public void replaceMatcher(ModifiableString modifiableString) { + String input = modifiableString.string(); + int length; try { - lenght = Integer.parseInt(replacement); + length = Integer.parseInt(replacement); } catch (NumberFormatException e) { - lenght = 3; // could load this from config and make it cleaner + length = 3; // could load this from config and make it cleaner } Matcher matcher = pattern.matcher(input); while (matcher.find()) { String group = matcher.group(); - input = input.replace(group, group.substring(0, lenght)); + modifiableString.string(input.replace(group, group.substring(0, length))); } - return input; } } diff --git a/api/src/main/java/com/alttd/chat/objects/ModifiableString.java b/api/src/main/java/com/alttd/chat/objects/ModifiableString.java new file mode 100644 index 0000000..6324148 --- /dev/null +++ b/api/src/main/java/com/alttd/chat/objects/ModifiableString.java @@ -0,0 +1,17 @@ +package com.alttd.chat.objects; + +public class ModifiableString { + private String string; + + public ModifiableString(String string) { + this.string = string; + } + + public void string(String string) { + this.string = string; + } + + public String string() { + return string; + } +} diff --git a/galaxy/src/main/java/com/alttd/chat/handler/ChatHandler.java b/galaxy/src/main/java/com/alttd/chat/handler/ChatHandler.java index 81a40a0..2e20493 100755 --- a/galaxy/src/main/java/com/alttd/chat/handler/ChatHandler.java +++ b/galaxy/src/main/java/com/alttd/chat/handler/ChatHandler.java @@ -5,6 +5,7 @@ import com.alttd.chat.config.Config; import com.alttd.chat.managers.ChatUserManager; import com.alttd.chat.managers.RegexManager; import com.alttd.chat.objects.ChatUser; +import com.alttd.chat.objects.ModifiableString; import com.alttd.chat.objects.channels.CustomChannel; import com.alttd.chat.util.GalaxyUtility; import com.alttd.chat.util.Utility; @@ -36,11 +37,16 @@ public class ChatHandler { public void privateMessage(Player player, String target, String message) { // ChatUser user = ChatUserManager.getChatUser(player.getUniqueId()); // user.setReplyTarget(target); - String updatedMessage = RegexManager.replaceText(player.getName(), player.getUniqueId(), message); // todo a better way for this - if(updatedMessage == null) { - GalaxyUtility.sendBlockedNotification("DM Language", player, message, target); + ModifiableString modifiableString = new ModifiableString(message); + // todo a better way for this + if(!RegexManager.filterText(player.getName(), player.getUniqueId(), modifiableString, "privatemessage")) { + GalaxyUtility.sendBlockedNotification("DM Language", + player, + Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())), + target); return; // the message was blocked } + String updatedMessage = modifiableString.string(); if(!player.hasPermission("chat.format")) { updatedMessage = Utility.stripTokens(updatedMessage); @@ -92,12 +98,17 @@ public class ChatHandler { Component senderName = user.getDisplayName(); Component prefix = user.getPrefix(); - String updatedMessage = RegexManager.replaceText(player.getName(), player.getUniqueId(), message); // todo a better way for this - if(updatedMessage == null) { - GalaxyUtility.sendBlockedNotification("GC Language", player, message, ""); + ModifiableString modifiableString = new ModifiableString(message); + // todo a better way for this + if (!RegexManager.filterText(player.getName(), player.getUniqueId(), modifiableString, "globalchat")) { + GalaxyUtility.sendBlockedNotification("GC Language", + player, + Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())), + ""); return; // the message was blocked } + String updatedMessage = modifiableString.string(); if(!player.hasPermission("chat.format")) { updatedMessage = Utility.stripTokens(updatedMessage); } else { @@ -132,12 +143,16 @@ public class ChatHandler { ChatUser user = ChatUserManager.getChatUser(player.getUniqueId()); Component senderName = user.getDisplayName(); - String updatedMessage = RegexManager.replaceText(player.getName(), player.getUniqueId(), message); - if(updatedMessage == null) { - GalaxyUtility.sendBlockedNotification(channel.getChannelName() + " Language", player, message, ""); + ModifiableString modifiableString = new ModifiableString(message); + if(!RegexManager.filterText(player.getName(), player.getUniqueId(), modifiableString, channel.getChannelName())) { + GalaxyUtility.sendBlockedNotification(channel.getChannelName() + " Language", + player, + Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())), + ""); return; // the message was blocked } + String updatedMessage = modifiableString.string(); if(!player.hasPermission("chat.format")) { updatedMessage = Utility.stripTokens(updatedMessage); } @@ -253,7 +268,7 @@ public class ChatHandler { if (user == null) return false; if (user.isMuted() || (ChatPlugin.getInstance().serverMuted() && !player.hasPermission("chat.bypass-server-muted"))) { // if (Database.get().isPlayerMuted(player.getUniqueId(), null) || (ChatPlugin.getInstance().serverMuted() && !player.hasPermission("chat.bypass-server-muted"))) { - GalaxyUtility.sendBlockedNotification(prefix, player, message, ""); + GalaxyUtility.sendBlockedNotification(prefix, player, Utility.parseMiniMessage(Utility.stripTokens(message)), ""); return true; } return false; diff --git a/galaxy/src/main/java/com/alttd/chat/listeners/ChatListener.java b/galaxy/src/main/java/com/alttd/chat/listeners/ChatListener.java index 9953afe..ea4d6ac 100755 --- a/galaxy/src/main/java/com/alttd/chat/listeners/ChatListener.java +++ b/galaxy/src/main/java/com/alttd/chat/listeners/ChatListener.java @@ -6,6 +6,7 @@ import com.alttd.chat.handler.ChatHandler; import com.alttd.chat.managers.ChatUserManager; import com.alttd.chat.managers.RegexManager; import com.alttd.chat.objects.ChatUser; +import com.alttd.chat.objects.ModifiableString; import com.alttd.chat.util.GalaxyUtility; import com.alttd.chat.util.Utility; import io.papermc.paper.chat.ChatRenderer; @@ -13,7 +14,6 @@ import io.papermc.paper.event.player.AsyncChatEvent; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.placeholder.Replacement; -import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -44,14 +44,16 @@ public class ChatListener implements Listener, ChatRenderer { Component input = event.message(); String message = PlainTextComponentSerializer.plainText().serialize(input); - - message = RegexManager.replaceText(player.getName(), player.getUniqueId(), message); // todo a better way for this - if(message == null) { + ModifiableString modifiableString = new ModifiableString(message); + // todo a better way for this + if(!RegexManager.filterText(player.getName(), player.getUniqueId(), modifiableString, "chat")) { event.setCancelled(true); - GalaxyUtility.sendBlockedNotification("Language", player, input, ""); + GalaxyUtility.sendBlockedNotification("Language", player, + Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())), + ""); return; // the message was blocked } - + message = modifiableString.string(); if(!player.hasPermission("chat.format")) { message = Utility.stripTokens(message); } else { diff --git a/galaxy/src/main/java/com/alttd/chat/listeners/PlayerListener.java b/galaxy/src/main/java/com/alttd/chat/listeners/PlayerListener.java index 5f73526..9dd412e 100755 --- a/galaxy/src/main/java/com/alttd/chat/listeners/PlayerListener.java +++ b/galaxy/src/main/java/com/alttd/chat/listeners/PlayerListener.java @@ -4,10 +4,10 @@ import com.alttd.chat.database.Queries; import com.alttd.chat.managers.ChatUserManager; import com.alttd.chat.managers.RegexManager; import com.alttd.chat.objects.ChatUser; +import com.alttd.chat.objects.ModifiableString; import com.alttd.chat.util.GalaxyUtility; import com.alttd.chat.util.Utility; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -48,12 +48,17 @@ public class PlayerListener implements Listener { Component component = event.line(i); if (component != null) { String message = PlainTextComponentSerializer.plainText().serialize(component); + ModifiableString modifiableString = new ModifiableString(message); Player player = event.getPlayer(); - message = RegexManager.replaceText(player.getName(), player.getUniqueId(), message, false); // todo a better way for this - if (message == null) { - GalaxyUtility.sendBlockedNotification("Sign Language" , player, PlainTextComponentSerializer.plainText().serialize(component), ""); + // todo a better way for this + if (!RegexManager.filterText(player.getName(), player.getUniqueId(), modifiableString, false, "sign")) { + GalaxyUtility.sendBlockedNotification("Sign Language", + player, + Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())), + ""); } + message = modifiableString.string(); component = message == null ? Component.empty() : Component.text(message); diff --git a/galaxy/src/main/java/com/alttd/chat/util/GalaxyUtility.java b/galaxy/src/main/java/com/alttd/chat/util/GalaxyUtility.java index 68c6ede..96a9e35 100644 --- a/galaxy/src/main/java/com/alttd/chat/util/GalaxyUtility.java +++ b/galaxy/src/main/java/com/alttd/chat/util/GalaxyUtility.java @@ -3,7 +3,6 @@ package com.alttd.chat.util; import com.alttd.chat.config.Config; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.placeholder.Replacement; -import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -12,12 +11,12 @@ import java.util.HashMap; import java.util.Map; public class GalaxyUtility { - public static void sendBlockedNotification(String prefix, Player player, String input, String target) { + public static void sendBlockedNotification(String prefix, Player player, Component input, String target) { Map> placeholders = new HashMap<>(); placeholders.put("prefix", Replacement.miniMessage(prefix)); placeholders.put("displayname", Replacement.miniMessage(Utility.getDisplayName(player.getUniqueId(), player.getName()))); - placeholders.put("target", Replacement.miniMessage((target.isEmpty() ? " tried to say: " : " -> " + target + ": "))); - placeholders.put("input", Replacement.miniMessage(input)); + placeholders.put("target", Replacement.miniMessage((target.isEmpty() ? "tried to say:" : " -> " + target + ": "))); + placeholders.put("input", Replacement.component(input)); Component blockedNotification = Utility.parseMiniMessage(Config.NOTIFICATIONFORMAT, placeholders); Bukkit.getOnlinePlayers().forEach(a ->{ @@ -28,8 +27,4 @@ public class GalaxyUtility { player.sendMessage(Utility.parseMiniMessage("The language you used in your message is not allowed, " + "this constitutes as your only warning. Any further attempts at bypassing the filter will result in staff intervention.")); } - - public static void sendBlockedNotification(String prefix, Player player, Component input, String target) { - sendBlockedNotification(prefix, player, PlainTextComponentSerializer.plainText().serialize(input), target); - } } diff --git a/velocity/src/main/java/com/alttd/velocitychat/handlers/ChatHandler.java b/velocity/src/main/java/com/alttd/velocitychat/handlers/ChatHandler.java index 8124904..42509a3 100755 --- a/velocity/src/main/java/com/alttd/velocitychat/handlers/ChatHandler.java +++ b/velocity/src/main/java/com/alttd/velocitychat/handlers/ChatHandler.java @@ -7,6 +7,7 @@ import com.alttd.chat.managers.PartyManager; import com.alttd.chat.managers.RegexManager; import com.alttd.chat.objects.ChatUser; import com.alttd.chat.objects.Mail; +import com.alttd.chat.objects.ModifiableString; import com.alttd.chat.objects.Party; import com.alttd.chat.util.ALogger; import com.alttd.chat.util.Utility; @@ -116,12 +117,17 @@ public class ChatHandler { } Component senderName = user.getDisplayName(); - String updatedMessage = RegexManager.replaceText(player.getUsername(), uuid, message); - if(updatedMessage == null) { - sendBlockedNotification("Party Language", player, message, "", serverConnection); + ModifiableString modifiableString = new ModifiableString(message); + if (!RegexManager.filterText(player.getUsername(), uuid, modifiableString, "partychat")) { + sendBlockedNotification("Party Language", + player, + modifiableString.string(), + "", + serverConnection); return; // the message was blocked } + String updatedMessage = modifiableString.string(); if(!player.hasPermission("chat.format")) { updatedMessage = Utility.stripTokens(updatedMessage); }