Updated AntiSpam

This commit is contained in:
obvWolf
2024-02-21 16:43:29 -06:00
parent 18e0ad4c02
commit 78d6518bcd
15 changed files with 412 additions and 392 deletions

View File

@@ -137,10 +137,6 @@ public final class Sentinel extends JavaPlugin {
// Plugin startup logic // Plugin startup logic
log.info("Starting Up! (%s)...".formatted(getDescription().getVersion())); log.info("Starting Up! (%s)...".formatted(getDescription().getVersion()));
// Enable Functions
AntiSpam.enableAntiSpam();
ProfanityFilter.enableAntiSwear();
// Commands // Commands
new SentinelCommand().register(); new SentinelCommand().register();
new MessageCommand().register(); new MessageCommand().register();

View File

@@ -7,12 +7,14 @@ import io.github.itzispyder.pdk.commands.Permission;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder; import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import io.github.itzispyder.pdk.utils.misc.Cooldown; import io.github.itzispyder.pdk.utils.misc.Cooldown;
import io.github.thetrouper.sentinel.Sentinel; import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Report;
import io.github.thetrouper.sentinel.server.functions.ReportFalsePositives; import io.github.thetrouper.sentinel.server.functions.ReportFalsePositives;
import io.github.thetrouper.sentinel.server.util.Text; import io.github.thetrouper.sentinel.server.util.Text;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.UUID; import java.util.UUID;
@CommandRegistry(value = "sentinelcallback", permission = @Permission("sentinel.callbacks"), printStackTrace = true) @CommandRegistry(value = "sentinelcallback", permission = @Permission("sentinel.callbacks"), printStackTrace = true)
public class ChatClickCallback implements CustomCommand { public class ChatClickCallback implements CustomCommand {
Cooldown<UUID> fpReportCooldown = new Cooldown<>(); Cooldown<UUID> fpReportCooldown = new Cooldown<>();
@@ -24,7 +26,14 @@ public class ChatClickCallback implements CustomCommand {
if (fpReportCooldown.isOnCooldown(p.getUniqueId()) && !p.isOp()) { if (fpReportCooldown.isOnCooldown(p.getUniqueId()) && !p.isOp()) {
p.sendMessage(Text.prefix(Sentinel.language.get("cooldown") + fpReportCooldown.getCooldown(p.getUniqueId()))); p.sendMessage(Text.prefix(Sentinel.language.get("cooldown") + fpReportCooldown.getCooldown(p.getUniqueId())));
} else { } else {
ReportFalsePositives.sendFalsePositiveReport(ReportFalsePositives.reports.get(args.get(1).toLong())); long id = args.get(1).toLong();
Report send = ReportFalsePositives.reports.get(id);
if (send == null) {
p.sendMessage(Text.prefix(Sentinel.language.get("no-report")));
return;
}
p.sendMessage(Text.prefix(Sentinel.language.get("reporting-false-positive")));
ReportFalsePositives.sendFalsePositiveReport(send);
p.sendMessage(Text.prefix(Sentinel.language.get("false-positive-report-success"))); p.sendMessage(Text.prefix(Sentinel.language.get("false-positive-report-success")));
} }
} }

View File

@@ -1,13 +1,13 @@
package io.github.thetrouper.sentinel.data; package io.github.thetrouper.sentinel.data;
public class Emojis { public class Emojis {
public static String space = "<:space:1125871914334818446>"; public static String space = "<:space:1210008300515762238>";
public static String rightSort = "<:rightSort:1125785837255270520>"; public static String rightSort = "<:rightSort:1210008337144479754>";
public static String arrowRight = "<:arrowRight:1125785471520354304>"; public static String rightArrow = "<:rightArrow:1210008295738179594>";
public static String rightDoubleArrow = "<:rightDoubleArrow:1125785800353783868>"; public static String rightDoubleArrow = "<:rightDoubleArrow:1210008296723976224>";
public static String activity = "<:activity:1125785527468167178>"; public static String activity = "<:activity:1125785527468167178>";
public static String alarm = "<:alarm:1125790301873770606>"; public static String alarm = "<:alarm:1210008289635475547>";
public static String target = "<:target:1125788461371232307>"; public static String target = "<:target:1210008303992701068>";
public static String bot = "<:bot:1125791121851826206>"; public static String bot = "<:bot:1125791121851826206>";
public static String cancel = "<:cancel:1125785769471127694>"; public static String cancel = "<:cancel:1125785769471127694>";
public static String creation = "<:creation:1125790610729730109>"; public static String creation = "<:creation:1125790610729730109>";
@@ -15,19 +15,19 @@ public class Emojis {
public static String kick = "<:kick:1125785612595761212>"; public static String kick = "<:kick:1125785612595761212>";
public static String members = "<:members:1125791101199077426>"; public static String members = "<:members:1125791101199077426>";
public static String mute = "<:mute:1125789032937435247>"; public static String mute = "<:mute:1125789032937435247>";
public static String noDM = "<:noDM:1125790359423824022>"; public static String noDM = "<:noDM:1210008293729370204>";
public static String owner = "<:owner:1125791175559876669>"; public static String owner = "<:owner:1125791175559876669>";
public static String potentialDanger = "<:potentialDanger:1125788513971998741>"; public static String potentialDanger = "<:potentialDanger:1125788513971998741>";
public static String roles = "<:roles:1125790513933594645>"; public static String roles = "<:roles:1125790513933594645>";
public static String separator = "<:separator:1125790817626357861>"; public static String separator = "<:separator:1125790817626357861>";
public static String splash = "<:splash:1125791213933563905>"; public static String splash = "<:splash:1125791213933563905>";
public static String success = "<:success:1125785728161419356>"; public static String success = "<:success:1210008354039275570>";
public static String suspicious = "<:suspicious:1125790709371371682>"; public static String suspicious = "<:suspicious:1125790709371371682>";
public static String trustedAdmin = "<:trustedAdmin:1125785574591180822>"; public static String trustedAdmin = "<:trustedAdmin:1210008362230743080>";
public static String upvoter = "<:upvoter:1125790659735977994>"; public static String upvoter = "<:upvoter:1125790659735977994>";
public static String vanity = "<:vanity:1125791060594004039>"; public static String vanity = "<:vanity:1125791060594004039>";
public static String webhook = "<:webhook:1125790545638330388>"; public static String webhook = "<:webhook:1125790545638330388>";
public static String failure = "<:failure:1125241087909429369>"; public static String failure = "<:failure:1210008290625462432>";
public static String nuke = "<:nuke:1125244368807280702>"; public static String nuke = "<:nuke:1210008294756712478>";
public static String member = "<:member:1125244044407218176>"; public static String member = "<:member:1210008291174785105>";
} }

View File

@@ -3,7 +3,8 @@ package io.github.thetrouper.sentinel.data;
import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
public record Report(long id, AsyncPlayerChatEvent event, HashMap<String,String> stepsTaken) { public record Report(long id, AsyncPlayerChatEvent event, LinkedHashMap<String,String> stepsTaken) {
} }

View File

@@ -50,6 +50,8 @@ public class LanguageFile implements JsonSerializable<LanguageFile> {
put("unicode-notification", "§b§n%1$s§7 has triggered the anti-unicode."); put("unicode-notification", "§b§n%1$s§7 has triggered the anti-unicode.");
put("unicode-notification-hover", "§8]==-- §d§lSentinel §8--==[\n§bMessage: §f%1$s"); put("unicode-notification-hover", "§8]==-- §d§lSentinel §8--==[\n§bMessage: §f%1$s");
put("no-plugins-for-u", "§cThis server wishes to keep their plugins confidential."); put("no-plugins-for-u", "§cThis server wishes to keep their plugins confidential.");
put("reporting-false-positive","Sending report to staff...");
put("no-report","§cThe report you requested either does not exist, or has expired!");
}}; }};
public LanguageFile() {} public LanguageFile() {}

