Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de24ca4437 | ||
|
|
e351e86bea | ||
|
|
4e92285261 | ||
|
|
a377bdfe48 | ||
|
|
4af85d0e79 | ||
|
|
034de90062 | ||
|
|
bd8fa02f1e |
@@ -543,4 +543,12 @@ public final class Config {
|
||||
NICK_ALLOWED_COLOR_CODESLIST = getList("nicknames.allowed-color-codes", List.of("&0", "&1", "&2", "&3", "&4", "&5", "&6", "&7", "&8", "&9", "&a", "&b", "&c", "&d", "&e", "&f", "&r"));
|
||||
NICK_CURRENT = getString("nicknames.messages.nick-current", NICK_CURRENT);
|
||||
}
|
||||
|
||||
public static int DEATH_MESSAGES_MAX_PER_PERIOD = 5;
|
||||
public static int DEATH_MESSAGES_LIMIT_PERIOD_MINUTES = 15;
|
||||
|
||||
private static void deathMessagesSettings() {
|
||||
DEATH_MESSAGES_MAX_PER_PERIOD = getInt("death-messages.max-per-period", DEATH_MESSAGES_MAX_PER_PERIOD);
|
||||
DEATH_MESSAGES_LIMIT_PERIOD_MINUTES = getInt("death-messages.limit-period-minutes", DEATH_MESSAGES_LIMIT_PERIOD_MINUTES);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,13 +178,18 @@ public final class RegexConfig {
|
||||
String regex = entry.getValue().node("regex").getString();
|
||||
String replacement = entry.getValue().node("replacement").getString();
|
||||
List<String> exclusions = entry.getValue().node("exclusions").getList(io.leangen.geantyref.TypeToken.get(String.class), new ArrayList<>());
|
||||
boolean disableInPrivate = false;
|
||||
ConfigurationNode node = entry.getValue().node("disable-in-private");
|
||||
if (node != null) {
|
||||
disableInPrivate = node.getBoolean();
|
||||
}
|
||||
if (type == null || type.isEmpty() || regex == null || regex.isEmpty()) {
|
||||
ALogger.warn("Filter: " + name + " was set up incorrectly");
|
||||
} else {
|
||||
if (replacement == null || replacement.isEmpty()) {
|
||||
replacement = name;
|
||||
}
|
||||
ChatFilter chatFilter = new ChatFilter(name, type, regex, replacement, exclusions);
|
||||
ChatFilter chatFilter = new ChatFilter(name, type, regex, replacement, exclusions, disableInPrivate);
|
||||
RegexManager.addFilter(chatFilter);
|
||||
}
|
||||
} catch(SerializationException ex) {
|
||||
|
||||
@@ -8,10 +8,13 @@ import com.alttd.chat.objects.ModifiableString;
|
||||
import com.alttd.chat.util.ALogger;
|
||||
import net.luckperms.api.cacheddata.CachedPermissionData;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class RegexManager {
|
||||
@@ -43,17 +46,24 @@ public class RegexManager {
|
||||
}
|
||||
|
||||
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);
|
||||
return filterText(playerName, uuid, modifiableString, true, channel, null);
|
||||
}
|
||||
|
||||
public static boolean filterText(String playerName, UUID uuid, ModifiableString modifiableString, boolean matcher, String channel) {
|
||||
return filterText(playerName, uuid, modifiableString, matcher, channel, null);
|
||||
}
|
||||
|
||||
public static boolean filterText(String playerName, UUID uuid, ModifiableString modifiableString, boolean matcher, String channel, Consumer<FilterType> filterAction) {
|
||||
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 false;
|
||||
}
|
||||
CachedPermissionData permissionData = user.getCachedData().getPermissionData();
|
||||
boolean isPrivate = channel.equals("party");
|
||||
for(ChatFilter chatFilter : chatFilters) {
|
||||
if (isPrivate && chatFilter.isDisabledInPrivate())
|
||||
continue;
|
||||
switch (chatFilter.getType()) {
|
||||
case CHAT:
|
||||
break;
|
||||
@@ -74,6 +84,25 @@ public class RegexManager {
|
||||
chatFilter.replaceMatcher(modifiableString);
|
||||
}
|
||||
break;
|
||||
case PUNISH:
|
||||
if (permissionData.checkPermission("chat.bypass-punish").asBoolean())
|
||||
break;
|
||||
if (chatFilter.matches(modifiableString)) {
|
||||
ALogger.info(playerName + " triggered the punish filter for " + chatFilter.getName()
|
||||
+ " with: " + modifiableString.string() + ".");
|
||||
|
||||
if (filterAction == null){
|
||||
ALogger.info("No filterAction was provided, not doing anything");
|
||||
return false;
|
||||
}
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player == null) {
|
||||
ALogger.warn("Tried to punish a player who triggered the filter, but the player is offline.");
|
||||
return false;
|
||||
}
|
||||
filterAction.accept(FilterType.PUNISH);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -17,14 +17,16 @@ public class ChatFilter {
|
||||
private final Pattern pattern;
|
||||
private final String replacement;
|
||||
private final List<String> exclusions;
|
||||
private final boolean disableInPrivate;
|
||||
|
||||
public ChatFilter(String name, String type, String regex, String replacement, List<String> exclusions) {
|
||||
public ChatFilter(String name, String type, String regex, String replacement, List<String> exclusions, boolean disableInPrivate) {
|
||||
this.name = name;
|
||||
this.filterType = FilterType.getType(type);
|
||||
this.regex = regex;
|
||||
this.pattern = Pattern.compile(getRegex(), Pattern.CASE_INSENSITIVE);
|
||||
this.replacement = replacement;
|
||||
this.exclusions = exclusions;
|
||||
this.disableInPrivate = disableInPrivate;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -47,6 +49,10 @@ public class ChatFilter {
|
||||
return this.exclusions;
|
||||
}
|
||||
|
||||
public boolean isDisabledInPrivate() {
|
||||
return disableInPrivate;
|
||||
}
|
||||
|
||||
public boolean matches(ModifiableString filterableString) {
|
||||
String input = filterableString.string();
|
||||
Matcher matcher = pattern.matcher(input);
|
||||
|
||||
@@ -5,7 +5,8 @@ public enum FilterType {
|
||||
EMOTE("emote"),
|
||||
CHAT("chat"),
|
||||
REPLACEMATCHER("replacematcher"),
|
||||
BLOCK("block");
|
||||
BLOCK("block"),
|
||||
PUNISH("punish");
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
@@ -16,6 +16,10 @@ public class ALogger {
|
||||
logger.warn(message);
|
||||
}
|
||||
|
||||
public static void warn(String message, Throwable throwable) {
|
||||
logger.warn(message, throwable);
|
||||
}
|
||||
|
||||
public static void info(String message) {
|
||||
logger.info(message);
|
||||
}
|
||||
@@ -23,4 +27,8 @@ public class ALogger {
|
||||
public static void error(String message) {
|
||||
logger.error(message);
|
||||
}
|
||||
|
||||
public static void error(String message, Throwable throwable) {
|
||||
logger.error(message, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,12 @@ import com.alttd.chat.config.Config;
|
||||
import com.alttd.chat.handler.ChatHandler;
|
||||
import com.alttd.chat.managers.ChatUserManager;
|
||||
import com.alttd.chat.managers.RegexManager;
|
||||
import com.alttd.chat.objects.ChatFilter;
|
||||
import com.alttd.chat.objects.ChatUser;
|
||||
import com.alttd.chat.objects.ModifiableString;
|
||||
import com.alttd.chat.objects.Toggleable;
|
||||
import com.alttd.chat.objects.*;
|
||||
import com.alttd.chat.util.ALogger;
|
||||
import com.alttd.chat.util.GalaxyUtility;
|
||||
import com.alttd.chat.util.Utility;
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import io.papermc.paper.event.player.AsyncChatCommandDecorateEvent;
|
||||
import io.papermc.paper.event.player.AsyncChatDecorateEvent;
|
||||
import io.papermc.paper.event.player.AsyncChatEvent;
|
||||
@@ -87,7 +86,18 @@ public class ChatListener implements Listener {
|
||||
ModifiableString modifiableString = new ModifiableString(input);
|
||||
|
||||
// todo a better way for this
|
||||
if(!RegexManager.filterText(player.getName(), player.getUniqueId(), modifiableString, "chat")) {
|
||||
if(!RegexManager.filterText(player.getName(), player.getUniqueId(), modifiableString, true, "chat", filterType -> {
|
||||
if (!filterType.equals(FilterType.PUNISH)) {
|
||||
ALogger.warn("Received another FilterType than punish when filtering chat and executing a filter action");
|
||||
return;
|
||||
}
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF("punish");
|
||||
out.writeUTF(player.getName());
|
||||
out.writeUTF(player.getUniqueId().toString());
|
||||
out.writeUTF(modifiableString.string());
|
||||
player.sendPluginMessage(ChatPlugin.getInstance(), Config.MESSAGECHANNEL, out.toByteArray());
|
||||
})) {
|
||||
event.setCancelled(true);
|
||||
GalaxyUtility.sendBlockedNotification("Language", player,
|
||||
modifiableString.component(),
|
||||
|
||||
@@ -11,15 +11,25 @@ import com.alttd.chat.objects.Toggleable;
|
||||
import com.alttd.chat.util.GalaxyUtility;
|
||||
import com.alttd.chat.util.Utility;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.SignChangeEvent;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.HashMap;
|
||||
import java.util.Stack;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -86,4 +96,29 @@ public class PlayerListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private final HashMap<UUID, Stack<Instant>> sendPlayerDeaths = new HashMap<>();
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onPlayerDeath(@NotNull PlayerDeathEvent event) {
|
||||
UUID uuid = event.getPlayer().getUniqueId();
|
||||
Stack<Instant> playerDeathsStack = sendPlayerDeaths.computeIfAbsent(uuid, key -> new Stack<>());
|
||||
Instant cutOff = Instant.now().minus(Config.DEATH_MESSAGES_LIMIT_PERIOD_MINUTES, ChronoUnit.MINUTES);
|
||||
|
||||
while (playerDeathsStack.peek().isBefore(cutOff)) {
|
||||
playerDeathsStack.pop();
|
||||
}
|
||||
|
||||
if (playerDeathsStack.size() > Config.DEATH_MESSAGES_MAX_PER_PERIOD || serverConfig.MUTED) {
|
||||
event.deathMessage(Component.empty());
|
||||
return;
|
||||
} else {
|
||||
Component component = event.deathMessage();
|
||||
if (component != null) {
|
||||
component = Component.text("* ").append(component);
|
||||
component = component.style(Style.style(TextColor.color(82, 80, 77), TextDecoration.ITALIC));
|
||||
event.deathMessage(component);
|
||||
}
|
||||
}
|
||||
playerDeathsStack.push(Instant.now());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,11 +4,14 @@ import com.alttd.chat.managers.ChatUserManager;
|
||||
import com.alttd.chat.objects.ChatUser;
|
||||
import com.alttd.chat.objects.channels.CustomChannel;
|
||||
import com.alttd.chat.util.ALogger;
|
||||
import com.alttd.proxydiscordlink.DiscordLink;
|
||||
import com.alttd.proxydiscordlink.lib.net.dv8tion.jda.api.EmbedBuilder;
|
||||
import com.alttd.velocitychat.VelocityChat;
|
||||
import com.google.common.io.ByteArrayDataInput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
||||
import com.velocitypowered.api.proxy.ConsoleCommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
@@ -16,8 +19,10 @@ import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PluginMessageListener {
|
||||
@@ -93,6 +98,20 @@ public class PluginMessageListener {
|
||||
proxy.getAllServers().forEach(registeredServer ->
|
||||
registeredServer.sendPluginMessage(VelocityChat.getPlugin().getChannelIdentifier(), event.getData()));
|
||||
}
|
||||
case "punish" -> {
|
||||
String playerName = in.readUTF();
|
||||
ProxyServer proxy = VelocityChat.getPlugin().getProxy();
|
||||
ConsoleCommandSource consoleCommandSource = proxy.getConsoleCommandSource();
|
||||
proxy.getCommandManager().executeAsync(consoleCommandSource, String.format("ban %s Automatic ban, please appeal if you feel review is needed.", playerName));
|
||||
ALogger.info(String.format("Auto banned %s due to violating the `punish` filter.", playerName));
|
||||
|
||||
EmbedBuilder embedBuilder = new EmbedBuilder();
|
||||
embedBuilder.setTitle("Automatic ban through the chat filter");
|
||||
embedBuilder.setAuthor(playerName, null, "https://crafatar.com/avatars/" + in.readUTF() + "?overlay");
|
||||
embedBuilder.setDescription(String.format("`%s`\n\n Auto permanent ban\n\n Auto banned for violating the `punish` chat filter. This could be a false positive! Their message was\n||%s||", playerName, in.readUTF()));
|
||||
embedBuilder.setColor(Color.RED);
|
||||
DiscordLink.getPlugin().getBot().sendEmbedToDiscord(514922317923614728L, embedBuilder, -1);
|
||||
}
|
||||
default -> {
|
||||
VelocityChat.getPlugin().getLogger().info("server " + event.getSource());
|
||||
ProxyServer proxy = VelocityChat.getPlugin().getProxy();
|
||||
|
||||
Reference in New Issue
Block a user