diff --git a/build.gradle b/build.gradle index ddde3ef..9fd44c2 100644 --- a/build.gradle +++ b/build.gradle @@ -2,8 +2,8 @@ plugins { id 'java' } -group = 'io.github.thetrouper' -version = '0.0.2' +group = project.group +version = project.version repositories { mavenCentral() @@ -18,7 +18,7 @@ repositories { } dependencies { - compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT' + compileOnly "org.spigotmc:spigot-api:${project.mc_version}-R0.1-SNAPSHOT" } def targetJavaVersion = 16 diff --git a/gradle.properties b/gradle.properties index e69de29..934c46b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -0,0 +1,8 @@ + +# Plugin +group = 'io.github.thetrouper' +version = 0.0.3 + +# Minecraft +mc_version = 1.19.4 + diff --git a/src/main/java/io/github/thetrouper/sentinel/Sentinel.java b/src/main/java/io/github/thetrouper/sentinel/Sentinel.java index fc1479b..09e4590 100644 --- a/src/main/java/io/github/thetrouper/sentinel/Sentinel.java +++ b/src/main/java/io/github/thetrouper/sentinel/Sentinel.java @@ -20,6 +20,7 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import java.io.File; import java.util.List; import java.util.logging.Logger; @@ -42,7 +43,7 @@ public final class Sentinel extends JavaPlugin { // Files getConfig().options().copyDefaults(); - saveDefaultConfig(); + saveDefaultConfig(); // Plugin startup logic Config.loadConfiguration(); @@ -67,6 +68,7 @@ public final class Sentinel extends JavaPlugin { // Scheduled timers Bukkit.getScheduler().runTaskTimer(this, AntiSpam::decayHeat,0, 20); + Bukkit.getScheduler().runTaskTimer(this, ProfanityFilter::decayScore,0,1200); log.info("\n" + " ____ __ ___ \n" + "/\\ _`\\ /\\ \\__ __ /\\_ \\ \n" + @@ -86,7 +88,9 @@ public final class Sentinel extends JavaPlugin { // Plugin shutdown logic log.info("Sentinel has disabled! (" + getDescription().getVersion() + ") Your server is now no longer protected!"); } - + public static File getDF() { + return getInstance().getDataFolder(); + } /** * Checks if a player is trusted. diff --git a/src/main/java/io/github/thetrouper/sentinel/commands/InfoCommand.java b/src/main/java/io/github/thetrouper/sentinel/commands/InfoCommand.java index 10a4b1b..7920583 100644 --- a/src/main/java/io/github/thetrouper/sentinel/commands/InfoCommand.java +++ b/src/main/java/io/github/thetrouper/sentinel/commands/InfoCommand.java @@ -4,15 +4,18 @@ package io.github.thetrouper.sentinel.commands; +import io.github.thetrouper.sentinel.Sentinel; +import io.github.thetrouper.sentinel.data.Config; import io.github.thetrouper.sentinel.discord.WebhookSender; import io.github.thetrouper.sentinel.exceptions.CmdExHandler; import io.github.thetrouper.sentinel.server.functions.AntiSpam; +import io.github.thetrouper.sentinel.server.util.FileUtils; import io.github.thetrouper.sentinel.server.util.ServerUtils; import io.github.thetrouper.sentinel.server.util.TextUtils; import org.bukkit.Bukkit; import org.bukkit.command.*; +import org.bukkit.entity.Player; -import java.util.ArrayList; import java.util.List; /** @@ -35,7 +38,6 @@ public class InfoCommand implements TabExecutor { case "webhooktest" -> { sender.sendMessage(TextUtils.prefix("Testing the webhook...")); WebhookSender.sendEmbedWarning(sender.getName(), "/sentinel webhooktest",true,true,false); - WebhookSender.sendHelloWorldEmbed(); } case "checkheat" -> { sender.sendMessage(TextUtils.prefix("Your heat is §e" + AntiSpam.heatMap.get(sender).toString())); @@ -44,6 +46,16 @@ public class InfoCommand implements TabExecutor { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "say " + " ]=- Sentinel Anti-Grief -=[ You have been banned for attempting a dangerous command. Contact an administrator if you believe this to be a mistake."); ServerUtils.sendCommand("say test complete!"); } + case "pastebintest" -> { + WebhookSender.sendTestEmbed(); + } + case "filetest" -> { + sender.sendMessage(TextUtils.prefix("testing file stuff")); + if (!FileUtils.folderExists("/LoggedNBT")) { + FileUtils.createFolder("/LoggedNBT"); + } + FileUtils.createNBTLog("{[IDFK MINECRAFT NBT LMAO]}; [][]\\ima just fill this with text to test it. ()()() ||||| &^%$#@!@#$%^&*(){}|:\"\"<><>"); + } } return true; } catch (Exception ex) { @@ -61,7 +73,9 @@ public class InfoCommand implements TabExecutor { "debugmode", "webhooktest", "checkheat", - "dispatchtest" + "dispatchtest", + "pastebintest", + "filetest" }).build(); } } diff --git a/src/main/java/io/github/thetrouper/sentinel/data/Config.java b/src/main/java/io/github/thetrouper/sentinel/data/Config.java index aba263e..a769e17 100644 --- a/src/main/java/io/github/thetrouper/sentinel/data/Config.java +++ b/src/main/java/io/github/thetrouper/sentinel/data/Config.java @@ -27,6 +27,7 @@ public abstract class Config { } } public static String webhook; + public static String pbapikey; public static List trustedPlayers; public static boolean blockSpecificCommands; public static boolean preventNBT; @@ -49,6 +50,8 @@ public abstract class Config { public static int blockHeat; public static int punishHeat; public static String punishSpamCommand; + public static String clearChatCommand; + public static boolean clearChat; public static boolean logSpam; public static boolean antiSwearEnabled; public static int lowScore; @@ -60,6 +63,7 @@ public abstract class Config { public static String swearPunishCommand; public static boolean slurInstaPunish; public static String slurPunishCommand; + public static Integer scoreDecay; public static List swearWhitelist; public static List swearBlacklist; public static List slurs; @@ -71,6 +75,7 @@ public abstract class Config { Sentinel.prefix = config.getString("config.plugin.prefix"); // antiNuke webhook = config.getString("config.plugin.webhook"); + pbapikey = config.getString("config.plugin.pbapikey"); trustedPlayers = config.getStringList("config.plugin.trusted"); blockSpecificCommands = config.getBoolean("config.plugin.block-specific"); preventNBT = config.getBoolean("config.plugin.prevent-nbt"); @@ -93,23 +98,27 @@ public abstract class Config { blockHeat = config.getInt("config.chat.anti-spam.block-heat"); punishHeat = config.getInt("config.chat.anti-spam.punish-heat"); punishSpamCommand = config.getString("config.chat.anti-spam.punish-command"); + clearChat = config.getBoolean("config.chat.anti-spam.clear-chat"); + clearChatCommand = config.getString("config.chat.anti-spam.clear-chat-command"); logSpam = config.getBoolean("config.chat.anti-swear.log-swear"); // antiSwear antiSwearEnabled = config.getBoolean("config.chat.anti-swear.enabled"); - lowScore = config.getInt("config.chat.anti-swear.low-gain"); - mediumLowScore = config.getInt("config.chat.anti-swear.medium-low-gain"); - mediumScore = config.getInt("config.chat.anti-swear.medium-gain"); - mediumHighScore = config.getInt("config.chat.anti-swear.medium-high-gain"); - highScore = config.getInt("config.chat.anti-swear.high-gain"); + lowScore = config.getInt("config.chat.anti-swear.low-score"); + mediumLowScore = config.getInt("config.chat.anti-swear.medium-low-score"); + mediumScore = config.getInt("config.chat.anti-swear.medium-score"); + mediumHighScore = config.getInt("config.chat.anti-swear.medium-high-score"); + highScore = config.getInt("config.chat.anti-swear.high-score"); punishScore = config.getInt("config.chat.anti-swear.punish-score"); swearPunishCommand = config.getString("config.chat.anti-swear.punish-command"); slurInstaPunish = config.getBoolean("config.chat.anti-swear.slur-insta-punish"); slurPunishCommand = config.getString("config.chat.anti-swear.slur-command"); + scoreDecay = config.getInt("config.chat.anti-swear.score-decay"); swearWhitelist = config.getStringList("config.chat.anti-swear.whitelisted"); swearBlacklist = config.getStringList("config.chat.anti-swear.blacklisted"); slurs = config.getStringList("config.chat.anti-swear.slurs"); leetPatterns = loadLeetPatterns(); logSwear = config.getBoolean("config.chat.anti-swear.log-swear"); + } private static Map loadLeetPatterns() { Map dictionary = new HashMap<>(); diff --git a/src/main/java/io/github/thetrouper/sentinel/data/Emojis.java b/src/main/java/io/github/thetrouper/sentinel/data/Emojis.java index 15d05d0..88a332f 100644 --- a/src/main/java/io/github/thetrouper/sentinel/data/Emojis.java +++ b/src/main/java/io/github/thetrouper/sentinel/data/Emojis.java @@ -1,6 +1,7 @@ package io.github.thetrouper.sentinel.data; public class Emojis { + public static String space = "<:space:1125871914334818446>"; public static String rightSort = "<:rightSort:1125785837255270520>"; public static String arrowRight = "<:arrowRight:1125785471520354304>"; public static String rightDoubleArrow = "<:rightDoubleArrow:1125785800353783868>"; diff --git a/src/main/java/io/github/thetrouper/sentinel/discord/DiscordWebhook.java b/src/main/java/io/github/thetrouper/sentinel/discord/DiscordWebhook.java index 96f9f02..8e48b24 100644 --- a/src/main/java/io/github/thetrouper/sentinel/discord/DiscordWebhook.java +++ b/src/main/java/io/github/thetrouper/sentinel/discord/DiscordWebhook.java @@ -2,10 +2,10 @@ package io.github.thetrouper.sentinel.discord; import javax.net.ssl.HttpsURLConnection; import java.awt.Color; -import java.io.IOException; -import java.io.OutputStream; +import java.io.*; import java.lang.reflect.Array; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -23,6 +23,7 @@ public class DiscordWebhook { private String avatarUrl; private boolean tts; private List embeds = new ArrayList<>(); + private List attachments = new ArrayList<>(); /** * Constructs a new DiscordWebhook instance @@ -53,9 +54,13 @@ public class DiscordWebhook { this.embeds.add(embed); } + public void addAttachment(String filename, String content) { + attachments.add(new Attachment(filename, content)); + } + public void execute() throws IOException { - if (this.content == null && this.embeds.isEmpty()) { - throw new IllegalArgumentException("Set content or add at least one EmbedObject"); + if (this.content == null && this.embeds.isEmpty() && this.attachments.isEmpty()) { + throw new IllegalArgumentException("Set content, add at least one EmbedObject, or add an attachment"); } JSONObject json = new JSONObject(); @@ -139,6 +144,19 @@ public class DiscordWebhook { json.put("embeds", embedObjects.toArray()); } + if (!this.attachments.isEmpty()) { + List attachmentObjects = new ArrayList<>(); + + for (Attachment attachment : this.attachments) { + JSONObject attachmentObject = new JSONObject(); + attachmentObject.put("name", attachment.getFilename()); + attachmentObject.put("content", attachment.getContent()); + attachmentObjects.add(attachmentObject); + } + + json.put("attachments", attachmentObjects.toArray()); + } + URL url = new URL(this.url); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.addRequestProperty("Content-Type", "application/json"); @@ -339,6 +357,24 @@ public class DiscordWebhook { } } + private class Attachment { + private String filename; + private String content; + + private Attachment(String filename, String content) { + this.filename = filename; + this.content = content; + } + + private String getFilename() { + return filename; + } + + private String getContent() { + return content; + } + } + private class JSONObject { private final HashMap map = new HashMap<>(); @@ -387,4 +423,4 @@ public class DiscordWebhook { return "\"" + string + "\""; } } -} \ No newline at end of file +} diff --git a/src/main/java/io/github/thetrouper/sentinel/discord/WebhookSender.java b/src/main/java/io/github/thetrouper/sentinel/discord/WebhookSender.java index c0e9911..3e27e25 100644 --- a/src/main/java/io/github/thetrouper/sentinel/discord/WebhookSender.java +++ b/src/main/java/io/github/thetrouper/sentinel/discord/WebhookSender.java @@ -1,40 +1,125 @@ package io.github.thetrouper.sentinel.discord; import io.github.thetrouper.sentinel.Sentinel; -import io.github.thetrouper.sentinel.commands.InfoCommand; import io.github.thetrouper.sentinel.data.Config; import io.github.thetrouper.sentinel.data.Emojis; -import io.github.thetrouper.sentinel.discord.DiscordWebhook; +import io.github.thetrouper.sentinel.server.functions.ProfanityFilter; +import io.github.thetrouper.sentinel.server.util.FileUtils; import io.github.thetrouper.sentinel.server.util.ServerUtils; import io.github.thetrouper.sentinel.server.util.TextUtils; +import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import java.awt.Color; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; public class WebhookSender { - public static void sendHelloWorldEmbed() { + public static void sendTestEmbed() { String webhookUrl = Config.webhook; - // Create a new DiscordWebhook instance DiscordWebhook webhook = new DiscordWebhook(webhookUrl); // Create an EmbedObject and set its properties DiscordWebhook.EmbedObject embed = new DiscordWebhook.EmbedObject() - .setDescription("Hello, World!") + .setAuthor("Test Success!", "", "") + .setDescription("eeeee") .setColor(Color.GREEN); - - // Add the EmbedObject to the webhook webhook.addEmbed(embed); - + webhook.addAttachment("text.txt","Text Here hehehehaw!"); try { - // Execute the webhook webhook.execute(); } catch (IOException e) { - e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public static void sendSpamLog(Player player, String message1, String message2, int finalHeat, boolean chatCleared) { + ServerUtils.sendDebugMessage("Creating spamLog Webhook..."); + DiscordWebhook webhook = new DiscordWebhook(Config.webhook); + webhook.setAvatarUrl("https://r2.e-z.host/d440b58a-ba90-4839-8df6-8bba298cf817/3lwit5nt.png"); + webhook.setUsername("Sentinel Anti-Nuke | Logs"); + DiscordWebhook.EmbedObject embed = new DiscordWebhook.EmbedObject() + .setAuthor("Anti-Spam Punishment","","") + .setTitle("Punish Report:") + .setDescription( + Emojis.rightSort + "Player: " + player.getName() + " " + Emojis.target + "\\n" + + Emojis.space + Emojis.arrowRight + "Heat: `" + finalHeat + "/" + Config.punishHeat + "`\\n" + + Emojis.space + Emojis.arrowRight + "UUID: `" + player.getUniqueId() + "`\\n" + + Emojis.rightSort + "Executed: " + Config.punishSpamCommand + " " + Emojis.mute + "\\n" + + Emojis.space + Emojis.arrowRight + "Chat Cleared: " + successOrFail(chatCleared) + "\\n" + ) + .addField("Previous Message", "||" + message1 + "|| " + Emojis.activity, false) + .addField("Current Message", "||" + message2 + "|| " + Emojis.alarm, false) + .setColor(Color.RED) + .setThumbnail("https://crafatar.com/avatars/" + player.getUniqueId() + "?size=64&&overlay"); + webhook.addEmbed(embed); + try { + ServerUtils.sendDebugMessage("Executing webhook..."); + webhook.execute(); + } catch (IOException e) { + ServerUtils.sendDebugMessage(TextUtils.prefix("Epic webhook failure!!!")); + Sentinel.log.info(e.toString()); + } + } + public static void sendSwearLog(Player player, String message, int finalScore) { + ServerUtils.sendDebugMessage("Creating swearLog Webhook..."); + DiscordWebhook webhook = new DiscordWebhook(Config.webhook); + webhook.setAvatarUrl("https://r2.e-z.host/d440b58a-ba90-4839-8df6-8bba298cf817/3lwit5nt.png"); + webhook.setUsername("Sentinel Anti-Nuke | Logs"); + DiscordWebhook.EmbedObject embed = new DiscordWebhook.EmbedObject() + .setAuthor("Anti-Swear Punishment","","") + .setTitle("Punish Report:") + .setDescription( + Emojis.rightSort + "Player: " + player.getName() + " " + Emojis.target + "\\n" + + Emojis.space + Emojis.arrowRight + "Score: `" + finalScore + "/" + Config.punishScore + "`\\n" + + Emojis.space + Emojis.arrowRight + "UUID: `" + player.getUniqueId() + "`\\n" + + Emojis.rightSort + "Executed: " + Config.swearPunishCommand + " " + Emojis.mute + "\\n" + ) + .addField("Original Message", "||" + message + "|| " + Emojis.alarm, false) + .addField("Sanitized Message", ProfanityFilter.highlightProfanity(message,"||", "||") + " " + Emojis.noDM, false) + .setColor(Color.orange) + .setThumbnail("https://crafatar.com/avatars/" + player.getUniqueId() + "?size=64&&overlay"); + webhook.addEmbed(embed); + try { + ServerUtils.sendDebugMessage("Executing webhook..."); + webhook.execute(); + } catch (IOException e) { + ServerUtils.sendDebugMessage(TextUtils.prefix("Epic webhook failure!!!")); + Sentinel.log.info(e.toString()); + } + } + public static void sendSlurLog(Player player, String message, int finalScore) { + ServerUtils.sendDebugMessage("Creating swearLog Webhook..."); + DiscordWebhook webhook = new DiscordWebhook(Config.webhook); + webhook.setAvatarUrl("https://r2.e-z.host/d440b58a-ba90-4839-8df6-8bba298cf817/3lwit5nt.png"); + webhook.setUsername("Sentinel Anti-Nuke | Logs"); + DiscordWebhook.EmbedObject embed = new DiscordWebhook.EmbedObject() + .setAuthor("Anti-Slur Punishment","","") + .setTitle(player.getName() + " has triggered the anti-slur!") + .setDescription( + Emojis.rightSort + "Player: " + player.getName() + " " + Emojis.target + "\\n" + + Emojis.space + Emojis.arrowRight + "Score: `" + finalScore + "/" + Config.punishScore + "`\\n" + + Emojis.space + Emojis.arrowRight + "UUID: `" + player.getUniqueId() + "`\\n" + + Emojis.rightSort + "Executed: " + Config.slurPunishCommand + " " + Emojis.mute + "\\n" + ) + .addField("Original Message", "||" + message + "|| " + Emojis.alarm, false) + .addField("Sanitized Message", ProfanityFilter.highlightProfanity(message,"||", "||") + " " + Emojis.noDM, false) + .setColor(Color.orange) + .setThumbnail("https://crafatar.com/avatars/" + player.getUniqueId() + "?size=64&&overlay"); + webhook.addEmbed(embed); + try { + ServerUtils.sendDebugMessage("Executing webhook..."); + webhook.execute(); + } catch (IOException e) { + ServerUtils.sendDebugMessage(TextUtils.prefix("Epic webhook failure!!!")); + Sentinel.log.info(e.toString()); } } @@ -49,11 +134,11 @@ public class WebhookSender { public static void sendEmbedWarning(String player, String command, boolean denied, boolean removedOp, boolean banned) { ServerUtils.sendDebugMessage("Creating Command Webhook..."); final String description = - Emojis.arrowRight + " **Player:** " + player + " " + Emojis.member + "\\n" + - Emojis.arrowRight + " **Command:** " + command + " " + Emojis.nuke + "\\n" + - Emojis.arrowRight + " **Denied:** " + successOrFail(denied) + "\\n" + - Emojis.arrowRight + " **Removed OP:** " + successOrFail(removedOp) + "\\n" + - Emojis.arrowRight + " **Banned:** " + successOrFail(banned) + "\\n"; + Emojis.rightSort + " **Player:** " + player + " " + Emojis.member + "\\n" + + Emojis.rightSort + " **Command:** " + command + " " + Emojis.nuke + "\\n" + + Emojis.rightSort + " **Denied:** " + successOrFail(denied) + "\\n" + + Emojis.rightSort + " **Removed OP:** " + successOrFail(removedOp) + "\\n" + + Emojis.rightSort + " **Banned:** " + successOrFail(banned) + "\\n"; DiscordWebhook webhook = new DiscordWebhook(Config.webhook); webhook.setAvatarUrl("https://r2.e-z.host/d440b58a-ba90-4839-8df6-8bba298cf817/3lwit5nt.png"); @@ -75,11 +160,11 @@ public class WebhookSender { public static void sendEmbedWarning(String player, Block b, boolean denied, boolean removedOp, boolean banned) { ServerUtils.sendDebugMessage("Creating Block Webhook..."); final String description = - Emojis.arrowRight + " **Player:** " + player + " " + Emojis.member + "\\n" + - Emojis.arrowRight + " **Block:** " + b.getType() + " " + Emojis.nuke + "\\n" + - Emojis.arrowRight + " **Denied:** " + successOrFail(denied) + "\\n" + - Emojis.arrowRight + " **Removed OP:** " + successOrFail(removedOp) + "\\n" + - Emojis.arrowRight + " **Banned:** " + successOrFail(banned) + "\\n"; + Emojis.rightSort + " **Player:** " + player + " " + Emojis.member + "\\n" + + Emojis.rightSort + " **Block:** " + b.getType() + " " + Emojis.nuke + "\\n" + + Emojis.rightSort + " **Denied:** " + successOrFail(denied) + "\\n" + + Emojis.rightSort + " **Removed OP:** " + successOrFail(removedOp) + "\\n" + + Emojis.rightSort + " **Banned:** " + successOrFail(banned) + "\\n"; DiscordWebhook webhook = new DiscordWebhook(Config.webhook); webhook.setAvatarUrl("https://r2.e-z.host/d440b58a-ba90-4839-8df6-8bba298cf817/3lwit5nt.png"); @@ -100,29 +185,32 @@ public class WebhookSender { } public static void sendEmbedWarning(String player, ItemStack item, boolean denied, boolean removedOp, boolean banned) { - ServerUtils.sendDebugMessage("Creating Webhook..."); - final String description = - Emojis.arrowRight + " **Player:** " + player + " " + Emojis.member + "\\n" + - Emojis.arrowRight + " **Item:** " + item.getType() + " " + Emojis.nuke + "\\n" + - Emojis.arrowRight + " **Denied:** " + successOrFail(denied) + "\\n" + - Emojis.arrowRight + " **Removed OP:** " + successOrFail(removedOp) + "\\n" + - Emojis.arrowRight + " **Banned:** " + successOrFail(banned) + "\\n"; + Bukkit.getScheduler().runTaskLater(Sentinel.getInstance(),() -> { + ServerUtils.sendDebugMessage("Creating Webhook..."); + final String description = + Emojis.rightSort + " **Player:** " + player + " " + Emojis.member + "\\n" + + Emojis.rightSort + " **Item:** " + item.getType().toString().toLowerCase() + " " + Emojis.nuke + "\\n" + + Emojis.space + Emojis.rightDoubleArrow + "**NBT:** Uploaded to /Sentinel/LoggedNBT/" + FileUtils.createNBTLog(item.getItemMeta().getAsString()) + " \\n" + + Emojis.rightSort + " **Denied:** " + successOrFail(denied) + "\\n" + + Emojis.rightSort + " **Removed OP:** " + successOrFail(removedOp) + "\\n" + + Emojis.rightSort + " **Banned:** " + successOrFail(banned) + "\\n"; - DiscordWebhook webhook = new DiscordWebhook(Config.webhook); - webhook.setAvatarUrl("https://r2.e-z.host/d440b58a-ba90-4839-8df6-8bba298cf817/3lwit5nt.png"); - webhook.setUsername("Sentinel Anti-Nuke | Logs"); - DiscordWebhook.EmbedObject embed = new DiscordWebhook.EmbedObject() - .setAuthor("Anti-Nuke has been triggered","","") - .setTitle("The use of a dangerous item has been detected!") - .setDescription(description) - .setColor(Color.BLUE); - webhook.addEmbed(embed); - try { - ServerUtils.sendDebugMessage("Executing webhook..."); - webhook.execute(); - } catch (IOException e) { - ServerUtils.sendDebugMessage(TextUtils.prefix("Epic webhook failure!!!")); - Sentinel.log.info(e.toString()); - } + DiscordWebhook webhook = new DiscordWebhook(Config.webhook); + webhook.setAvatarUrl("https://r2.e-z.host/d440b58a-ba90-4839-8df6-8bba298cf817/3lwit5nt.png"); + webhook.setUsername("Sentinel Anti-Nuke | Logs"); + DiscordWebhook.EmbedObject embed = new DiscordWebhook.EmbedObject() + .setAuthor("Anti-Nuke has been triggered","","") + .setTitle("The use of a dangerous item has been detected!") + .setDescription(description) + .setColor(Color.BLUE); + webhook.addEmbed(embed); + try { + ServerUtils.sendDebugMessage("Executing webhook..."); + webhook.execute(); + } catch (IOException e) { + ServerUtils.sendDebugMessage(TextUtils.prefix("Epic webhook failure!!!")); + Sentinel.log.info(e.toString()); + } + },10); } } diff --git a/src/main/java/io/github/thetrouper/sentinel/events/ChatEvent.java b/src/main/java/io/github/thetrouper/sentinel/events/ChatEvent.java index 4fd8bd2..62112de 100644 --- a/src/main/java/io/github/thetrouper/sentinel/events/ChatEvent.java +++ b/src/main/java/io/github/thetrouper/sentinel/events/ChatEvent.java @@ -1,5 +1,6 @@ package io.github.thetrouper.sentinel.events; +import io.github.thetrouper.sentinel.Sentinel; import io.github.thetrouper.sentinel.data.Config; import io.github.thetrouper.sentinel.server.functions.AntiSpam; import io.github.thetrouper.sentinel.server.functions.ProfanityFilter; @@ -11,7 +12,7 @@ public class ChatEvent implements Listener { @EventHandler public static void onChat(AsyncPlayerChatEvent e) { - if (Config.antiSwearEnabled) ProfanityFilter.handleProfanityFilter(e); - if (Config.antiSpamEnabled) AntiSpam.handleAntiSpam(e); + if (!Sentinel.isTrusted(e.getPlayer()) || !e.getPlayer().hasPermission("sentinel.chat.antiswear.bypass")) if (Config.antiSwearEnabled) ProfanityFilter.handleProfanityFilter(e); + if (!Sentinel.isTrusted(e.getPlayer()) || !e.getPlayer().hasPermission("sentinel.chat.antispam.bypass")) if (Config.antiSpamEnabled) AntiSpam.handleAntiSpam(e); } } diff --git a/src/main/java/io/github/thetrouper/sentinel/server/functions/AntiSpam.java b/src/main/java/io/github/thetrouper/sentinel/server/functions/AntiSpam.java index 4c71309..460aa25 100644 --- a/src/main/java/io/github/thetrouper/sentinel/server/functions/AntiSpam.java +++ b/src/main/java/io/github/thetrouper/sentinel/server/functions/AntiSpam.java @@ -1,6 +1,7 @@ package io.github.thetrouper.sentinel.server.functions; import io.github.thetrouper.sentinel.data.Config; +import io.github.thetrouper.sentinel.discord.WebhookSender; import io.github.thetrouper.sentinel.server.util.GPTUtils; import io.github.thetrouper.sentinel.server.util.ServerUtils; import io.github.thetrouper.sentinel.server.util.TextUtils; @@ -34,9 +35,11 @@ public class AntiSpam { punishSpam(p,message, lastMessageMap.get(p)); return; } + if (heatMap.get(p) > Config.blockHeat) { e.setCancelled(true); alertSpam(p, message, lastMessageMap.get(p)); + heatMap.put(p, heatMap.get(p) + Config.highGain); return; } if (lastMessageMap.containsKey(p)) { @@ -61,7 +64,10 @@ public class AntiSpam { public static void alertSpam(Player p, String message1, String message2) { TextComponent text = new TextComponent(); p.sendMessage(TextUtils.prefix("Do not spam in chat! Please wait before sending another message.")); - String hover = TextUtils.color("&bPrevious: &f" + message2 + "\n&bCurrent: &f" + message1 + "\n&bSimilarity &f" + GPTUtils.calculateSimilarity(message1,message2 + "%")); + String hover = TextUtils.color("§8]==-- §d§lSentinel §8--==[" + + "\n&bPrevious: &f" + message2 + + "\n&bCurrent: &f" + message1 + + "\n&bSimilarity &f" + GPTUtils.calculateSimilarity(message1,message2 + "%")); text.setText(TextUtils.prefix(TextUtils.color ("&b&n" + p.getName() + "&7 might be spamming! &8(&c" + heatMap.get(p) + "&7/&4" + Config.punishHeat + "&8)"))); text.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(hover))); @@ -70,6 +76,11 @@ public class AntiSpam { }); } public static void punishSpam(Player player, String message1, String message2) { + boolean chatCleared = false; + if (Config.clearChat) { + ServerUtils.sendCommand(Config.clearChatCommand); + chatCleared = true; + } ServerUtils.sendCommand(Config.punishSpamCommand.replace("%player%", player.getName())); player.sendMessage(TextUtils.prefix(TextUtils.color("&cYou have been auto-punished for violating the anti-spam repetitively!"))); TextComponent text = new TextComponent(); @@ -78,5 +89,6 @@ public class AntiSpam { ServerUtils.forEachStaff(staff -> { staff.spigot().sendMessage(text); }); + if (Config.logSpam) WebhookSender.sendSpamLog(player,message1,message2,heatMap.get(player),chatCleared); } } diff --git a/src/main/java/io/github/thetrouper/sentinel/server/functions/ProfanityFilter.java b/src/main/java/io/github/thetrouper/sentinel/server/functions/ProfanityFilter.java index 3df64fa..a63a3ae 100644 --- a/src/main/java/io/github/thetrouper/sentinel/server/functions/ProfanityFilter.java +++ b/src/main/java/io/github/thetrouper/sentinel/server/functions/ProfanityFilter.java @@ -1,6 +1,7 @@ package io.github.thetrouper.sentinel.server.functions; import io.github.thetrouper.sentinel.Sentinel; import io.github.thetrouper.sentinel.data.Config; +import io.github.thetrouper.sentinel.discord.WebhookSender; import io.github.thetrouper.sentinel.server.util.ServerUtils; import io.github.thetrouper.sentinel.server.util.TextUtils; import net.md_5.bungee.api.chat.ClickEvent; @@ -27,36 +28,44 @@ public class ProfanityFilter { String message = e.getMessage(); if (!scoreMap.containsKey(p)) scoreMap.put(p, 0); if (scoreMap.get(p) > Config.punishScore) punishSwear(p,highlightProfanity(message),message); - switch (ProfanityFilter.checkSeverity(message)) { + String severity = ProfanityFilter.checkSeverity(message); + switch (severity) { case "low" -> { - e.setCancelled(true); + ServerUtils.sendDebugMessage("AntiSwear Flag, Message: " + message + " Concentrated: " + fullSimplify(message) + " Severity: " + severity + " Previous Score: " + scoreMap.get(p) +" Adding Score: " + Config.lowScore); scoreMap.put(p, scoreMap.get(p) + Config.lowScore); + e.setCancelled(true); p.sendMessage(TextUtils.prefix("§cPlease do not swear in chat! Attempting to bypass this filter will result in a mute!")); + blockSwear(p,highlightProfanity(message),message,severity); } case "medium-low" -> { - e.setCancelled(true); + ServerUtils.sendDebugMessage("AntiSwear Flag, Message: " + message + " Concentrated: " + fullSimplify(message) + " Severity: " + severity + " Previous Score: " + scoreMap.get(p) +" Adding Score: " + Config.mediumLowScore); scoreMap.put(p, scoreMap.get(p) + Config.mediumLowScore); - blockSwear(p,highlightProfanity(message),message); + e.setCancelled(true); + blockSwear(p,highlightProfanity(message),message,severity); } case "medium" -> { - e.setCancelled(true); + ServerUtils.sendDebugMessage("AntiSwear Flag, Message: " + message + " Concentrated: " + fullSimplify(message) + " Severity: " + severity + " Previous Score: " + scoreMap.get(p) +" Adding Score: " + Config.mediumScore); scoreMap.put(p, scoreMap.get(p) + Config.mediumScore); - blockSwear(p,highlightProfanity(message),message); + e.setCancelled(true); + blockSwear(p,highlightProfanity(message),message,severity); } case "medium-high" -> { - e.setCancelled(true); + ServerUtils.sendDebugMessage("AntiSwear Flag, Message: " + message + " Concentrated: " + fullSimplify(message) + " Severity: " + severity + " Previous Score: " + scoreMap.get(p) +" Adding Score: " + Config.mediumHighScore); scoreMap.put(p, scoreMap.get(p) + Config.mediumHighScore); - blockSwear(p,highlightProfanity(message),message); + e.setCancelled(true); + blockSwear(p,highlightProfanity(message),message,severity); } case "high" -> { - e.setCancelled(true); + ServerUtils.sendDebugMessage("AntiSwear Flag, Message: " + message + " Concentrated: " + fullSimplify(message) + " Severity: " + severity + " Previous Score: " + scoreMap.get(p) +" Adding Score: " + Config.highScore); scoreMap.put(p, scoreMap.get(p) + Config.highScore); - blockSwear(p,highlightProfanity(message),message); + e.setCancelled(true); + blockSwear(p,highlightProfanity(message),message,severity); } case "slur" -> { // Insta-Punish - e.setCancelled(true); + ServerUtils.sendDebugMessage("AntiSwear Flag, Message: " + message + " Concentrated: " + fullSimplify(message) + " Severity: " + severity + " Previous Score: " + scoreMap.get(p) +" Adding Score: " + Config.highScore); scoreMap.put(p, scoreMap.get(p) + Config.highScore); + e.setCancelled(true); punishSlur(p,highlightProfanity(message),message); } } @@ -74,6 +83,7 @@ public class ProfanityFilter { ServerUtils.forEachStaff(staff -> { staff.spigot().sendMessage(text); }); + if (Config.logSwear) WebhookSender.sendSwearLog(player,origMessage,scoreMap.get(player)); } public static void punishSlur(Player player, String highlightedMSG, String origMessage) { if (!Config.slurInstaPunish) return; @@ -89,10 +99,11 @@ public class ProfanityFilter { ServerUtils.forEachStaff(staff -> { staff.spigot().sendMessage(text); }); + if (Config.logSwear) WebhookSender.sendSlurLog(player,origMessage,scoreMap.get(player)); } - public static void blockSwear(Player player, String highlightedMSG, String origMessage) { + public static void blockSwear(Player player, String highlightedMSG, String origMessage, String severity) { player.sendMessage(TextUtils.prefix(TextUtils.color("&cPlease do not swear in chat! Attempting to bypass this filter will result in a mute!"))); - String hover = TextUtils.color("&bOriginal: &f" + origMessage + "\n&bSanitized: &f" + highlightedMSG + "\n&7&o(click to copy)"); + String hover = TextUtils.color("&bOriginal: &f" + origMessage + "\n&bSanitized: &f" + highlightedMSG + "\n&bSeverity" + severity + "\n&7&o(click to copy)"); TextComponent text = new TextComponent(); text.setText(TextUtils.prefix(TextUtils.color ("&b&n" + player.getName() + "&7 has triggered the anti-swear! &8(&c" + scoreMap.get(player) + "&7/&4" + Config.punishScore + "&8)"))); @@ -105,9 +116,13 @@ public class ProfanityFilter { } public static String highlightProfanity(String text) { - String lowercasedText = text.toLowerCase(); - String highlightedSwears = highlightSwears(lowercasedText, "§c", "§f"); - String highlightedText = highlightSlurs(highlightedSwears, "§e", "§f"); + String highlightedSwears = highlightSwears(fullSimplify(text), "§e", "§f"); + String highlightedText = highlightSlurs(highlightedSwears, "§c", "§f"); + return highlightedText; + } + public static String highlightProfanity(String text, String start, String end) { + String highlightedSwears = highlightSwears(fullSimplify(text), start, end); + String highlightedText = highlightSlurs(highlightedSwears, start, end); return highlightedText; } @@ -140,6 +155,15 @@ public class ProfanityFilter { * 10: remove periods and spaces * 11: Check for swears and return "high" if true */ + public static String fullSimplify(String text) { + String lowercasedText = text.toLowerCase(); + String cleanedText = removeFalsePositives(lowercasedText); + String convertedText = convertLeetSpeakCharacters(cleanedText); + String strippedText = stripSpecialCharacters(convertedText); + String simplifiedText = simplifyRepeatingLetters(strippedText); + String finalText = removePeriodsAndSpaces(simplifiedText); + return finalText; + } public static String checkSeverity(String text) { // 1: String lowercasedText = text.toLowerCase(); @@ -220,4 +244,13 @@ public class ProfanityFilter { private static String removePeriodsAndSpaces(String text) { return text.replace(".", "").replace(" ", ""); } + public static void decayScore() { + for (Player p : scoreMap.keySet()) { + int score = scoreMap.get(p); + if (score > 0) { + score = score - Config.scoreDecay; + scoreMap.put(p, Math.max(0, score)); + } + } + } } diff --git a/src/main/java/io/github/thetrouper/sentinel/server/util/FileUtils.java b/src/main/java/io/github/thetrouper/sentinel/server/util/FileUtils.java new file mode 100644 index 0000000..76418aa --- /dev/null +++ b/src/main/java/io/github/thetrouper/sentinel/server/util/FileUtils.java @@ -0,0 +1,40 @@ +package io.github.thetrouper.sentinel.server.util; + +import io.github.thetrouper.sentinel.Sentinel; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.time.*; +import java.util.Random; + +public class FileUtils { + public static boolean folderExists(String folderName) { + File folder = new File(Sentinel.getDF(), folderName); + return folder.exists() && folder.isDirectory(); + } + public static void createFolder(String folderName) { + File folder = new File(Sentinel.getDF(), folderName); + if (!folder.exists()) { + folder.mkdirs(); + } + } + public static String createNBTLog(String contents) { + String fileName = "nbt_log-" + Randomizer.generateID(); + File file = new File(Sentinel.getDF() + "/LoggedNBT/" + fileName + ".txt"); + try { + if (!file.exists()) { + file.createNewFile(); + } + + BufferedWriter writer = new BufferedWriter(new FileWriter(file, true)); + writer.append(contents); + writer.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + return fileName; + } +} diff --git a/src/main/java/io/github/thetrouper/sentinel/server/util/Randomizer.java b/src/main/java/io/github/thetrouper/sentinel/server/util/Randomizer.java index 80b3318..940965f 100644 --- a/src/main/java/io/github/thetrouper/sentinel/server/util/Randomizer.java +++ b/src/main/java/io/github/thetrouper/sentinel/server/util/Randomizer.java @@ -3,12 +3,22 @@ package io.github.thetrouper.sentinel.server.util; import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.text.SimpleDateFormat; +import java.util.Date; /** * Randomize items from a list * @param list of? */ public class Randomizer { + public static long generateID() { + Date now = new Date(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS"); + String formattedDate = dateFormat.format(now); + long id = Long.parseLong(formattedDate); + + return id; + } private final List array; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index d1bc450..ad2c9cf 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -15,7 +15,8 @@ config : # Anti-Nuke Setup (Do this first) # -------------------------------- prefix: "§d§lSentinel §8» §7" # Prefix of the plugin. Line below is the discord webhook for logs to be sent to - webhook: "https://discord.com/api/webhooks/1124908469842096211/7NGOeFvtmxQ4n0_hSvbqhZUjnzRHIicLpHKETYU92n9JaLUPPsueBSn7w4wUfAnhjlLF" + webhook: "https://discord.com/api/webhooks/1126363806147289088/UfWz9jdmXpZ4f2kqqsKK6mx4NmZyknhHNzGuAHYSx30iSLCPwqf66AiToZn2rItAmAym" + pbapikey: "Sar3RgGOxMhps71H3JDWKPeCaMIDbS_g" # Put your pastebin.com API key here (they are free), if you wish for NBT logs to work trusted: # List the UUIDs of players who are trusted, will bypass the plugin and be immune to logs and are able to re-op themeselves - "049460f7-21cb-42f5-8059-d42752bf406f" # obvWolf block-specific: true # Defaulted true | Weather or not to block ALL plugin specific commands from non-trusted members (EX: minecraft:ban) these will not be logged. @@ -53,31 +54,183 @@ config : high-gain: 6 # Default 6 | Heat gained for >90% similarity heat-decay: 1 # Default 1 | Heat lost every second block-heat: 10 # Default 10 | The heat required to block the message - punish-heat: 15 # Default 15 | The heat required to punish the player + punish-heat: 25 # Default 25 | The heat required to punish the player + clear-chat: true # Default true | will run the clear chat command before a spam punishment + chat-clear-command: "cc" # Default cc | Command for if "clear-chat" is enabled punish-command: "mute %player% 1m Please refrain from spamming!" # (Use %player% for the player's name placeholder) log-spam: true # Default true | logs spam punishments to the webhook anti-swear: enabled: true # Default true | Enables/disables the entire anti-swear low-score: 0 # Default 0 | How much score should you gain for not attempting a bypass - medium-low-score: 0 # Default 0 | How much score should you gain for "bad "bypass attempt - medium-score: 1 # Default 1 | How much score should you gain for "ok" bypass attempt - medium-high-score: 3 # Default 3 | How much score should you gain for "good" bypass attempt - high-score: 5 # Default 5 | How much score should be gained for "extreme" attempt to bypass + medium-low-score: 1 # Default 1 | How much score should you gain for "bad "bypass attempt + medium-score: 3 # Default 3 | How much score should you gain for "ok" bypass attempt + medium-high-score: 5 # Default 5 | How much score should you gain for "good" bypass attempt + high-score: 7 # Default 7 | How much score should be gained for "extreme" attempt to bypass + score-decay: 3 # Default 3 | Rate at which score is lost every minute punish-score: 20 # Default 20 | how much score is required to get punished slur-insta-punish: true # Default true | Should players get insta punished for any words on the "slurs" list? - punish-command: "mute %player% 15m Please refrain from excessive use of profanity!" + punish-command: "mute %player% 15m Do not attempt to bypass the Profanity Filter" slur-command: "mute %player% 1h Discriminatory speech is not tolerated on this server!" log-swear: true # Default true | Logs swear punishments to the webhook - whitelisted: # List known false positives here - - glass - blacklisted: # list all the swears you wish to blacklist here + whitelisted: + - but then + - was scamming + - an alt + - can also + - analysis + - analytics + - arsenal + - assassin + - as saying + - assert + - assign + - assimil + - assist + - associat + - assum + - assur + - basement + - bass + - cass + - butter + - canvass + - cocktail + - cumber + - document + - evaluate + - exclusive + - expensive + - explain + - expression + - grape + - grass + - harass + - hot water + - identit + - kassa + - kassi + - lass + - leafage + - libshitz + - magnacumlaude + - mass + - mocha + - pass + - phoebe + - phoenix + - push it + - sassy + - saturday + - scrap + - serfage + - sexist + - shoe + - stitch + - therapist + blacklisted: + - anal + - anus + - arse - ass - slurs: # List slurs here that you wish to insta-punish for attempting + - ballsack + - balls + - bastard + - bitch + - btch + - biatch + - blowjob + - bollock + - bollok + - boner + - boob + - bugger + - butt + - choad + - clitoris + - cock + - coon + - crap + - cum + - cunt + - dick + - dildo + - douchebag + - dyke + - feck + - fellate + - fellatio + - felching + - fuck + - fudgepacker + - flange + - gtfo + - hoe + - horny + - incest + - jerk + - jizz + - labia + - masturb + - muff + - nazi + - nipple + - nips + - nude + - pedophile + - penis + - piss + - poop + - porn + - prick + - prostit + - pube + - pussie + - pussy + - queer + - rape + - rapist + - retard + - rimjob + - scrotum + - sex + - shit + - slut + - spunk + - stfu + - suckmy + - tits + - tittie + - titty + - turd + - twat + - vagina + - wank + - whore + slurs: - nigg + - niger + - nlgg + - nlger + - njgg + - tranny + - fag + - beaner leet-patterns: '0': o '1': i '3': e '4': a + '5': s + '6': g + '7': l + $: s + '!': i + '|': i + +: t + '#': h + '@': a + <: c + V: u + v: u diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 06cb79f..8097719 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: Sentinel version: '${version}' main: io.github.thetrouper.sentinel.Sentinel -api-version: 1.17 +api-version: 1.19 authors: [ TheTrouper ] description: Detect Block and Ban players who attempt to grief your server. website: https://thetrouper.github.io/