View File

@@ -22,9 +22,9 @@ public class MainConfig implements JsonSerializable<MainConfig> {
public String prefix = "§d§lSentinel §8» §7"; public String prefix = "§d§lSentinel §8» §7";
public String webhook = "https://discord.com/api/webhooks/id/token"; public String webhook = "https://discord.com/api/webhooks/id/token";
public String lang = "en-us.json"; public String lang = "en-us.json";
public List<String> trustedPlayers = new ArrayList<>() {{ public List<String> trustedPlayers = List.of(
add("049460f7-21cb-42f5-8059-d42752bf406f"); "049460f7-21cb-42f5-8059-d42752bf406f"
}}; );
public boolean blockSpecific = true; public boolean blockSpecific = true;
public boolean preventNBT = true; public boolean preventNBT = true;
public boolean preventCmdBlockPlace = true; public boolean preventCmdBlockPlace = true;
@@ -53,25 +53,30 @@ public class MainConfig implements JsonSerializable<MainConfig> {
"perms", "perms",
"perm", "perm",
"permission", "permission",
"permissions" "permissions",
"pm",
"pluginmanager",
"rl",
"reload",
"plugman"
); );
public boolean logDangerous = true; public boolean logDangerous = true;
public boolean logCmdBlocks = true; public boolean logCmdBlocks = true;
public boolean logNBT = true; public boolean logNBT = true;
public boolean logSpecific = false; public boolean logSpecific = false;
public List<String> logged = new ArrayList<>() {{ public List<String> logged = List.of(
add("give"); "give",
add("item"); "item"
}}; );
public boolean deop = true; public boolean deop = true;
public boolean nbtPunish = false; public boolean nbtPunish = false;
public boolean cmdBlockPunish = false; public boolean cmdBlockPunish = false;
public boolean commandPunish = false; public boolean commandPunish = false;
public boolean specificPunish = false; public boolean specificPunish = false;
public List<String> punishCommands = new ArrayList<>() {{ public List<String> punishCommands = List.of(
add("smite %player%"); "smite %player%",
add("ban %player% ]=- Sentinel -=[ You have been banned for attempting a dangerous action. If you believe this to be a mistake, please contact the server owner."); "ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
}}; );
public boolean reopCommand = false; public boolean reopCommand = false;
public boolean pluginHider = true; public boolean pluginHider = true;
} }

View File

@@ -14,84 +14,84 @@ public class SwearsConfig implements JsonSerializable<SwearsConfig> {
return file; return file;
} }
public List<String> swears = new ArrayList<>() {{ public List<String> swears = List.of(
add("anal"); "anal",
add("anus"); "anus",
add("arse"); "arse",
add("ass"); "ass",
add("ballsack"); "ballsack",
add("balls"); "balls",
add("bastard"); "bastard",
add("bitch"); "bitch",
add("btch"); "btch",
add("biatch"); "biatch",
add("blowjob"); "blowjob",
add("bollock"); "bollock",
add("bollok"); "bollok",
add("boner"); "boner",
add("boob"); "boob",
add("bugger"); "bugger",
add("butt"); "butt",
add("choad"); "choad",
add("clitoris"); "clitoris",
add("cock"); "cock",
add("coon"); "coon",
add("crap"); "crap",
add("cum"); "cum",
add("cunt"); "cunt",
add("dick"); "dick",
add("dildo"); "dildo",
add("douchebag"); "douchebag",
add("dyke"); "dyke",
add("feck"); "feck",
add("fellate"); "fellate",
add("fellatio"); "fellatio",
add("felching"); "felching",
add("fuck"); "fuck",
add("fudgepacker"); "fudgepacker",
add("flange"); "flange",
add("gtfo"); "gtfo",
add("hoe"); "hoe",
add("horny"); "horny",
add("incest"); "incest",
add("jerk"); "jerk",
add("jizz"); "jizz",
add("labia"); "labia",
add("masturb"); "masturb",
add("muff"); "muff",
add("nazi"); "nazi",
add("nipple"); "nipple",
add("nips"); "nips",
add("nude"); "nude",
add("pedophile"); "pedophile",
add("penis"); "penis",
add("piss"); "piss",
add("poop"); "poop",
add("porn"); "porn",
add("prick"); "prick",
add("prostit"); "prostit",
add("pube"); "pube",
add("pussie"); "pussie",
add("pussy"); "pussy",
add("queer"); "queer",
add("rape"); "rape",
add("rapist"); "rapist",
add("retard"); "retard",
add("rimjob"); "rimjob",
add("scrotum"); "scrotum",
add("sex"); "sex",
add("shit"); "shit",
add("slut"); "slut",
add("spunk"); "spunk",
add("stfu"); "stfu",
add("suckmy"); "suckmy",
add("tits"); "tits",
add("tittie"); "tittie",
add("titty"); "titty",
add("turd"); "turd",
add("twat"); "twat",
add("vagina"); "vagina",
add("wank"); "wank",
add("whore"); "whore"
}}; );
} }

View File

@@ -1,6 +1,7 @@
package io.github.thetrouper.sentinel.events; package io.github.thetrouper.sentinel.events;
import io.github.itzispyder.pdk.events.CustomListener; import io.github.itzispyder.pdk.events.CustomListener;
import io.github.itzispyder.pdk.utils.ArrayUtils;
import io.github.thetrouper.sentinel.Sentinel; import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Report; import io.github.thetrouper.sentinel.data.Report;
import io.github.thetrouper.sentinel.server.functions.AdvancedBlockers; import io.github.thetrouper.sentinel.server.functions.AdvancedBlockers;
@@ -26,6 +27,14 @@ public class ChatEvent implements CustomListener {
Report report = ReportFalsePositives.initializeReport(e); Report report = ReportFalsePositives.initializeReport(e);
ServerUtils.sendDebugMessage("""
Creating a chat report...
ID %s
Player %s
Message %s
Fields %s
""".formatted(report.id(),report.event().getPlayer(),report.event().getMessage(), report.stepsTaken().toString()));
handleEventIfNotBypassed(p, handleEventIfNotBypassed(p,
"sentinel.chat.antiunicode.bypass", "sentinel.chat.antiunicode.bypass",
Sentinel.mainConfig.chat.useAntiUnicode, "unicode", Sentinel.mainConfig.chat.useAntiUnicode, "unicode",
@@ -52,16 +61,22 @@ public class ChatEvent implements CustomListener {
ProfanityFilter.handleProfanityFilter(event,report); ProfanityFilter.handleProfanityFilter(event,report);
}); });
ServerUtils.sendDebugMessage("""
Adding a report to the list...
ID %s
Fields %s
""".formatted(report.id(), report.stepsTaken().toString()));
ReportFalsePositives.reports.put(report.id(),report); ReportFalsePositives.reports.put(report.id(),report);
AntiSpam.lastMessageMap.put(p, e.getMessage());
} }
private static void handleEventIfNotBypassed(Player p, String permission, boolean isEnabled, String eventType, AsyncPlayerChatEvent e, Consumer<AsyncPlayerChatEvent> handler) { private static void handleEventIfNotBypassed(Player p, String permission, boolean isEnabled, String eventType, AsyncPlayerChatEvent e, Consumer<AsyncPlayerChatEvent> handler) {
if (!Sentinel.isTrusted(p) || !p.hasPermission(permission)) { if (!Sentinel.isTrusted(p) || !p.hasPermission(permission)) {
ServerUtils.sendDebugMessage("ChatEvent: Permission bypass failed, checking for " + eventType); ServerUtils.sendDebugMessage("ChatEvent: Permission bypass failed, checking for " + eventType);
if (isEnabled) { if (e.isCancelled()) return;
if (!isEnabled) return;
ServerUtils.sendDebugMessage("ChatEvent: " + eventType + " check enabled, continuing!"); ServerUtils.sendDebugMessage("ChatEvent: " + eventType + " check enabled, continuing!");
handler.accept(e); handler.accept(e);
} }
} }
}
} }

