Anti-Spam has been finished and the Anti-Swear got an upgrade!

This commit is contained in:
TheTrouper
2023-07-04 14:40:06 -05:00
parent 142641d647
commit 3c1a08f231
17 changed files with 691 additions and 160 deletions

View File

@@ -12,6 +12,7 @@ import io.github.thetrouper.sentinel.events.CmdBlockEvents;
import io.github.thetrouper.sentinel.events.CommandEvent;
import io.github.thetrouper.sentinel.events.NBTEvents;
import io.github.thetrouper.sentinel.server.functions.AntiSpam;
import io.github.thetrouper.sentinel.server.functions.ProfanityFilter;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
@@ -32,19 +33,7 @@ public final class Sentinel extends JavaPlugin {
public static final PluginManager manager = Bukkit.getPluginManager();
public static String prefix = "";
public static final Logger log = Bukkit.getLogger();
public static String webhook;
public static List<String> trustedPlayers;
public static boolean blockSpecificCommands;
public static boolean preventNBT;
public static boolean logNBT;
public static boolean preventCmdBlocks;
public static boolean logCmdBlocks;
public static List<String> dangerousCommands;
public static boolean logDangerousCommands;
public static List<String> loggedCommands;
public static boolean deop;
public static boolean ban;
public static boolean reopCommand;
/**
* Plugin startup logic
*/
@@ -56,10 +45,12 @@ public final class Sentinel extends JavaPlugin {
saveDefaultConfig();
// Plugin startup logic
loadConfiguration();
Config.loadConfiguration();
log.info("Sentinel has loaded! (" + getDescription().getVersion() + ")");
// Enable Functions
AntiSpam.enableAntiSpam();
ProfanityFilter.enableAntiSwear();
prefix = Config.Plugin.getPrefix();
@@ -95,54 +86,15 @@ public final class Sentinel extends JavaPlugin {
// Plugin shutdown logic
log.info("Sentinel has disabled! (" + getDescription().getVersion() + ") Your server is now no longer protected!");
}
private void loadConfiguration() {
saveDefaultConfig();
FileConfiguration config = getConfig();
// Load prefix
prefix = config.getString("config.plugin.prefix");
// Load webhook
webhook = config.getString("config.plugin.webhook");
// Load trusted players
trustedPlayers = config.getStringList("config.plugin.trusted");
// Load block-specific commands
blockSpecificCommands = config.getBoolean("config.plugin.block-specific");
// Load prevent NBT
preventNBT = config.getBoolean("config.plugin.prevent-nbt");
// Load log NBT
logNBT = config.getBoolean("config.plugin.log-nbt");
// Load prevent command blocks
preventCmdBlocks = config.getBoolean("config.plugin.prevent-cmdblocks");
// Load log command blocks
logCmdBlocks = config.getBoolean("config.plugin.log-cmdblocks");
// Load dangerous commands
dangerousCommands = config.getStringList("config.plugin.dangerous");
// Load log protected commands
logDangerousCommands = config.getBoolean("config.plugin.log-dangerous");
// Load logged commands
loggedCommands = config.getStringList("config.plugin.logged");
deop = config.getBoolean("config.plugin.deop");
ban = config.getBoolean("config.plugin.ban");
reopCommand = config.getBoolean("config.plugin.reop-command");
}
/**
* Checks if a player is trusted.
* @param player the player to check
* @return true if the player is trusted, false otherwise
*/
public static boolean isTrusted(Player player) {
return trustedPlayers.contains(player.getUniqueId().toString());
return Config.trustedPlayers.contains(player.getUniqueId().toString());
}
/**
@@ -151,7 +103,7 @@ public final class Sentinel extends JavaPlugin {
* @return true if the command is logged, false otherwise
*/
public static boolean isLoggedCommand(String command) {
return loggedCommands.contains(command);
return Config.loggedCommands.contains(command);
}
/**
@@ -160,7 +112,7 @@ public final class Sentinel extends JavaPlugin {
* @return true if the command is dangerous, false otherwise
*/
public static boolean isDangerousCommand(String command) {
return dangerousCommands.contains(command);
return Config.dangerousCommands.contains(command);
}
/**
* Returns an instance of this plugin

View File

@@ -7,7 +7,9 @@ package io.github.thetrouper.sentinel.commands;
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.ServerUtils;
import io.github.thetrouper.sentinel.server.util.TextUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import java.util.ArrayList;
@@ -38,6 +40,10 @@ public class InfoCommand implements TabExecutor {
case "checkheat" -> {
sender.sendMessage(TextUtils.prefix("Your heat is §e" + AntiSpam.heatMap.get(sender).toString()));
}
case "dispatchtest" -> {
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!");
}
}
return true;
} catch (Exception ex) {
@@ -54,7 +60,8 @@ public class InfoCommand implements TabExecutor {
.add(1,new String[]{
"debugmode",
"webhooktest",
"checkheat"
"checkheat",
"dispatchtest"
}).build();
}
}

View File

@@ -1,6 +1,7 @@
package io.github.thetrouper.sentinel.commands;
import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Config;
import io.github.thetrouper.sentinel.exceptions.CmdExHandler;
import io.github.thetrouper.sentinel.server.util.TextUtils;
import org.bukkit.command.Command;
@@ -17,7 +18,7 @@ public class ReopCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
try {
if (Sentinel.reopCommand) {
if (Config.reopCommand) {
String name = sender.getName().toString();
Player p = sender.getServer().getPlayer(name);
if (Sentinel.isTrusted(p)) {

View File

@@ -5,13 +5,17 @@
package io.github.thetrouper.sentinel.data;
import io.github.thetrouper.sentinel.Sentinel;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Config loader
*/
public abstract class Config {
private static final FileConfiguration config = Sentinel.getInstance().getConfig();
/**
@@ -22,4 +26,101 @@ public abstract class Config {
return config.getString("config.plugin.prefix");
}
}
public static String webhook;
public static List<String> trustedPlayers;
public static boolean blockSpecificCommands;
public static boolean preventNBT;
public static boolean logNBT;
public static boolean preventCmdBlocks;
public static boolean logCmdBlocks;
public static List<String> dangerousCommands;
public static boolean logDangerousCommands;
public static List<String> loggedCommands;
public static boolean deop;
public static boolean ban;
public static boolean reopCommand;
public static boolean antiSpamEnabled;
public static int defaultGain;
public static int lowGain;
public static int mediumGain;
public static int highGain;
public static int heatDecay;
public static int blockHeat;
public static int punishHeat;
public static String punishSpamCommand;
public static boolean logSpam;
public static boolean antiSwearEnabled;
public static int lowScore;
public static int mediumLowScore;
public static int mediumScore;
public static int mediumHighScore;
public static int highScore;
public static int punishScore;
public static String swearPunishCommand;
public static boolean slurInstaPunish;
public static String slurPunishCommand;
public static List<String> swearWhitelist;
public static List<String> swearBlacklist;
public static List<String> slurs;
public static Map<String, String> leetPatterns;
public static boolean logSwear;
public static void loadConfiguration() {
Sentinel.prefix = config.getString("config.plugin.prefix");
// antiNuke
webhook = config.getString("config.plugin.webhook");
trustedPlayers = config.getStringList("config.plugin.trusted");
blockSpecificCommands = config.getBoolean("config.plugin.block-specific");
preventNBT = config.getBoolean("config.plugin.prevent-nbt");
logNBT = config.getBoolean("config.plugin.log-nbt");
preventCmdBlocks = config.getBoolean("config.plugin.prevent-cmdblocks");
logCmdBlocks = config.getBoolean("config.plugin.log-cmdblocks");
dangerousCommands = config.getStringList("config.plugin.dangerous");
logDangerousCommands = config.getBoolean("config.plugin.log-dangerous");
loggedCommands = config.getStringList("config.plugin.logged");
deop = config.getBoolean("config.plugin.deop");
ban = config.getBoolean("config.plugin.ban");
reopCommand = config.getBoolean("config.plugin.reop-command");
// antiSpam
antiSpamEnabled = config.getBoolean("config.chat.anti-spam.enabled");
defaultGain = config.getInt("config.chat.anti-spam.default-gain");
lowGain = config.getInt("config.chat.anti-spam.low-gain");
mediumGain = config.getInt("config.chat.anti-spam.medium-gain");
highGain = config.getInt("config.chat.anti-spam.high-gain");
heatDecay = config.getInt("config.chat.anti-spam.heat-decay");
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");
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");
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");
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<String, String> loadLeetPatterns() {
Map<String, String> dictionary = new HashMap<>();
ConfigurationSection section = config.getConfigurationSection("config.chat.anti-swear.leet-patterns");
if (section != null) {
for (String key : section.getKeys(false)) {
dictionary.put(key, section.getString(key));
}
}
return dictionary;
}
}

View File

@@ -1,9 +1,32 @@
package io.github.thetrouper.sentinel.data;
public class Emojis {
public static String success = "<:success:1125240412081238066>";
public static String rightSort = "<:rightSort:1125785837255270520>";
public static String arrowRight = "<:arrowRight:1125785471520354304>";
public static String rightDoubleArrow = "<:rightDoubleArrow:1125785800353783868>";
public static String activity = "<:activity:1125785527468167178>";
public static String alarm = "<:alarm:1125790301873770606>";
public static String target = "<:target:1125788461371232307>";
public static String bot = "<:bot:1125791121851826206>";
public static String cancel = "<:cancel:1125785769471127694>";
public static String creation = "<:creation:1125790610729730109>";
public static String date = "<:date:1125790434443145297>";
public static String kick = "<:kick:1125785612595761212>";
public static String members = "<:members:1125791101199077426>";
public static String mute = "<:mute:1125789032937435247>";
public static String noDM = "<:noDM:1125790359423824022>";
public static String owner = "<:owner:1125791175559876669>";
public static String potentialDanger = "<:potentialDanger:1125788513971998741>";
public static String roles = "<:roles:1125790513933594645>";
public static String separator = "<:separator:1125790817626357861>";
public static String splash = "<:splash:1125791213933563905>";
public static String success = "<:success:1125785728161419356>";
public static String suspicious = "<:suspicious:1125790709371371682>";
public static String trustedAdmin = "<:trustedAdmin:1125785574591180822>";
public static String upvoter = "<:upvoter:1125790659735977994>";
public static String vanity = "<:vanity:1125791060594004039>";
public static String webhook = "<:webhook:1125790545638330388>";
public static String failure = "<:failure:1125241087909429369>";
public static String rightArrow = "<:rightArrow:1125241843597189160>";
public static String nuke = "<:nuke:1125244368807280702>";
public static String member = "<:member:1125244044407218176>";
}

View File

@@ -2,11 +2,13 @@ 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.util.ServerUtils;
import io.github.thetrouper.sentinel.server.util.TextUtils;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.awt.Color;
@@ -15,7 +17,7 @@ import java.io.IOException;
public class WebhookSender {
public static void sendHelloWorldEmbed() {
String webhookUrl = Sentinel.webhook;
String webhookUrl = Config.webhook;
// Create a new DiscordWebhook instance
DiscordWebhook webhook = new DiscordWebhook(webhookUrl);
@@ -36,6 +38,7 @@ public class WebhookSender {
}
}
public static String successOrFail(boolean bool) {
if (bool) {
return Emojis.success;
@@ -46,13 +49,13 @@ 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.rightArrow + " **Player:** " + player + " " + Emojis.member + "\\n" +
Emojis.rightArrow + " **Command:** " + command + " " + Emojis.nuke + "\\n" +
Emojis.rightArrow + " **Denied:** " + successOrFail(denied) + "\\n" +
Emojis.rightArrow + " **Removed OP:** " + successOrFail(removedOp) + "\\n" +
Emojis.rightArrow + " **Banned:** " + successOrFail(banned) + "\\n";
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";
DiscordWebhook webhook = new DiscordWebhook(Sentinel.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()
@@ -72,13 +75,13 @@ 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.rightArrow + " **Player:** " + player + " " + Emojis.member + "\\n" +
Emojis.rightArrow + " **Block:** " + b.getType() + " " + Emojis.nuke + "\\n" +
Emojis.rightArrow + " **Denied:** " + successOrFail(denied) + "\\n" +
Emojis.rightArrow + " **Removed OP:** " + successOrFail(removedOp) + "\\n" +
Emojis.rightArrow + " **Banned:** " + successOrFail(banned) + "\\n";
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";
DiscordWebhook webhook = new DiscordWebhook(Sentinel.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()
@@ -99,13 +102,13 @@ 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.rightArrow + " **Player:** " + player + " " + Emojis.member + "\\n" +
Emojis.rightArrow + " **Item:** " + item.getType() + " " + Emojis.nuke + "\\n" +
Emojis.rightArrow + " **Denied:** " + successOrFail(denied) + "\\n" +
Emojis.rightArrow + " **Removed OP:** " + successOrFail(removedOp) + "\\n" +
Emojis.rightArrow + " **Banned:** " + successOrFail(banned) + "\\n";
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";
DiscordWebhook webhook = new DiscordWebhook(Sentinel.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()

View File

@@ -1,13 +1,17 @@
package io.github.thetrouper.sentinel.events;
import io.github.thetrouper.sentinel.data.Config;
import io.github.thetrouper.sentinel.server.functions.AntiSpam;
import io.github.thetrouper.sentinel.server.functions.ProfanityFilter;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
public class ChatEvent implements Listener {
@EventHandler
public static void onChat(AsyncPlayerChatEvent e) {
AntiSpam.handleAntiSpam(e);
if (Config.antiSwearEnabled) ProfanityFilter.handleProfanityFilter(e);
if (Config.antiSpamEnabled) AntiSpam.handleAntiSpam(e);
}
}

View File

@@ -1,6 +1,7 @@
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.util.DeniedActions;
import org.bukkit.Material;
import org.bukkit.block.Block;
@@ -15,7 +16,7 @@ import org.bukkit.event.player.PlayerInteractEvent;
public class CmdBlockEvents implements Listener {
@EventHandler
private void onCMDBlockUse(PlayerInteractEvent e) {
if (!Sentinel.preventCmdBlocks) return;
if (!Config.preventCmdBlocks) return;
if (e.getClickedBlock() == null) return;
Block b = e.getClickedBlock();
if (b.getType() == Material.COMMAND_BLOCK || b.getType() == Material.REPEATING_COMMAND_BLOCK || b.getType() == Material.CHAIN_COMMAND_BLOCK) {
@@ -28,7 +29,7 @@ public class CmdBlockEvents implements Listener {
}
@EventHandler
private void onCMDBlockPlace(BlockPlaceEvent e) {
if (!Sentinel.preventCmdBlocks) return;
if (!Config.preventCmdBlocks) return;
Block b = e.getBlockPlaced();
if (b.getType() == Material.COMMAND_BLOCK || b.getType() == Material.CHAIN_COMMAND_BLOCK || b.getType() == Material.REPEATING_COMMAND_BLOCK ) {
Player p = e.getPlayer();
@@ -40,7 +41,7 @@ public class CmdBlockEvents implements Listener {
}
@EventHandler
private void onCMDBlockMinecartUse(PlayerInteractEntityEvent e) {
if (!Sentinel.preventCmdBlocks) return;
if (!Config.preventCmdBlocks) return;
if (e.getRightClicked().getType() == EntityType.MINECART_COMMAND) {
Player p = e.getPlayer();
if (!Sentinel.isTrusted(p)) {

View File

@@ -1,6 +1,7 @@
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.util.DeniedActions;
import io.github.thetrouper.sentinel.server.util.ServerUtils;
import io.github.thetrouper.sentinel.server.util.TextUtils;
@@ -24,7 +25,7 @@ public class CommandEvent implements Listener {
DeniedActions.handleDeniedAction(p,e.getMessage());
}
}
if (Sentinel.blockSpecificCommands) {
if (Config.blockSpecificCommands) {
ServerUtils.sendDebugMessage(TextUtils.prefix("Checking command for specific"));
if (command.contains(":")) {
ServerUtils.sendDebugMessage(TextUtils.prefix("Checking is specific"));

View File

@@ -1,7 +1,13 @@
package io.github.thetrouper.sentinel.server.functions;
import io.github.thetrouper.sentinel.data.Config;
import io.github.thetrouper.sentinel.server.util.GPTUtils;
import io.github.thetrouper.sentinel.server.util.ServerUtils;
import io.github.thetrouper.sentinel.server.util.TextUtils;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent;
@@ -19,29 +25,58 @@ public class AntiSpam {
heatMap = new HashMap<>();
lastMessageMap = new HashMap<>();
}
public static void handleAntiSpam(AsyncPlayerChatEvent event) {
Player player = event.getPlayer();
String message = event.getMessage();
if (!heatMap.containsKey(player)) heatMap.put(player, 0);
if (heatMap.get(player) > 10) {
event.setCancelled(true);
player.sendMessage(TextUtils.prefix("Rate limit exceeded! Please wait before sending another message."));
public static void handleAntiSpam(AsyncPlayerChatEvent e) {
Player p = e.getPlayer();
String message = e.getMessage();
if (!heatMap.containsKey(p)) heatMap.put(p, 0);
if (heatMap.get(p) > Config.punishHeat) {
e.setCancelled(true);
punishSpam(p,message, lastMessageMap.get(p));
return;
}
if (lastMessageMap.containsKey(player)) {
String lastMessage = lastMessageMap.get(player);
double similarity = calculateSimilarity(message, lastMessage);
if (similarity > 0.5) heatMap.put(player, heatMap.get(player) + 3);
if (similarity > 0.9) heatMap.put(player, heatMap.get(player) + 6);
if (heatMap.get(p) > Config.blockHeat) {
e.setCancelled(true);
alertSpam(p, message, lastMessageMap.get(p));
return;
}
lastMessageMap.put(player, message);
if (lastMessageMap.containsKey(p)) {
String lastMessage = lastMessageMap.get(p);
double similarity = calculateSimilarity(message, lastMessage);
if (similarity > 0.25) heatMap.put(p, heatMap.get(p) + Config.lowGain);
if (similarity > 0.5) heatMap.put(p, heatMap.get(p) + Config.mediumGain);
if (similarity > 0.9) heatMap.put(p, heatMap.get(p) + Config.highGain);
}
lastMessageMap.put(p, message);
}
public static void decayHeat() {
for (Player player : heatMap.keySet()) {
int heat = heatMap.get(player);
for (Player p : heatMap.keySet()) {
int heat = heatMap.get(p);
if (heat > 0) {
heatMap.put(player, heat - 1);
heat = heat - Config.heatDecay;
heatMap.put(p, Math.max(0, heat));
}
}
}
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 + "%"));
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)));
ServerUtils.forEachStaff(staff -> {
staff.spigot().sendMessage(text);
});
}
public static void punishSpam(Player player, String message1, String message2) {
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();
text.setText(TextUtils.prefix(TextUtils.color
("&b&n" + player.getName() + "&7 has been auto-muted by the anti-spam! &8(&c" + heatMap.get(player) + "&7/&4" + Config.punishHeat + "&8)")));
ServerUtils.forEachStaff(staff -> {
staff.spigot().sendMessage(text);
});
}
}

View File

@@ -0,0 +1,223 @@
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.server.util.ServerUtils;
import io.github.thetrouper.sentinel.server.util.TextUtils;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ProfanityFilter {
public static Map<Player, Integer> scoreMap;
private static final List<String> swearBlacklist = Config.swearBlacklist;
private static final List<String> swearWhitelist = Config.swearWhitelist;
private static final List<String> slurs = Config.slurs;
public static void enableAntiSwear() {
scoreMap = new HashMap<>();
}
public static void handleProfanityFilter(AsyncPlayerChatEvent e) {
Player p = e.getPlayer();
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)) {
case "low" -> {
e.setCancelled(true);
scoreMap.put(p, scoreMap.get(p) + Config.lowScore);
p.sendMessage(TextUtils.prefix("§cPlease do not swear in chat! Attempting to bypass this filter will result in a mute!"));
}
case "medium-low" -> {
e.setCancelled(true);
scoreMap.put(p, scoreMap.get(p) + Config.mediumLowScore);
blockSwear(p,highlightProfanity(message),message);
}
case "medium" -> {
e.setCancelled(true);
scoreMap.put(p, scoreMap.get(p) + Config.mediumScore);
blockSwear(p,highlightProfanity(message),message);
}
case "medium-high" -> {
e.setCancelled(true);
scoreMap.put(p, scoreMap.get(p) + Config.mediumHighScore);
blockSwear(p,highlightProfanity(message),message);
}
case "high" -> {
e.setCancelled(true);
scoreMap.put(p, scoreMap.get(p) + Config.highScore);
blockSwear(p,highlightProfanity(message),message);
}
case "slur" -> {
// Insta-Punish
e.setCancelled(true);
scoreMap.put(p, scoreMap.get(p) + Config.highScore);
punishSlur(p,highlightProfanity(message),message);
}
}
}
public static void punishSwear(Player player, String highlightedMSG, String origMessage) {
ServerUtils.sendCommand(Config.swearPunishCommand.replace("%player%", player.getName()));
player.sendMessage(TextUtils.prefix(TextUtils.color("&cYou have been auto-muted for violating the anti-swear repetitively!")));
String hover = TextUtils.color("&bOriginal: &f" + origMessage + "\n&bSanitized: &f" + highlightedMSG + "\n&7&o(click to copy)");
TextComponent text = new TextComponent();
text.setText(TextUtils.prefix(TextUtils.color
("&b&n" + player.getName() + "&7 has been auto-muted by the anti-swear! &8(&c" + scoreMap.get(player) + "&7/&4" + Config.punishScore + "&8)")));
text.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(hover)));
text.setClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, origMessage));
ServerUtils.forEachStaff(staff -> {
staff.spigot().sendMessage(text);
});
}
public static void punishSlur(Player player, String highlightedMSG, String origMessage) {
if (!Config.slurInstaPunish) return;
ServerUtils.sendCommand(Config.slurPunishCommand.replace("%player%", player.getName()));
player.sendMessage(TextUtils.prefix(TextUtils.color("&cYou have been insta-muted for saying a slur!")));
String hover = TextUtils.color("&bOriginal: &f" + origMessage + "\n&bSanitized: &f" + highlightedMSG + "\n&7&o(click to copy)");
TextComponent text = new TextComponent();
text.setText(TextUtils.prefix(TextUtils.color
("&b&n" + player.getName() + "&7 has been insta-muted by the anti-swear! &8(&e" + scoreMap.get(player) + "&7/&4" + Config.punishScore + "&8)")));
text.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(hover)));
text.setClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, origMessage));
ServerUtils.forEachStaff(staff -> {
staff.spigot().sendMessage(text);
});
}
public static void blockSwear(Player player, String highlightedMSG, String origMessage) {
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)");
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)")));
text.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(hover)));
text.setClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, origMessage));
ServerUtils.forEachStaff(staff -> {
staff.spigot().sendMessage(text);
});
}
public static String highlightProfanity(String text) {
String lowercasedText = text.toLowerCase();
String highlightedSwears = highlightSwears(lowercasedText, "§c", "§f");
String highlightedText = highlightSlurs(highlightedSwears, "§e", "§f");
return highlightedText;
}
private static String highlightSwears(String text, String start, String end) {
for (String swear : swearBlacklist) {
if (text.contains(swear)) {text = text.replace(swear, start + swear + end);}
}
return text;
}
private static String highlightSlurs(String text, String start, String end) {
for (String slur : slurs) {
if (text.contains(slur)) {
text = text.replace(slur, start + slur + end);
}
}
return text;
}
/**
* 1: lowercase the text
* 2: remove the known false positives
* 3: Check for swears and return "low" if true
* 4: Convert LeetSpeak Characters
* 5: Check for swears and return "medium-low" if true
* 6: Strip all special characters
* 7: Check for swears and return "medium" if true
* 8: simplify repeating letters
* 9: Check for swears and return "medium-high" if true
* 10: remove periods and spaces
* 11: Check for swears and return "high" if true
*/
public static String checkSeverity(String text) {
// 1:
String lowercasedText = text.toLowerCase();
// 2:
String cleanedText = removeFalsePositives(lowercasedText);
// 3:
if (containsSwears(cleanedText)) return "low";
if (containsSlurs(cleanedText)) return "slur";
// 4:
String convertedText = convertLeetSpeakCharacters(cleanedText);
// 5:
if (containsSwears(convertedText)) return "medium-low";
if (containsSlurs(cleanedText)) return "slur";
// 6:
String strippedText = stripSpecialCharacters(convertedText);
// 7:
if (containsSwears(strippedText)) return "medium";
if (containsSlurs(strippedText)) return "slur";
// 8:
String simplifiedText = simplifyRepeatingLetters(strippedText);
// 9:
if (containsSwears(simplifiedText)) return "medium-high";
if (containsSlurs(simplifiedText)) return "slur";
// 10:
String finalText = removePeriodsAndSpaces(simplifiedText);
// 11:
if (containsSwears(finalText)) return "high";
if (containsSlurs(finalText)) return "slur";
return "safe";
}
private static String removeFalsePositives(String text) {
for (String falsePositive : swearWhitelist) {
text = text.replace(falsePositive, "");
}
return text;
}
private static boolean containsSwears(String text) {
for (String swear : swearBlacklist) {
if (text.contains(swear)) return true;
}
return false;
}
private static boolean containsSlurs(String text) {
for (String slur : slurs) {
if (text.contains(slur)) return true;
}
return false;
}
private static String convertLeetSpeakCharacters(String text) {
text = TextUtils.fromLeetString(text);
return text;
}
private static String stripSpecialCharacters(String text) {
text = text.replaceAll("[^A-Za-z0-9]", "").trim();
return text;
}
private static String simplifyRepeatingLetters(String text) {
text = TextUtils.replaceRepeatingLetters(text);
return text;
}
private static String removePeriodsAndSpaces(String text) {
return text.replace(".", "").replace(" ", "");
}
}

View File

@@ -0,0 +1,41 @@
package io.github.thetrouper.sentinel.server.util;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public final class ArrayUtils {
/**
* Transforms an array to another one
* @param e iterable list
* @param a action
* @return new transformed list
* @param <I> input
* @param <O> output
*/
public static <I,O> List<O> toNewList(Iterable<I> e, Function<I,O> a) {
List<O> list = new ArrayList<>();
e.forEach(i -> list.add(a.apply(i)));
return list;
}
public static <T> String list2string(List<T> list) {
return TextUtils.color("&7[&e" + String.join("&7, &e", ArrayUtils.toNewList(list, Object::toString)) + "&7]");
}
public static <T> List<T> bind(Iterable<T> tList, T... ts) {
List<T> list = Arrays.asList(ts);
tList.forEach(list::add);
return list;
}
public static class Constants {
public static final List<String> MATERIAL_NAMES = toNewList(Arrays.stream(Material.values()).toList(),m -> m.name().toLowerCase());
public static final List<String> ENTITY_NAMES = toNewList(Arrays.stream(EntityType.values()).toList(),e -> e.name().toLowerCase());
}
}

View File

@@ -1,6 +1,7 @@
package io.github.thetrouper.sentinel.server.util;
import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Config;
import io.github.thetrouper.sentinel.discord.WebhookSender;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
@@ -18,15 +19,19 @@ public class DeniedActions {
private static boolean opRemoved;
private static boolean denied;
public static void logPunishment(Player p, String type, String reason) {
}
public static void handleDeniedAction(Player p, String command) {
ServerUtils.sendDebugMessage(TextUtils.prefix("Handling denied command..."));
if (!Sentinel.logDangerousCommands) return;
if (!Config.logDangerousCommands) return;
ServerUtils.sendDebugMessage(TextUtils.prefix("LDC is enabled"));
logMessage = "]==-- Sentinel --==[\n" +
"A Dangerous command has been attempted!\n" +
"Player: " + p.getName() + "\n" +
"Command: " + command + "\n";
if (Sentinel.deop) {
if (Config.deop) {
ServerUtils.sendDebugMessage(TextUtils.prefix("Deoping player"));
p.setOp(false);
logMessage = logMessage + "Operator Removed: ✔\n";
@@ -35,7 +40,7 @@ public class DeniedActions {
logMessage = logMessage + "Operator Removed: ✘\n";
opRemoved = false;
}
if (Sentinel.ban) {
if (Config.ban) {
ServerUtils.sendDebugMessage(TextUtils.prefix("Banning player"));
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "ban " + p.getName() + " ]=- Sentinel Anti-Grief -=[ You have been banned for attempting a dangerous command. Contact an administrator if you believe this to be a mistake.");
logMessage = logMessage + "Banned: ✔\n";
@@ -52,12 +57,12 @@ public class DeniedActions {
WebhookSender.sendEmbedWarning(p.getName(),command,denied,opRemoved,banned);
}
public static void handleDeniedAction(Player p, Block block) {
if (!Sentinel.logCmdBlocks) return;
if (!Config.logCmdBlocks) return;
logMessage = "]==-- Sentinel --==[\n" +
"A Dangerous block usage has been detected!\n" +
"Player: " + p.getName() + "\n" +
"BlockType: " + block.getType() + "\n";
if (Sentinel.deop) {
if (Config.deop) {
p.setOp(false);
logMessage = logMessage + "Operator Removed: ✔\n";
opRemoved = true;
@@ -65,7 +70,7 @@ public class DeniedActions {
logMessage = logMessage + "Operator Removed: ✘\n";
opRemoved = false;
}
if (Sentinel.ban) {
if (Config.ban) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "ban " + p.getName() + " ]=- Sentinel Anti-Grief -=[ You have been banned for attempting to use dangerous blocks. Contact an administrator if you believe this to be a mistake.");
logMessage = logMessage + "Banned: ✔\n";
banned = true;
@@ -80,12 +85,12 @@ public class DeniedActions {
WebhookSender.sendEmbedWarning(p.getName(),block,denied,opRemoved,banned);
}
public static void handleDeniedAction(Player p, ItemStack i) {
if (!Sentinel.logNBT) return;
if (!Config.logNBT) return;
logMessage = "]==-- Sentinel --==[\n" +
"A Dangerous item has been detected!\n" +
"Player: " + p.getName() + "\n" +
"ItemType: " + i.getType() + "\n";
if (Sentinel.deop) {
if (Config.deop) {
p.setOp(false);
logMessage = logMessage + "Operator Removed: ✔\n";
opRemoved = true;
@@ -93,7 +98,7 @@ public class DeniedActions {
logMessage = logMessage + "Operator Removed: ✘\n";
opRemoved = false;
}
if (Sentinel.ban) {
if (Config.ban) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "ban " + p.getName() + " ]=- Sentinel Anti-Grief -=[ You have been banned for attempting to use an NBT item. Contact an administrator if you believe this to be a mistake.");
logMessage = logMessage + "Banned: ✔\n";
banned = true;

View File

@@ -1,23 +1,33 @@
/**
* This file is for tutorial purposes made by ImproperIssues. Distribute if you want :)
*/
package io.github.thetrouper.sentinel.server.util;
import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.commands.InfoCommand;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* Server utils
*/
public abstract class ServerUtils {
public class ServerUtils {
public static void sendCommand(String command) {
ServerUtils.sendDebugMessage("Getting scheduler");
Bukkit.getScheduler().scheduleSyncDelayedTask(Sentinel.getInstance(), () -> {
try {
ServerUtils.sendDebugMessage("Attempting to run command...");
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), command);
} catch (Exception e) {
e.printStackTrace();
}
},1);
}
public static void sendDebugMessage(String message) {
if (InfoCommand.debugmode) {
Sentinel.log.info(message);
@@ -28,37 +38,57 @@ public abstract class ServerUtils {
}
}
}
/**
* List of names of online players
* @return list of names
*/
public static List<String> listPlayers() {
List<String> list =new ArrayList<>();
Bukkit.getOnlinePlayers().forEach(p -> list.add(p.getName()));
return list;
public static List<Player> getPlayers() {
return new ArrayList<>(Bukkit.getOnlinePlayers());
}
/**
* List of names of online staff
* @return list of names
*/
public static List<String> listStaff() {
List<String> list =new ArrayList<>();
Bukkit.getOnlinePlayers().forEach(p -> {
if (p.isOp()) list.add(p.getName());
});
return list;
public static List<Player> getStaff() {
return getPlayers().stream().filter(Player -> Player.hasPermission("sentinel.staff")).toList();
}
/**
* List of names of online staff
* @return list of staff
*/
public static Set<Player> getStaff() {
Set<Player> list = new HashSet<>();
Bukkit.getOnlinePlayers().forEach(p -> {
if (p.isOp()) list.add(p);
public static void forEachPlayer(Consumer<Player> consumer) {
getPlayers().forEach(consumer);
}
public static void forEachStaff(Consumer<Player> consumer) {
getStaff().forEach(consumer);
}
public static void dmEachPlayer(Predicate<Player> condition, String dm) {
forEachPlayer(p -> {
if (condition.test(p)) p.sendMessage(dm);
});
return list;
}
public static void dmEachPlayer(String dm) {
forEachPlayer(p -> p.sendMessage(dm));
}
public static void forEachSpecified(Iterable<Player> players, Consumer<Player> consumer) {
players.forEach(consumer);
}
public static void forEachSpecified(Consumer<Player> consumer, Player... players) {
Arrays.stream(players).forEach(consumer);
}
public static void forEachPlayerRun(Predicate<Player> condition, Consumer<Player> task) {
forEachPlayer(p -> {
if (condition.test(p)) {
task.accept(p);
}
});
}
public static void sendActionBar(Player p, String msg) {
p.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(msg));
}
public static boolean hasBlockBelow(Player player, Material material) {
for (int y = player.getLocation().getBlockY() - 1; y >= player.getLocation().getBlockY() - 12; y--) {
if (player.getWorld().getBlockAt(player.getLocation().getBlockX(), y, player.getLocation().getBlockZ()).getType() == material) {
return true;
}
}
return false;
}
}

View File

@@ -2,11 +2,58 @@ package io.github.thetrouper.sentinel.server.util;
import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Config;
import java.util.Map;
import java.util.regex.PatternSyntaxException;
public class TextUtils {
public static String color(String s) {
return s.replaceAll("&","§");
}
public static String prefix(String text) {
String prefix = Sentinel.prefix;
return prefix + text;
}
public static String replaceRepeatingLetters(String message) {
StringBuilder result = new StringBuilder();
char prevChar = '\0';
int count = 0;
for (char c : message.toCharArray()) {
if (c == prevChar) {
count++;
if (count <= 3) {
result.append(c);
}
} else {
prevChar = c;
count = 1;
result.append(c);
}
}
return result.toString();
}
public static String fromLeetString(String s) {
Map<String, String> dictionary = Config.leetPatterns;
String msg = s;
for (String key : dictionary.keySet()) {
if (!s.contains(key)) continue;
try {
if (key.equals("$")) {
msg = msg.replaceAll("\\$", "s");
}
else {
msg = msg.replaceAll(key, dictionary.get(key));
}
}
catch (PatternSyntaxException ex) {
String regex = "[" + key + "]";
msg = msg.replaceAll(regex, dictionary.get(key));
}
}
return msg;
}
}

View File

@@ -11,39 +11,73 @@
# Be sure to check out their amazing discord bot!
config :
plugin:
# -------------------------------
# Important Setup (Do this first)
# -------------------------------
# --------------------------------
# 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"
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.
prevent-nbt: true # Defaulted true | Should NBT items be blocked from the creative hotbar
log-nbt: true # Defaulted true | Should items and their NBT's be logged
prevent-cmdblocks: true # Defaulted true | Should all command block actions be blocked
log-cmdblocks: true # Defaulted true | Log attempts of command-block place-ery
dangerous: # These commands can only be run by "trusted" users
- "op"
- "deop"
- "stop"
- "execute"
- "sudo"
- ""
log-dangerous: true # Default true | Weather or not to log when a dangerous command is executed
log-cmdblocks: true # Defaulted true | Log attempts of command-block place-ery
log-nbt: true # Defaulted true | Should items and their NBT's be logged
logged: # Commands that will always be logged when executed.
- "gamemode"
- "give"
deop: true # Defaulted true | This will remove an untrusted player's operator permissions whenever they attempt dangerous actions
ban: false # Defaulted false | This will ban a player when they attempt dangerous actions
ban: false
nbt-punish: false # Defaulted false | This will ban a player when they attempt to use an NBT item
cmdblock-punish: false # Defaulted false | This will ban a player when they attempt to use a command block
command-punish: true # Defaulted true | This will ban a player when they attempt to use a dangerous command
reop-command: false # Defaulted false | This enables the command allowing trusted players to op themselves if they get deoped.
# -------------------------------
# Chat Filter Setup & AntiSpam
# -------------------------------
chat:
anti-unicode: true # Default true | Prevents all non A-Z 0-9 + specials from being sent in chat
anti-spam:
# AntiSpam Heat system
anti-spam: true # Default true | Enables the anti-spam
default-gain: 1 # Heat gained as base for every message
medium-gain: 3 # Heat gained when your message is 50% similar
high-gain: 6 # Heat gained for
max-heat: 15 # Highest value of heat a player can reach
enabled: true # Default true | Enables/disables the entire anti-spam
default-gain: 1 # Default 1 | Heat gained as base for every message
low-gain: 2 # Default 2 | Heat gained when message is >25% similar
medium-gain: 4 # Default 4 | Heat gained when message is >50% similar
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-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
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!"
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
- ass
slurs: # List slurs here that you wish to insta-punish for attempting
- nigg
leet-patterns:
'0': o
'1': i
'3': e
'4': a

View File

@@ -9,6 +9,29 @@ permissions:
sentinel.info:
description: Permission to view sentinel info
default: op
sentinel.staff:
description: Receive anti-swear and anti-spam warnings
default: op
sentinel.chat.antiswear.flags:
description: See antiSwear flags
default: op
sentinel.chat.antiswear.bypass:
description: Bypass the antiSwear
default: op
sentinel.chat.antispam.flags:
description: See antispam flags
default: op
sentinel.chat.antispam.bypass:
description: Bypass the antispam
default: op
sentinel.chat.*:
description: bypass all chat rules and see all flags
default: op
children:
sentinel.chat.antiswear.flags: true
sentinel.chat.antiswear.bypass: true
sentinel.chat.antispam.flags: true
sentinel.chat.antispam.bypass: true
commands:
sentinel:
description: An info command.