From dc6942197ea0c6b9ebbe11fcc32a8963d7bffa21 Mon Sep 17 00:00:00 2001 From: ThatGamerBlue Date: Wed, 4 Mar 2020 01:54:32 +0000 Subject: [PATCH] chatfilter: add filtering by username --- .../plugins/chatfilter/ChatFilterConfig.java | 17 +- .../plugins/chatfilter/ChatFilterPlugin.java | 71 ++++++-- .../chatfilter/ChatFilterPluginTest.java | 156 +++++++++++++++++- 3 files changed, 218 insertions(+), 26 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterConfig.java index dbdb4d6478..253afd7e18 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterConfig.java @@ -65,11 +65,22 @@ public interface ChatFilterConfig extends Config return ""; } + @ConfigItem( + keyName = "filteredNames", + name = "Filtered Names", + description = "List of filtered names, one per line. Accepts regular expressions", + position = 4 + ) + default String filteredNames() + { + return ""; + } + @ConfigItem( keyName = "filterFriends", name = "Filter Friends", description = "Filter your friends' messages", - position = 4 + position = 5 ) default boolean filterFriends() { @@ -80,7 +91,7 @@ public interface ChatFilterConfig extends Config keyName = "filterClan", name = "Filter Clan Chat Members", description = "Filter your clan chat members' messages", - position = 5 + position = 6 ) default boolean filterClan() { @@ -91,7 +102,7 @@ public interface ChatFilterConfig extends Config keyName = "filterLogin", name = "Filter Logged In/Out Messages", description = "Filter your private chat to remove logged in/out messages", - position = 6 + position = 7 ) default boolean filterLogin() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java index fe8fdb18f4..d78f2c8bcd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java @@ -25,6 +25,7 @@ */ package net.runelite.client.plugins.chatfilter; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.CharMatcher; import com.google.common.base.Splitter; import com.google.inject.Provides; @@ -62,10 +63,12 @@ public class ChatFilterPlugin extends Plugin .omitEmptyStrings() .trimResults(); - private static final String CENSOR_MESSAGE = "Hey, everyone, I just tried to say something very silly!"; + @VisibleForTesting + static final String CENSOR_MESSAGE = "Hey, everyone, I just tried to say something very silly!"; private final CharMatcher jagexPrintableCharMatcher = Text.JAGEX_PRINTABLE_CHAR_MATCHER; private final List filteredPatterns = new ArrayList<>(); + private final List filteredNamePatterns = new ArrayList<>(); @Inject private Client client; @@ -143,7 +146,7 @@ public class ChatFilterPlugin extends Plugin int stringStackSize = client.getStringStackSize(); String message = stringStack[stringStackSize - 1]; - String censoredMessage = censorMessage(message); + String censoredMessage = censorMessage(name, message); if (censoredMessage == null) { @@ -165,7 +168,7 @@ public class ChatFilterPlugin extends Plugin return; } - String message = censorMessage(event.getOverheadText()); + String message = censorMessage(event.getActor().getName(), event.getOverheadText()); if (message == null) { @@ -183,10 +186,23 @@ public class ChatFilterPlugin extends Plugin (config.filterClan() || !clanManager.isClanMember(playerName)); } - String censorMessage(final String message) + String censorMessage(final String username, final String message) { String strippedMessage = jagexPrintableCharMatcher.retainFrom(message) .replace('\u00A0', ' '); + if (shouldFilterByName(username)) + { + switch (config.filterType()) + { + case CENSOR_WORDS: + return StringUtils.repeat('*', strippedMessage.length()); + case CENSOR_MESSAGE: + return CENSOR_MESSAGE; + case REMOVE_MESSAGE: + return null; + } + } + boolean filtered = false; for (Pattern pattern : filteredPatterns) { @@ -199,7 +215,7 @@ public class ChatFilterPlugin extends Plugin switch (config.filterType()) { case CENSOR_WORDS: - m.appendReplacement(sb, StringUtils.repeat("*", m.group(0).length())); + m.appendReplacement(sb, StringUtils.repeat('*', m.group(0).length())); filtered = true; break; case CENSOR_MESSAGE: @@ -219,25 +235,33 @@ public class ChatFilterPlugin extends Plugin void updateFilteredPatterns() { filteredPatterns.clear(); + filteredNamePatterns.clear(); Text.fromCSV(config.filteredWords()).stream() .map(s -> Pattern.compile(Pattern.quote(s), Pattern.CASE_INSENSITIVE)) .forEach(filteredPatterns::add); NEWLINE_SPLITTER.splitToList(config.filteredRegex()).stream() - .map(s -> - { - try - { - return Pattern.compile(s, Pattern.CASE_INSENSITIVE); - } - catch (PatternSyntaxException ex) - { - return null; - } - }) + .map(ChatFilterPlugin::compilePattern) .filter(Objects::nonNull) .forEach(filteredPatterns::add); + + NEWLINE_SPLITTER.splitToList(config.filteredNames()).stream() + .map(ChatFilterPlugin::compilePattern) + .filter(Objects::nonNull) + .forEach(filteredNamePatterns::add); + } + + private static Pattern compilePattern(String pattern) + { + try + { + return Pattern.compile(pattern, Pattern.CASE_INSENSITIVE); + } + catch (PatternSyntaxException ex) + { + return null; + } } @Subscribe @@ -253,4 +277,19 @@ public class ChatFilterPlugin extends Plugin //Refresh chat after config change to reflect current rules client.refreshChat(); } + + @VisibleForTesting + boolean shouldFilterByName(final String playerName) + { + String sanitizedName = Text.standardize(playerName); + for (Pattern pattern : filteredNamePatterns) + { + Matcher m = pattern.matcher(sanitizedName); + if (m.find()) + { + return true; + } + } + return false; + } } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java index 949bac892d..07a45e7a29 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java @@ -29,9 +29,14 @@ import com.google.inject.Guice; import com.google.inject.testing.fieldbinder.Bind; import com.google.inject.testing.fieldbinder.BoundFieldModule; import javax.inject.Inject; +import net.runelite.api.ChatMessageType; import net.runelite.api.Client; +import net.runelite.api.IterableHashTable; +import net.runelite.api.MessageNode; import net.runelite.api.Player; +import net.runelite.api.events.ScriptCallbackEvent; import net.runelite.client.game.ClanManager; +import static net.runelite.client.plugins.chatfilter.ChatFilterPlugin.CENSOR_MESSAGE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -40,6 +45,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import org.mockito.junit.MockitoJUnitRunner; @@ -72,16 +78,43 @@ public class ChatFilterPluginTest when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_WORDS); when(chatFilterConfig.filteredWords()).thenReturn(""); when(chatFilterConfig.filteredRegex()).thenReturn(""); + when(chatFilterConfig.filteredNames()).thenReturn(""); when(client.getLocalPlayer()).thenReturn(localPlayer); } + private ScriptCallbackEvent createCallbackEvent(final String sender, final String chatMessage, final ChatMessageType messageType) + { + ScriptCallbackEvent event = new ScriptCallbackEvent(); + event.setScript(null); + event.setEventName("chatFilterCheck"); + int[] simulatedIntStack = + new int[]{1, messageType.getType(), 1}; // is msg allowed to show, ChatMessageType.PUBLICCHAT, message id + String[] simulatedStringStack = new String[]{chatMessage}; + IterableHashTable messageTable = mock(IterableHashTable.class); + MessageNode mockedMsgNode = mockMessageNode(sender); + when(client.getIntStack()).thenReturn(simulatedIntStack); + when(client.getIntStackSize()).thenReturn(simulatedIntStack.length); + when(client.getStringStack()).thenReturn(simulatedStringStack); + when(client.getStringStackSize()).thenReturn(simulatedStringStack.length); + when(client.getMessages()).thenReturn(messageTable); + when(messageTable.get(1)).thenReturn(mockedMsgNode); + return event; + } + + private MessageNode mockMessageNode(String sender) + { + MessageNode node = mock(MessageNode.class); + when(node.getName()).thenReturn(sender); + return node; + } + @Test public void testCensorWords() { when(chatFilterConfig.filteredWords()).thenReturn("hat"); chatFilterPlugin.updateFilteredPatterns(); - assertEquals("w***s up", chatFilterPlugin.censorMessage("whats up")); + assertEquals("w***s up", chatFilterPlugin.censorMessage("Blue", "whats up")); } @Test @@ -91,7 +124,7 @@ public class ChatFilterPluginTest when(chatFilterConfig.filteredRegex()).thenReturn("5[0-9]x2\n("); chatFilterPlugin.updateFilteredPatterns(); - assertNull(chatFilterPlugin.censorMessage("55X2 Dicing | Trusted Ranks | Huge Pay Outs!")); + assertNull(chatFilterPlugin.censorMessage("Blue", "55X2 Dicing | Trusted Ranks | Huge Pay Outs!")); } @Test @@ -100,7 +133,7 @@ public class ChatFilterPluginTest when(chatFilterConfig.filteredRegex()).thenReturn("Test\n)\n73"); chatFilterPlugin.updateFilteredPatterns(); - assertEquals("** isn't funny", chatFilterPlugin.censorMessage("73 isn't funny")); + assertEquals("** isn't funny", chatFilterPlugin.censorMessage("Blue", "73 isn't funny")); } @Test @@ -110,8 +143,7 @@ public class ChatFilterPluginTest when(chatFilterConfig.filteredWords()).thenReturn("ReGeX!!!"); chatFilterPlugin.updateFilteredPatterns(); - assertEquals("Hey, everyone, I just tried to say something very silly!", - chatFilterPlugin.censorMessage("I love regex!!!!!!!!")); + assertEquals(CENSOR_MESSAGE, chatFilterPlugin.censorMessage("Blue", "I love regex!!!!!!!!")); } @Test @@ -121,7 +153,7 @@ public class ChatFilterPluginTest when(chatFilterConfig.filteredWords()).thenReturn("test"); chatFilterPlugin.updateFilteredPatterns(); - assertNull(chatFilterPlugin.censorMessage("te\u008Cst")); + assertNull(chatFilterPlugin.censorMessage("Blue", "te\u008Cst")); } @Test @@ -131,7 +163,7 @@ public class ChatFilterPluginTest when(chatFilterConfig.filteredWords()).thenReturn("hello osrs"); chatFilterPlugin.updateFilteredPatterns(); - assertNull(chatFilterPlugin.censorMessage("hello\u00A0osrs")); + assertNull(chatFilterPlugin.censorMessage("Blue", "hello\u00A0osrs")); } @Test @@ -180,4 +212,114 @@ public class ChatFilterPluginTest when(clanManager.isClanMember("Woox")).thenReturn(false); assertTrue(chatFilterPlugin.shouldFilterPlayerMessage("Woox")); } + + @Test + public void testShouldFilterByName() + { + when(chatFilterConfig.filteredNames()).thenReturn("Gamble [0-9]*"); + + chatFilterPlugin.updateFilteredPatterns(); + assertTrue(chatFilterPlugin.shouldFilterByName("Gamble 1234")); + assertFalse(chatFilterPlugin.shouldFilterByName("Adam")); + } + + @Test + public void testCensorWordsByName() + { + when(chatFilterConfig.filteredNames()).thenReturn("Blue"); + chatFilterPlugin.updateFilteredPatterns(); + assertEquals("************", chatFilterPlugin.censorMessage("Blue", "Gamble today")); + } + + @Test + public void textCensorMessageByName() + { + when(chatFilterConfig.filteredNames()).thenReturn("Blue"); + chatFilterPlugin.updateFilteredPatterns(); + when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_MESSAGE); + assertEquals(CENSOR_MESSAGE, + chatFilterPlugin.censorMessage("Blue", "Meet swampletics, my morytania locked ultimate ironman")); + } + + @Test + public void testRemoveMessageByName() + { + when(chatFilterConfig.filteredNames()).thenReturn("Blue"); + chatFilterPlugin.updateFilteredPatterns(); + when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.REMOVE_MESSAGE); + assertNull( + chatFilterPlugin.censorMessage("Blue", "What about now it's time to rock with the biggity buck bumble")); + } + + @Test + public void testEventRemoveByName() + { + when(chatFilterConfig.filteredNames()).thenReturn("Gamble [0-9]*"); + when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.REMOVE_MESSAGE); + + chatFilterPlugin.updateFilteredPatterns(); + ScriptCallbackEvent event = createCallbackEvent("Gamble 1234", "filterme", ChatMessageType.PUBLICCHAT); + chatFilterPlugin.onScriptCallbackEvent(event); + assertEquals(0, client.getIntStack()[client.getIntStackSize() - 3]); + } + + @Test + public void testEventRemoveByText() + { + when(chatFilterConfig.filteredWords()).thenReturn("filterme"); + when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.REMOVE_MESSAGE); + + chatFilterPlugin.updateFilteredPatterns(); + ScriptCallbackEvent event = createCallbackEvent("Adam", "please filterme plugin", ChatMessageType.PUBLICCHAT); + chatFilterPlugin.onScriptCallbackEvent(event); + assertEquals(0, client.getIntStack()[client.getIntStackSize() - 3]); + } + + @Test + public void testEventCensorWordsByName() + { + when(chatFilterConfig.filteredNames()).thenReturn("Gamble [0-9]*"); + when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_WORDS); + + chatFilterPlugin.updateFilteredPatterns(); + ScriptCallbackEvent event = createCallbackEvent("Gamble 1234", "filterme", ChatMessageType.PUBLICCHAT); + chatFilterPlugin.onScriptCallbackEvent(event); + assertEquals("********", client.getStringStack()[client.getStringStackSize() - 1]); + } + + @Test + public void testEventCensorWordsByText() + { + when(chatFilterConfig.filteredWords()).thenReturn("filterme"); + when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_WORDS); + + chatFilterPlugin.updateFilteredPatterns(); + ScriptCallbackEvent event = createCallbackEvent("Adam", "please filterme plugin", ChatMessageType.PUBLICCHAT); + chatFilterPlugin.onScriptCallbackEvent(event); + assertEquals("please ******** plugin", client.getStringStack()[client.getStringStackSize() - 1]); + } + + @Test + public void testEventCensorMessageByName() + { + when(chatFilterConfig.filteredNames()).thenReturn("Gamble [0-9]*"); + when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_MESSAGE); + + chatFilterPlugin.updateFilteredPatterns(); + ScriptCallbackEvent event = createCallbackEvent("Gamble 1234", "filterme", ChatMessageType.PUBLICCHAT); + chatFilterPlugin.onScriptCallbackEvent(event); + assertEquals(CENSOR_MESSAGE, client.getStringStack()[client.getStringStackSize() - 1]); + } + + @Test + public void testEventCensorMessageByText() + { + when(chatFilterConfig.filteredWords()).thenReturn("filterme"); + when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_MESSAGE); + + chatFilterPlugin.updateFilteredPatterns(); + ScriptCallbackEvent event = createCallbackEvent("Adam", "please filterme plugin", ChatMessageType.PUBLICCHAT); + chatFilterPlugin.onScriptCallbackEvent(event); + assertEquals(CENSOR_MESSAGE, client.getStringStack()[client.getStringStackSize() - 1]); + } } \ No newline at end of file