View File

@@ -6,8 +6,7 @@ import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Emojis; import io.github.thetrouper.sentinel.data.Emojis;
import io.github.thetrouper.sentinel.data.FAT; import io.github.thetrouper.sentinel.data.FAT;
import io.github.thetrouper.sentinel.data.FilterSeverity; import io.github.thetrouper.sentinel.data.FilterSeverity;
import io.github.thetrouper.sentinel.server.functions.AdvancedBlockers; import io.github.thetrouper.sentinel.data.Report;
import io.github.thetrouper.sentinel.server.functions.ReportFalsePositives;
import io.github.thetrouper.sentinel.server.util.ServerUtils; import io.github.thetrouper.sentinel.server.util.ServerUtils;
import io.github.thetrouper.sentinel.server.util.Text; import io.github.thetrouper.sentinel.server.util.Text;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
@@ -16,6 +15,7 @@ import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import static io.github.thetrouper.sentinel.server.functions.AntiSpam.heatMap; import static io.github.thetrouper.sentinel.server.functions.AntiSpam.heatMap;
@@ -24,34 +24,49 @@ import static io.github.thetrouper.sentinel.server.functions.ProfanityFilter.*;
public class FilterAction { public class FilterAction {
public static void filterPunish(AsyncPlayerChatEvent e, FAT type, Double similarity, FilterSeverity severity) { public static void filterPunish(AsyncPlayerChatEvent e, FAT type, Double similarity, FilterSeverity severity, long reportID) {
String report = "This action is not reportable."; long similar = Math.round(similarity);
TextComponent staffNotif = Component.text(""); long report = reportID;
TextComponent playerWarning = Component.text("");
Player offender = e.getPlayer(); Player offender = e.getPlayer();
switch (type) { switch (type) {
case BLOCK_UNICODE -> { case BLOCK_UNICODE -> handleUnicodeBlock(e,offender,type,report);
staffNotif = Component case BLOCK_URL -> handleURLBlock(e,offender,type,report);
case BLOCK_SPAM -> handleSpamBlock(e,type,offender,report,similar);
case SPAM_PUNISH -> handleSpamPunish(e,type,offender,report,similar);
case BLOCK_SWEAR -> handleSwearBlock(e,type,offender,report,severity);
case SWEAR_PUNISH -> handleSwearPunish(e,type,offender,report,severity);
case SLUR_PUNISH -> handleSlur(e,type,offender,report,severity);
}
}
public static void handleUnicodeBlock(AsyncPlayerChatEvent e, Player offender, FAT type, long report) {
TextComponent staffNotif = Component
.text(Text.prefix(Sentinel.language.get("unicode-notification") .text(Text.prefix(Sentinel.language.get("unicode-notification")
.formatted(offender.getName()))) .formatted(offender.getName())))
.hoverEvent(Component.text(Sentinel.language.get("unicode-notification-hover") .hoverEvent(Component.text(Sentinel.language.get("unicode-notification-hover")
.formatted(e.getMessage()))); .formatted(e.getMessage())));
playerWarning = Component TextComponent playerWarning = Component
.text(Text.prefix(Sentinel.language.get("unicode-warn"))); .text(Text.prefix(Sentinel.language.get("unicode-warn")));
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
} }
case BLOCK_URL -> {
staffNotif = Component public static void handleURLBlock(AsyncPlayerChatEvent e, Player offender, FAT type, long report) {
TextComponent staffNotif = Component
.text(Text.prefix(Sentinel.language.get("url-notification") .text(Text.prefix(Sentinel.language.get("url-notification")
.formatted(offender.getName()))) .formatted(offender.getName())))
.hoverEvent(Component.text(Sentinel.language.get("url-notification-hover") .hoverEvent(Component.text(Sentinel.language.get("url-notification-hover")
.formatted(Text.color(Text.regexHighlighter(e.getMessage(),Sentinel.advConfig.urlRegex," &e> &n","&r &e<&f "))))); .formatted(Text.color(Text.regexHighlighter(e.getMessage(),Sentinel.advConfig.urlRegex," &e> &n","&r &e<&f ")))));
playerWarning = Component TextComponent playerWarning = Component
.text(Text.prefix(Sentinel.language.get("url-warn"))); .text(Text.prefix(Sentinel.language.get("url-warn")));
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
} }
case BLOCK_SPAM -> {
public static void handleSpamBlock(AsyncPlayerChatEvent e, FAT type, Player offender, long report, double similarity) {
if (Sentinel.mainConfig.chat.antiSpam.clearChat) ServerUtils.sendCommand(Sentinel.mainConfig.chat.antiSpam.chatClearCommand); if (Sentinel.mainConfig.chat.antiSpam.clearChat) ServerUtils.sendCommand(Sentinel.mainConfig.chat.antiSpam.chatClearCommand);
staffNotif = Component TextComponent staffNotif = Component
.text(Text.prefix(String.format(Sentinel.language.get("spam-notification"), .text(Text.prefix(String.format(Sentinel.language.get("spam-notification"),
offender.getName(), offender.getName(),
heatMap.get(offender), heatMap.get(offender),
@@ -63,11 +78,15 @@ public class FilterAction {
similarity similarity
))); )));
playerWarning = Component.text(Text.prefix(Sentinel.language.get("spam-block-warn"))); TextComponent playerWarning = Component.text(Text.prefix(Sentinel.language.get("spam-block-warn")));
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
} }
case SPAM_PUNISH -> {
public static void handleSpamPunish(AsyncPlayerChatEvent e, FAT type, Player offender, long report, double similarity) {
if (Sentinel.mainConfig.chat.antiSpam.clearChat) ServerUtils.sendCommand(Sentinel.mainConfig.chat.antiSpam.chatClearCommand); if (Sentinel.mainConfig.chat.antiSpam.clearChat) ServerUtils.sendCommand(Sentinel.mainConfig.chat.antiSpam.chatClearCommand);
staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("spam-mute-notification"),
TextComponent staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("spam-mute-notification"),
offender.getName(), offender.getName(),
heatMap.get(offender), heatMap.get(offender),
Sentinel.mainConfig.chat.antiSpam.punishHeat Sentinel.mainConfig.chat.antiSpam.punishHeat
@@ -78,13 +97,15 @@ public class FilterAction {
similarity similarity
))); )));
playerWarning = Component.text(Sentinel.language.get("spam-mute-warn")); TextComponent playerWarning = Component.text(Sentinel.language.get("spam-mute-warn"));
sendConsoleLog(offender,e,type); sendConsoleLog(offender,e,type);
if (Sentinel.mainConfig.chat.antiSpam.logSpam) sendDiscordLog(offender,e,type); if (Sentinel.mainConfig.chat.antiSpam.logSpam) sendDiscordLog(offender,e,type);
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
} }
case BLOCK_SWEAR -> {
report = ReportFalsePositives.generateReport(e); public static void handleSwearBlock(AsyncPlayerChatEvent e, FAT type, Player offender, long report, FilterSeverity severity) {
staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("profanity-block-notification"), TextComponent staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("profanity-block-notification"),
offender.getName(), offender.getName(),
scoreMap.get(offender), scoreMap.get(offender),
Sentinel.mainConfig.chat.antiSwear.punishScore Sentinel.mainConfig.chat.antiSwear.punishScore
@@ -95,13 +116,14 @@ public class FilterAction {
severity.name() severity.name()
))); )));
playerWarning = Component.text(Text.prefix(Sentinel.language.get("profanity-block-warn"))) TextComponent playerWarning = Component.text(Text.prefix(Sentinel.language.get("profanity-block-warn")))
.hoverEvent(Component.text(Sentinel.language.get("action-automatic-reportable"))) .hoverEvent(Component.text(Sentinel.language.get("action-automatic-reportable")))
.clickEvent(ClickEvent.runCommand("sentinelcallback fpreport " + report)); .clickEvent(ClickEvent.runCommand("sentinelcallback fpreport " + report));
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
} }
case SWEAR_PUNISH -> { public static void handleSwearPunish(AsyncPlayerChatEvent e, FAT type, Player offender, long report, FilterSeverity severity) {
report = ReportFalsePositives.generateReport(e); TextComponent staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("profanity-mute-notification"),
staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("profanity-mute-notification"),
offender.getName(), offender.getName(),
scoreMap.get(offender), scoreMap.get(offender),
Sentinel.mainConfig.chat.antiSwear.punishScore Sentinel.mainConfig.chat.antiSwear.punishScore
@@ -112,14 +134,16 @@ public class FilterAction {
severity.name() severity.name()
))); )));
playerWarning = Component.text(Text.prefix(Sentinel.language.get("profanity-mute-warn"))) TextComponent playerWarning = Component.text(Text.prefix(Sentinel.language.get("profanity-mute-warn")))
.hoverEvent(Component.text(Sentinel.language.get("action-automatic-reportable"))); .hoverEvent(Component.text(Sentinel.language.get("action-automatic-reportable")));
sendConsoleLog(offender,e,type); sendConsoleLog(offender,e,type);
if (Sentinel.mainConfig.chat.antiSwear.logSwears) sendDiscordLog(offender,e,type); if (Sentinel.mainConfig.chat.antiSwear.logSwears) sendDiscordLog(offender,e,type);
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
} }
case SLUR_PUNISH -> {
report = ReportFalsePositives.generateReport(e); public static void handleSlur(AsyncPlayerChatEvent e, FAT type, Player offender, long report, FilterSeverity severity) {
staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("slur-mute-notification"), TextComponent staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("slur-mute-notification"),
offender.getName(), offender.getName(),
scoreMap.get(offender), scoreMap.get(offender),
Sentinel.mainConfig.chat.antiSwear.punishScore Sentinel.mainConfig.chat.antiSwear.punishScore
@@ -130,12 +154,15 @@ public class FilterAction {
severity.name() severity.name()
))); )));
playerWarning = Component.text(Text.prefix(Sentinel.language.get("slur-mute-warn"))) TextComponent playerWarning = Component.text(Text.prefix(Sentinel.language.get("slur-mute-warn")))
.hoverEvent(Component.text(Sentinel.language.get("action-automatic-reportable"))); .hoverEvent(Component.text(Sentinel.language.get("action-automatic-reportable")));
sendConsoleLog(offender,e,type); sendConsoleLog(offender,e,type);
if (Sentinel.mainConfig.chat.antiSwear.logSwears) sendDiscordLog(offender,e,type); if (Sentinel.mainConfig.chat.antiSwear.logSwears) sendDiscordLog(offender,e,type);
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
} }
}
public static void sendWarnings(AsyncPlayerChatEvent e, FAT type, Player offender, TextComponent staffNotif, TextComponent playerWarning, long report) {
if (type.getExecutedCommand() != null) { if (type.getExecutedCommand() != null) {
ServerUtils.sendCommand(type.getExecutedCommand().replace("%player%", offender.getName())); ServerUtils.sendCommand(type.getExecutedCommand().replace("%player%", offender.getName()));
} }
@@ -196,7 +223,7 @@ public class FilterAction {
case SPAM_PUNISH -> { case SPAM_PUNISH -> {
description.append(String.format("\n%1$s%2$sHeat: `%3$s/%4$s`", description.append(String.format("\n%1$s%2$sHeat: `%3$s/%4$s`",
Emojis.space, Emojis.space,
Emojis.arrowRight, Emojis.rightArrow,
heatMap.get(offender), heatMap.get(offender),
Sentinel.mainConfig.chat.antiSpam.punishHeat Sentinel.mainConfig.chat.antiSpam.punishHeat
)); ));
@@ -209,7 +236,7 @@ public class FilterAction {
case SWEAR_PUNISH, SLUR_PUNISH -> { case SWEAR_PUNISH, SLUR_PUNISH -> {
description.append(String.format("\n%1$s%2$sScore: `%3$s/%4$s`", description.append(String.format("\n%1$s%2$sScore: `%3$s/%4$s`",
Emojis.space, Emojis.space,
Emojis.arrowRight, Emojis.rightArrow,
scoreMap.get(offender), scoreMap.get(offender),
Sentinel.mainConfig.chat.antiSwear.punishScore Sentinel.mainConfig.chat.antiSwear.punishScore
)); ));

View File

@@ -24,19 +24,22 @@ public class AdvancedBlockers {
} }
public static void handleAntiUnicode(AsyncPlayerChatEvent e, Report report) { public static void handleAntiUnicode(AsyncPlayerChatEvent e, Report report) {
if (e.isCancelled()) return;
String message = Text.removeFirstColor(e.getMessage()); String message = Text.removeFirstColor(e.getMessage());
report.stepsTaken().put("Anti-Unicode", "`%s`".formatted(message)); report.stepsTaken().put("Anti-Unicode", "`%s`".formatted(message));
ServerUtils.sendDebugMessage("AdvBlocker: Checking for unicode: " + message); ServerUtils.sendDebugMessage("AdvBlocker: Checking for unicode: " + message);
String nonAllowed = message.replaceAll(Sentinel.advConfig.allowedCharRegex, "").trim(); String nonAllowed = message.replaceAll(Sentinel.advConfig.allowedCharRegex, "").trim();
if (nonAllowed.length() != 0) { if (nonAllowed.length() != 0) {
ServerUtils.sendDebugMessage("AdvBlocker: Caught Unicode: " + nonAllowed); ServerUtils.sendDebugMessage("AdvBlocker: Caught Unicode: " + nonAllowed);
e.setCancelled(true); e.setCancelled(true);
report.stepsTaken().replace("Anti-Unicode", "`%s` %s".formatted(message, Emojis.alarm)); report.stepsTaken().replace("Anti-Unicode", "`%s` %s".formatted(message, Emojis.alarm));
FilterAction.filterPunish(e,FAT.BLOCK_UNICODE,null,null); FilterAction.filterPunish(e,FAT.BLOCK_UNICODE,null,null,report.id());
} }
} }
public static void handleSwearRegex(AsyncPlayerChatEvent e, Report report) { public static void handleSwearRegex(AsyncPlayerChatEvent e, Report report) {
if (e.isCancelled()) return;
String swearRegex = Sentinel.advConfig.swearRegex; String swearRegex = Sentinel.advConfig.swearRegex;
Pattern pattern = Pattern.compile(swearRegex, Pattern.CASE_INSENSITIVE); Pattern pattern = Pattern.compile(swearRegex, Pattern.CASE_INSENSITIVE);
@@ -44,16 +47,16 @@ public class AdvancedBlockers {
report.stepsTaken().put("Anti-Swear Regex", "`%s`".formatted(e.getMessage())); report.stepsTaken().put("Anti-Swear Regex", "`%s`".formatted(e.getMessage()));
String highlighted = Text.regexHighlighter(swearRegex,e.getMessage()," > "," < ");
if (matcher.find()) { if (matcher.find()) {
e.setCancelled(true); e.setCancelled(true);
String highlighted = Text.regexHighlighter(swearRegex,e.getMessage()," > "," < ");
report.stepsTaken().replace("Anti-Swear Regex", "`%s` %s".formatted(highlighted, Emojis.alarm)); report.stepsTaken().replace("Anti-Swear Regex", "`%s` %s".formatted(highlighted, Emojis.alarm));
FilterAction.filterPunish(e,FAT.SWEAR_PUNISH,null,FilterSeverity.HIGH); FilterAction.filterPunish(e,FAT.SWEAR_PUNISH,null,FilterSeverity.HIGH,report.id());
} }
} }
public static void handleStrictRegex(AsyncPlayerChatEvent e, Report report) { public static void handleStrictRegex(AsyncPlayerChatEvent e, Report report) {
if (e.isCancelled()) return;
String strictRegex = Sentinel.advConfig.strictRegex; String strictRegex = Sentinel.advConfig.strictRegex;
Pattern pattern = Pattern.compile(strictRegex, Pattern.CASE_INSENSITIVE); Pattern pattern = Pattern.compile(strictRegex, Pattern.CASE_INSENSITIVE);
@@ -61,23 +64,27 @@ public class AdvancedBlockers {
report.stepsTaken().put("Strict Regex", "`%s`".formatted(e.getMessage())); report.stepsTaken().put("Strict Regex", "`%s`".formatted(e.getMessage()));
String highlighted = Text.regexHighlighter(strictRegex,e.getMessage()," > "," < ");
if (matcher.find()) { if (matcher.find()) {
e.setCancelled(true); e.setCancelled(true);
String highlighted = Text.regexHighlighter(strictRegex,e.getMessage()," > "," < ");
report.stepsTaken().replace("Strict Regex", "`%s` %s".formatted(highlighted, Emojis.alarm)); report.stepsTaken().replace("Strict Regex", "`%s` %s".formatted(highlighted, Emojis.alarm));
FilterAction.filterPunish(e, FAT.SLUR_PUNISH,null, FilterSeverity.SLUR); FilterAction.filterPunish(e, FAT.SLUR_PUNISH,null, FilterSeverity.SLUR,report.id());
} }
} }
public static void handleAntiURL(AsyncPlayerChatEvent e, Report report) { public static void handleAntiURL(AsyncPlayerChatEvent e, Report report) {
if (e.isCancelled()) return;
String urlRegex = Sentinel.advConfig.urlRegex; String urlRegex = Sentinel.advConfig.urlRegex;
Pattern pattern = Pattern.compile(urlRegex, Pattern.CASE_INSENSITIVE); Pattern pattern = Pattern.compile(urlRegex, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(e.getMessage()); Matcher matcher = pattern.matcher(e.getMessage());
ServerUtils.sendDebugMessage("AdvBlocker: Checking for URLs against regex `%1$s`:%2$s".formatted(urlRegex, e.getMessage())); ServerUtils.sendDebugMessage("AdvBlocker: Checking for URLs against regex `%1$s`:%2$s".formatted(urlRegex, e.getMessage()));
report.stepsTaken().replace("Anti-URL", "`%s` %s".formatted(e.getMessage(), Emojis.alarm)); report.stepsTaken().put("Anti-URL", "`%s`".formatted(
e.getMessage()
));
if (matcher.find()) { if (matcher.find()) {
e.setCancelled(true); e.setCancelled(true);
@@ -85,7 +92,7 @@ public class AdvancedBlockers {
ServerUtils.sendDebugMessage("AdvBlocker: Caught URL: " + highlighted); ServerUtils.sendDebugMessage("AdvBlocker: Caught URL: " + highlighted);
report.stepsTaken().replace("Anti-URL", "`%s` %s".formatted(highlighted, Emojis.alarm)); report.stepsTaken().replace("Anti-URL", "`%s` %s".formatted(highlighted, Emojis.alarm));
FilterAction.filterPunish(e,FAT.BLOCK_URL,null,null); FilterAction.filterPunish(e,FAT.BLOCK_URL,null,null,report.id());
} }
} }
} }

View File

@@ -1,5 +1,6 @@
package io.github.thetrouper.sentinel.server.functions; package io.github.thetrouper.sentinel.server.functions;
import io.github.itzispyder.pdk.utils.SchedulerUtils;
import io.github.thetrouper.sentinel.Sentinel; import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Emojis; import io.github.thetrouper.sentinel.data.Emojis;
import io.github.thetrouper.sentinel.data.FAT; import io.github.thetrouper.sentinel.data.FAT;
@@ -15,67 +16,52 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class AntiSpam { public class AntiSpam {
public static Map<Player, Integer> heatMap; public static Map<Player, Integer> heatMap = new HashMap<>();
public static Map<Player, String> lastMessageMap; public static Map<Player, String> lastMessageMap = new HashMap<>();
public static void enableAntiSpam() {
heatMap = new HashMap<>();
lastMessageMap = new HashMap<>();
}
public static void handleAntiSpam(AsyncPlayerChatEvent e, Report report) { public static void handleAntiSpam(AsyncPlayerChatEvent e, Report report) {
Player p = e.getPlayer(); Player p = e.getPlayer();
String message = Text.removeFirstColor(e.getMessage()); String message = Text.removeFirstColor(e.getMessage());
if (!lastMessageMap.containsKey(p)) { String lastMessage = lastMessageMap.getOrDefault(p,"/* Placeholder Message from Sentinel */");
lastMessageMap.put(p,"/* Placeholder Message from Sentinel */"); int currentHeat = heatMap.getOrDefault(p,0);
ServerUtils.sendDebugMessage("AntiSpam: " + p.getName() + " did not have a previous message, setting to placeholder!");
}
if (!heatMap.containsKey(p)) {
heatMap.put(p,0);
ServerUtils.sendDebugMessage("AntiSpam: " + p.getName() + " did not have a heat, setting it to 0!");
}
if (lastMessageMap.containsKey(p)) {
String lastMessage = lastMessageMap.get(p);
double similarity = GPTUtils.calcSim(message, lastMessage); double similarity = GPTUtils.calcSim(message, lastMessage);
ServerUtils.sendDebugMessage("AntiSpam: " + p.getName() + " has a heat of " + heatMap.get(p) + "/" + Sentinel.mainConfig.chat.antiSpam.punishHeat + ". Current Message: \"" + message + "\" Last message: \"" + lastMessage + "\"");
int addHeat = Sentinel.mainConfig.chat.antiSpam.defaultGain;
ServerUtils.sendDebugMessage("AntiSpam: " + p.getName() + " has a heat of " + currentHeat + "/" + Sentinel.mainConfig.chat.antiSpam.punishHeat + ". Current Message: \"" + message + "\" Last message: \"" + lastMessage + "\"");
if (similarity > 90) { if (similarity > 90) {
heatMap.put(p, heatMap.get(p) + Sentinel.mainConfig.chat.antiSpam.highGain); addHeat = Sentinel.mainConfig.chat.antiSpam.highGain;
ServerUtils.sendDebugMessage("AntiSpam: Similarity: " + similarity + ", is greater than 90% for " + p.getName() + ". Adding " + Sentinel.mainConfig.chat.antiSpam.highGain); ServerUtils.sendDebugMessage("AntiSpam: Similarity: " + similarity + ", is greater than 90% for " + p.getName() + ". Adding " + Sentinel.mainConfig.chat.antiSpam.highGain);
} else if (similarity > 50) { } else if (similarity > 50) {
heatMap.put(p, heatMap.get(p) + Sentinel.mainConfig.chat.antiSpam.mediumGain); addHeat = Sentinel.mainConfig.chat.antiSpam.mediumGain;
ServerUtils.sendDebugMessage("AntiSpam: Similarity: " + similarity + ", is greater than 50% for " + p.getName() + ". Adding " + Sentinel.mainConfig.chat.antiSpam.mediumGain); ServerUtils.sendDebugMessage("AntiSpam: Similarity: " + similarity + ", is greater than 50% for " + p.getName() + ". Adding " + Sentinel.mainConfig.chat.antiSpam.mediumGain);
} else if (similarity > 25) { } else if (similarity > 25) {
heatMap.put(p, heatMap.get(p) + Sentinel.mainConfig.chat.antiSpam.lowGain); addHeat = Sentinel.mainConfig.chat.antiSpam.lowGain;
ServerUtils.sendDebugMessage("AntiSpam: Similarity: " + similarity + ", is greater than 25% for " + p.getName() + ". Adding " + Sentinel.mainConfig.chat.antiSpam.lowGain); ServerUtils.sendDebugMessage("AntiSpam: Similarity: " + similarity + ", is greater than 25% for " + p.getName() + ". Adding " + Sentinel.mainConfig.chat.antiSpam.lowGain);
} }
}
report.stepsTaken().put("Anti-Spam", "Heat: %s\nMessage: `%s`".formatted(heatMap.get(p),message)); report.stepsTaken().put("Anti-Spam", "Heat: %s\nMessage: `%s`".formatted(currentHeat,message));
lastMessageMap.put(p, message); if (currentHeat > Sentinel.mainConfig.chat.antiSpam.punishHeat) {
if (heatMap.get(p) > Sentinel.mainConfig.chat.antiSpam.punishHeat) {
e.setCancelled(true); e.setCancelled(true);
report.stepsTaken().replace("Anti-Spam", "Heat: %s\nMessage: `%s` %s".formatted(heatMap.get(p),message, Emojis.alarm)); report.stepsTaken().replace("Anti-Spam", "Heat: %s\nMessage: `%s` %s".formatted(currentHeat,message, Emojis.alarm));
FilterAction.filterPunish(e,FAT.SPAM_PUNISH,GPTUtils.calcSim(e.getMessage(),lastMessageMap.get(p)), null); FilterAction.filterPunish(e,FAT.SPAM_PUNISH,GPTUtils.calcSim(e.getMessage(),lastMessage), null,report.id());
return; return;
} }
if (heatMap.get(p) > Sentinel.mainConfig.chat.antiSpam.blockHeat) { if (currentHeat > Sentinel.mainConfig.chat.antiSpam.blockHeat) {
e.setCancelled(true); e.setCancelled(true);
report.stepsTaken().replace("Anti-Spam", "Heat: %s\nMessage: `%s` %s".formatted(heatMap.get(p),message, Emojis.alarm)); report.stepsTaken().replace("Anti-Spam", "Heat: %s\nMessage: `%s` %s".formatted(currentHeat,message, Emojis.alarm));
FilterAction.filterPunish(e,FAT.BLOCK_SPAM, GPTUtils.calcSim(e.getMessage(),lastMessageMap.get(p)), null); FilterAction.filterPunish(e,FAT.BLOCK_SPAM, GPTUtils.calcSim(e.getMessage(),lastMessage), null,report.id());
heatMap.put(p, heatMap.get(p) + Sentinel.mainConfig.chat.antiSpam.highGain); heatMap.put(p, currentHeat + Sentinel.mainConfig.chat.antiSpam.highGain);
return; return;
} }
heatMap.put(p,heatMap.get(p) + Sentinel.mainConfig.chat.antiSpam.defaultGain); heatMap.put(p,currentHeat + addHeat);
} }
public static void decayHeat() { public static void decayHeat() {
for (Player p : heatMap.keySet()) { for (Player p : heatMap.keySet()) {
int heat = heatMap.get(p); int heat = heatMap.getOrDefault(p,0);
if (heat > 0) { if (heat > 0) {
heat = heat - Sentinel.mainConfig.chat.antiSpam.heatDecay; heat = heat - Sentinel.mainConfig.chat.antiSpam.heatDecay;
heatMap.put(p, Math.max(0, heat)); heatMap.put(p, Math.max(0, heat));

View File

@@ -1,6 +1,7 @@
package io.github.thetrouper.sentinel.server.functions; package io.github.thetrouper.sentinel.server.functions;
import io.github.thetrouper.sentinel.Sentinel; import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Emojis;
import io.github.thetrouper.sentinel.data.FAT; import io.github.thetrouper.sentinel.data.FAT;
import io.github.thetrouper.sentinel.data.FilterSeverity; import io.github.thetrouper.sentinel.data.FilterSeverity;
import io.github.thetrouper.sentinel.data.Report; import io.github.thetrouper.sentinel.data.Report;
@@ -15,15 +16,11 @@ import java.util.List;
import java.util.Map; import java.util.Map;
public class ProfanityFilter { public class ProfanityFilter {
public static Map<Player, Integer> scoreMap; public static Map<Player, Integer> scoreMap = new HashMap<>();
private static final List<String> swearBlacklist = Sentinel.swearConfig.swears; private static final List<String> swearBlacklist = Sentinel.swearConfig.swears;
private static final List<String> swearWhitelist = Sentinel.fpConfig.swearWhitelist; private static final List<String> swearWhitelist = Sentinel.fpConfig.swearWhitelist;
private static final List<String> slurs = Sentinel.strictConfig.strict; private static final List<String> slurs = Sentinel.strictConfig.strict;
public static void enableAntiSwear() {
scoreMap = new HashMap<>();
}
public static void handleProfanityFilter(AsyncPlayerChatEvent event, Report report) { public static void handleProfanityFilter(AsyncPlayerChatEvent event, Report report) {
Player player = event.getPlayer(); Player player = event.getPlayer();
String message = Text.removeFirstColor(event.getMessage()); String message = Text.removeFirstColor(event.getMessage());
@@ -41,11 +38,11 @@ public class ProfanityFilter {
scoreMap.put(player, newScore); scoreMap.put(player, newScore);
if (newScore > Sentinel.mainConfig.chat.antiSwear.punishScore) { if (newScore > Sentinel.mainConfig.chat.antiSwear.punishScore) {
FilterAction.filterPunish(event, FAT.SWEAR_PUNISH, null, severity); FilterAction.filterPunish(event, FAT.SWEAR_PUNISH, null, severity,report.id());
return; return;
} }
FilterAction.filterPunish(event, getFAT(severity), null, severity); FilterAction.filterPunish(event, getFAT(severity), null, severity,report.id());
} }
@@ -105,6 +102,7 @@ public class ProfanityFilter {
return removePeriodsAndSpaces(simplifiedText); return removePeriodsAndSpaces(simplifiedText);
} }
public static FilterSeverity checkSeverity(String text, Report report) { public static FilterSeverity checkSeverity(String text, Report report) {
FilterSeverity severity = FilterSeverity.SAFE;
// 1: // 1:
String lowercasedText = text.toLowerCase(); String lowercasedText = text.toLowerCase();
report.stepsTaken().put("Lowercased", lowercasedText); report.stepsTaken().put("Lowercased", lowercasedText);
@@ -116,8 +114,13 @@ public class ProfanityFilter {
ServerUtils.sendDebugMessage(("ProfanityFilter: Removed False positives: " + cleanedText)); ServerUtils.sendDebugMessage(("ProfanityFilter: Removed False positives: " + cleanedText));
// 3: // 3:
if (containsSwears(cleanedText)) return FilterSeverity.LOW; severity = checkProfanity(cleanedText,FilterSeverity.LOW);
if (containsSlurs(cleanedText)) return FilterSeverity.SLUR; if (severity != FilterSeverity.SAFE) {
report.stepsTaken().replace("Remove False Positives", "%s %s".formatted(
highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return severity;
}
// 4: // 4:
String convertedText = convertLeetSpeakCharacters(cleanedText); String convertedText = convertLeetSpeakCharacters(cleanedText);
@@ -125,42 +128,61 @@ public class ProfanityFilter {
ServerUtils.sendDebugMessage(("ProfanityFilter: Leet Converted: " + convertedText)); ServerUtils.sendDebugMessage(("ProfanityFilter: Leet Converted: " + convertedText));
// 5: // 5:
if (containsSwears(convertedText)) return FilterSeverity.MEDIUM_LOW; severity = checkProfanity(convertedText,FilterSeverity.MEDIUM_LOW);
if (containsSlurs(cleanedText)) return FilterSeverity.SLUR; if (severity != FilterSeverity.SAFE) {
report.stepsTaken().replace("Convert LeetSpeak", "%s %s".formatted(
highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return severity;
}
// 6: // 6:
String strippedText = stripSpecialCharacters(convertedText); String strippedText = stripSpecialCharacters(convertedText);
report.stepsTaken().put("Remove Special Characters", strippedText); report.stepsTaken().put("Remove Special Characters", strippedText);
ServerUtils.sendDebugMessage(("ProfanityFilter: Specials Removed: " + strippedText)); ServerUtils.sendDebugMessage(("ProfanityFilter: Specials Removed: " + strippedText));
// 7: // 7:
if (containsSwears(strippedText)) return FilterSeverity.MEDIUM; severity = checkProfanity(strippedText,FilterSeverity.MEDIUM);
if (containsSlurs(strippedText)) return FilterSeverity.SLUR; if (severity != FilterSeverity.SAFE) {
report.stepsTaken().replace("Remove Special Characters", "%s %s".formatted(
highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return severity;
}
// 8: // 8:
String simplifiedText = simplifyRepeatingLetters(strippedText); String simplifiedText = simplifyRepeatingLetters(strippedText);
report.stepsTaken().put("Remove Repeats", simplifiedText); report.stepsTaken().put("Remove Repeats", simplifiedText);
ServerUtils.sendDebugMessage(("ProfanityFilter: Removed Repeating: " + simplifiedText)); ServerUtils.sendDebugMessage(("ProfanityFilter: Removed Repeating: " + simplifiedText));
// 9: // 9:
if (containsSwears(simplifiedText)) return FilterSeverity.MEDIUM_HIGH; severity = checkProfanity(simplifiedText,FilterSeverity.MEDIUM_HIGH);
if (containsSlurs(simplifiedText)) return FilterSeverity.SLUR; if (severity != FilterSeverity.SAFE) {
report.stepsTaken().replace("Remove Repeats", "%s %s".formatted(
highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return severity;
}
// 10: // 10:
String finalText = removePeriodsAndSpaces(simplifiedText); String finalText = removePeriodsAndSpaces(simplifiedText);
report.stepsTaken().put("Remove Punctuation", finalText); report.stepsTaken().put("Remove Punctuation", finalText);
ServerUtils.sendDebugMessage(("ProfanityFilter: Remove Punctuation: " + finalText)); ServerUtils.sendDebugMessage(("ProfanityFilter: Remove Punctuation: " + finalText));
// 11: // 11:
if (containsSwears(finalText)) return FilterSeverity.HIGH; severity = checkProfanity(finalText,FilterSeverity.HIGH);
if (containsSlurs(finalText)) return FilterSeverity.SLUR; if (severity != FilterSeverity.SAFE) {
report.stepsTaken().replace("Remove Punctuation", "%s %s".formatted(
highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return severity;
}
return FilterSeverity.SAFE; return severity;
} }
public static boolean ContainsProfanity(String text) { public static FilterSeverity checkProfanity(String text, FilterSeverity severity) {
return containsSwears(text) || containsSlurs(text); if (containsSlurs(text)) return FilterSeverity.SLUR;
if (containsSwears(text)) return severity;
return FilterSeverity.SAFE;
} }
private static boolean containsSwears(String text) { private static boolean containsSwears(String text) {
ServerUtils.sendDebugMessage("ProfanityFilter: Checking for swears"); ServerUtils.sendDebugMessage("ProfanityFilter: Checking for swears");

View File

@@ -9,53 +9,42 @@ import io.github.thetrouper.sentinel.data.Report;
import io.github.thetrouper.sentinel.server.util.Randomizer; import io.github.thetrouper.sentinel.server.util.Randomizer;
import io.github.thetrouper.sentinel.server.util.ServerUtils; import io.github.thetrouper.sentinel.server.util.ServerUtils;
import io.github.thetrouper.sentinel.server.util.Text; import io.github.thetrouper.sentinel.server.util.Text;
import it.unimi.dsi.fastutil.Hash;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
public class ReportFalsePositives { public class ReportFalsePositives {
public static Map<String,AsyncPlayerChatEvent> reportMap = new HashMap<>();
public static Map<Long,Report> reports = new HashMap<>(); public static Map<Long,Report> reports = new HashMap<>();
public static Report initializeReport(AsyncPlayerChatEvent e) { public static Report initializeReport(AsyncPlayerChatEvent event) {
final long reportID = Randomizer.generateID(); final long reportID = Randomizer.generateID();
HashMap<String,String> steps = new HashMap<>(); LinkedHashMap<String,String> steps = new LinkedHashMap<>();
steps.put("Original Message", e.getMessage()); steps.put("Original Message", "`%s`".formatted(event.getMessage()));
return new Report(reportID,e,steps);
}
public static String generateReport(AsyncPlayerChatEvent e) {
final long reportLong = Randomizer.generateID();
final String reportID = Long.toString(reportLong);
ServerUtils.sendDebugMessage("FP Report: Generating chat filter report");
reportMap.put(reportID,e);
ServerUtils.sendDebugMessage(("FP Report: Generated chat filter report. ID:" + reportID + " Message: \"" + reportMap.get(reportID).getMessage() + "\" Expires in 60 seconds"));
SchedulerUtils.later(60000,()->{ SchedulerUtils.later(60000,()->{
reportMap.remove(reportID); reports.remove(reportID);
ServerUtils.sendDebugMessage("FP Report: Chat filter Report expired. ID: " + reportID);
}); });
return reportID; return new Report(reportID,event,steps);
} }
public static void sendFalsePositiveReport(Report report) { public static void sendFalsePositiveReport(Report report) {
DiscordEmbed.Builder embed = DiscordEmbed.create() DiscordEmbed.Builder embed = DiscordEmbed.create()
.author(new DiscordEmbed.Author("Anti-Swear False Positive","",null)) .author(new DiscordEmbed.Author("Anti-Swear False Positive","",null))
.title("Flag Report:") .title("A player has reported a false positive")
.desc(String.format(""" .desc(String.format("""
%1$sPlayer: %2$s %3$s\n %1$sPlayer: %2$s %3$s
%4$s %5$sUUID: `%2$s`\n %4$s %5$sUUID: `%6$s`
## **Filter Steps Taken:**
""", """,
Emojis.rightSort, Emojis.rightSort,
report.event().getPlayer().getName(), report.event().getPlayer().getName(),
Emojis.target, Emojis.target,
Emojis.space, Emojis.space,
Emojis.arrowRight Emojis.rightArrow,
report.event().getPlayer().getUniqueId()
)); ));
report.stepsTaken().forEach((key, value)->{ report.stepsTaken().forEach((key, value)->{
@@ -67,59 +56,7 @@ public class ReportFalsePositives {
.username("Sentinel Anti-Nuke | Logs") .username("Sentinel Anti-Nuke | Logs")
.addEmbed(embed.build()) .addEmbed(embed.build())
.send(Sentinel.mainConfig.plugin.webhook); .send(Sentinel.mainConfig.plugin.webhook);
}
public static void sendFalsePositiveReport(String reportID) {
AsyncPlayerChatEvent e = reportMap.get(reportID);
String orig = e.getMessage();
String lowercasedText = orig.toLowerCase();
String remFP = ProfanityFilter.removeFalsePositives(lowercasedText);
String convertedLeet = ProfanityFilter.convertLeetSpeakCharacters(remFP);
String remSpecials = ProfanityFilter.stripSpecialCharacters(convertedLeet);
String simplifyRep = ProfanityFilter.simplifyRepeatingLetters(remSpecials);
String sanitized = ProfanityFilter. removePeriodsAndSpaces(simplifyRep);
try {
sendEmbed(e.getPlayer(),orig,lowercasedText,remFP,convertedLeet,remSpecials,simplifyRep,sanitized);
} catch (Exception ex) {
e.getPlayer().sendMessage(Text.prefix("Report Failed!"));
Sentinel.log.warning(ex.getMessage());
}
}
public static void sendEmbed(Player player,
String message,
String lowercased,
String remFP,
String convertedLeet,
String remSpecials,
String simplifyRep,
String sanitized) throws IOException {
ServerUtils.sendDebugMessage("Creating FalsePositive Webhook...");
DiscordWebhook.create()
.avatar("https://r2.e-z.host/d440b58a-ba90-4839-8df6-8bba298cf817/3lwit5nt.png")
.username("Sentinel Anti-Nuke | Logs")
.addEmbed(DiscordEmbed.create()
.author(new DiscordEmbed.Author("Anti-Swear False Positive","",null))
.title("Flag Report:")
.desc(String.format("%1$sPlayer: %2$s %3$s\n%4$s %5$sUUID: `%2$s`\n",
Emojis.rightSort,
player.getName(),
Emojis.target,
Emojis.space,
Emojis.arrowRight
))
.addField("Original Message", "`" + message + "` " + (ProfanityFilter.ContainsProfanity(message) ? Emojis.alarm : ""), false)
.addField("Lowercase", "`" + lowercased + "` " + (ProfanityFilter.ContainsProfanity(lowercased) ? Emojis.alarm : ""), false)
.addField("Removed FPs", "`" + remFP + "` " + (ProfanityFilter.ContainsProfanity(remFP) ? Emojis.alarm : ""), false)
.addField("Converted Leet", "`" + convertedLeet + "` " + (ProfanityFilter.ContainsProfanity(convertedLeet) ? Emojis.alarm : ""), false)
.addField("Removed Specials", "`" + remSpecials + "` " + (ProfanityFilter.ContainsProfanity(remSpecials) ? Emojis.alarm : ""), false)
.addField("Simplify Repeats", "`" + simplifyRep + "` " + (ProfanityFilter.ContainsProfanity(simplifyRep) ? Emojis.alarm : ""), false)
.addField("Fully Sanitized Message", ProfanityFilter.highlightProfanity(sanitized,"`", "`") + " " + Emojis.noDM, false)
.color(0x00FF00)
.thumbnail("https://crafatar.com/avatars/" + player.getUniqueId() + "?size=64&&overlay")
.build())
.build().send(Sentinel.mainConfig.plugin.webhook);
reports.remove(report.id());
} }
} }

View File

@@ -144,10 +144,8 @@ public class SystemCheck {
AntiSpam.handleAntiSpam(spam,ReportFalsePositives.initializeReport(spam)); AntiSpam.handleAntiSpam(spam,ReportFalsePositives.initializeReport(spam));
}); });
String report = ReportFalsePositives.generateReport(falsePositive);
SchedulerUtils.later(20,()->{ SchedulerUtils.later(20,()->{
ReportFalsePositives.sendFalsePositiveReport(report);
}); });
Message.messagePlayer(p,p,"Sentinel Automatic System check > Private Message"); Message.messagePlayer(p,p,"Sentinel Automatic System check > Private Message");

View File

@@ -51,24 +51,39 @@ public class Text {
return input; return input;
} }
} }
public static String replaceRepeatingLetters(String message) { public static String replaceRepeatingLetters(String input) {
StringBuilder result = new StringBuilder(); if (input == null || input.isEmpty()) {
char prevChar = '\0'; return input;
int count = 0; }
for (char c : message.toCharArray()) { StringBuilder simplifiedText = new StringBuilder();
if (c == prevChar) { char currentChar = input.charAt(0);
int count = 1;
for (int i = 1; i < input.length(); i++) {
char nextChar = input.charAt(i);
if (Character.toLowerCase(nextChar) == Character.toLowerCase(currentChar)) {
count++; count++;
if (count <= 3) {
result.append(c);
}
} else { } else {
prevChar = c; simplifiedText.append(currentChar);
if (count > 1) {
simplifiedText.append(currentChar);
}
currentChar = nextChar;
count = 1; count = 1;
result.append(c);
} }
} }
return result.toString();
simplifiedText.append(currentChar);
if (count > 1) {
simplifiedText.append(currentChar);
}
return simplifiedText.toString();
} }
public static String fromLeetString(String s) { public static String fromLeetString(String s) {
Map<String, String> dictionary = Sentinel.advConfig.leetPatterns; Map<String, String> dictionary = Sentinel.advConfig.leetPatterns;