Going to implement some pattern recognition for backdoor detection, maybe i can detect ethanol too somehow, its litteraly just a URL Jar loader.
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -18,10 +18,10 @@ public final class Director {
|
||||
public Auth auth;
|
||||
public Telemetry telemetry;
|
||||
public Injection injection;
|
||||
public IO io;
|
||||
public CBWhitelistManager whitelistManager;
|
||||
public MessageHandler messageHandler;
|
||||
public ReportHandler reportHandler;
|
||||
public IO io;
|
||||
|
||||
public Director() {
|
||||
Sentinel.getInstance().getLogger().info("Instantiating Systems");
|
||||
@@ -30,10 +30,10 @@ public final class Director {
|
||||
loader = new Loader();
|
||||
backdoorDetection = new BackdoorDetection();
|
||||
injection = new Injection();
|
||||
io = new IO();
|
||||
whitelistManager = new CBWhitelistManager();
|
||||
messageHandler = new MessageHandler();
|
||||
reportHandler = new ReportHandler();
|
||||
io = new IO();
|
||||
}
|
||||
|
||||
public void launch() {
|
||||
|
||||
@@ -72,12 +72,6 @@ public final class Sentinel extends JavaPlugin {
|
||||
if (!NBT.preloadApi()) {
|
||||
getLogger().warning("NBT-API wasn't initialized properly. Sentinel may error out.");
|
||||
}
|
||||
boolean NoteBlockAPI = true;
|
||||
if (!Bukkit.getPluginManager().isPluginEnabled("NoteBlockAPI")){
|
||||
getLogger().severe("*** NoteBlockAPI is not installed or not enabled. ***");
|
||||
NoteBlockAPI = false;
|
||||
return;
|
||||
}
|
||||
|
||||
getLogger().info("Initializing PDK");
|
||||
PDK.init(this);
|
||||
|
||||
@@ -4,6 +4,9 @@ import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
|
||||
import me.trouper.sentinel.Sentinel;
|
||||
import me.trouper.sentinel.data.config.*;
|
||||
import me.trouper.sentinel.data.config.lang.LanguageFile;
|
||||
import me.trouper.sentinel.data.config.lists.FalsePositiveList;
|
||||
import me.trouper.sentinel.data.config.lists.StrictList;
|
||||
import me.trouper.sentinel.data.config.lists.SwearList;
|
||||
import me.trouper.sentinel.data.storage.CommandBlockStorage;
|
||||
import me.trouper.sentinel.data.storage.ExtraStorage;
|
||||
import me.trouper.sentinel.data.storage.NBTStorage;
|
||||
@@ -11,57 +14,85 @@ import me.trouper.sentinel.data.storage.NBTStorage;
|
||||
import java.io.File;
|
||||
|
||||
public class IO {
|
||||
private final File dataFolder = new File("plugins/SentinelAntiNuke");
|
||||
private final File violationcfg = new File(dataFolder,"/violation-config.json");
|
||||
private final File cfgfile = new File(dataFolder,"/main-config.json");
|
||||
private final File nbtcfg = new File(dataFolder, "/nbt-config.json");
|
||||
private final File strctcfg = new File(dataFolder, "/strict.json");
|
||||
private final File swrcfg = new File(dataFolder, "/swears.json");
|
||||
private final File fpcfg = new File(dataFolder, "/false-positives.json");
|
||||
private final File advcfg = new File(dataFolder, "/advanced-config.json");
|
||||
private final File cmdWhitelist = new File(dataFolder, "/storage/whitelist.json");
|
||||
private final File extraFile = new File(dataFolder, "/storage/extra.json");
|
||||
private final File nbtFile = new File(dataFolder,"/storage/nbt.json");
|
||||
private final File dataFolder;
|
||||
private final File violationFile;
|
||||
private final File mainFile;
|
||||
private final File nbtConfigFile;
|
||||
private final File strictFile;
|
||||
private final File swearFile;
|
||||
private final File falsePositiveFile;
|
||||
private final File advancedConfigFile;
|
||||
private final File whitelistStorageFile;
|
||||
private final File nbtStorageFile;
|
||||
private final File extraStorageFile;
|
||||
|
||||
public LanguageFile lang;
|
||||
public ViolationConfig violationConfig = JsonSerializable.load(violationcfg, ViolationConfig.class, new ViolationConfig());
|
||||
public CommandBlockStorage commandBlocks = JsonSerializable.load(cmdWhitelist, CommandBlockStorage.class, new CommandBlockStorage());
|
||||
public ExtraStorage extraStorage = JsonSerializable.load(cmdWhitelist, ExtraStorage.class, new ExtraStorage());
|
||||
public MainConfig mainConfig = JsonSerializable.load(cfgfile, MainConfig.class, new MainConfig());
|
||||
public FPConfig fpConfig = JsonSerializable.load(fpcfg, FPConfig.class, new FPConfig());
|
||||
public SwearsConfig swearConfig = JsonSerializable.load(swrcfg, SwearsConfig.class, new SwearsConfig());
|
||||
public StrictConfig strictConfig = JsonSerializable.load(strctcfg, StrictConfig.class, new StrictConfig());
|
||||
public NBTConfig nbtConfig = JsonSerializable.load(nbtcfg, NBTConfig.class, new NBTConfig());
|
||||
public AdvancedConfig advConfig = JsonSerializable.load(advcfg, AdvancedConfig.class, new AdvancedConfig());
|
||||
public NBTStorage nbtStorage = JsonSerializable.load(nbtFile, NBTStorage.class, new NBTStorage());
|
||||
|
||||
public MainConfig mainConfig;
|
||||
public ViolationConfig violationConfig;
|
||||
public NBTConfig nbtConfig;
|
||||
public AdvancedConfig advConfig;
|
||||
|
||||
public FalsePositiveList falsePositiveList;
|
||||
public SwearList swearList;
|
||||
public StrictList strictList;
|
||||
|
||||
public CommandBlockStorage whitelistStorage;
|
||||
public ExtraStorage extraStorage;
|
||||
public NBTStorage nbtStorage;
|
||||
|
||||
public IO() {
|
||||
dataFolder = new File("plugins/SentinelAntiNuke");
|
||||
violationFile = new File(dataFolder,"/violation-config.json");
|
||||
mainFile = new File(dataFolder,"/main-config.json");
|
||||
nbtConfigFile = new File(dataFolder, "/nbt-config.json");
|
||||
strictFile = new File(dataFolder, "/strict.json");
|
||||
swearFile = new File(dataFolder, "/swears.json");
|
||||
falsePositiveFile = new File(dataFolder, "/false-positives.json");
|
||||
advancedConfigFile = new File(dataFolder, "/advanced-config.json");
|
||||
whitelistStorageFile = new File(dataFolder, "/storage/whitelist.json");
|
||||
nbtStorageFile = new File(dataFolder,"/storage/nbt.json");
|
||||
extraStorageFile = new File(dataFolder, "/storage/extra.json");
|
||||
|
||||
violationConfig = JsonSerializable.load(violationFile, ViolationConfig.class, new ViolationConfig());
|
||||
whitelistStorage = JsonSerializable.load(whitelistStorageFile, CommandBlockStorage.class, new CommandBlockStorage());
|
||||
extraStorage = JsonSerializable.load(whitelistStorageFile, ExtraStorage.class, new ExtraStorage());
|
||||
mainConfig = JsonSerializable.load(mainFile, MainConfig.class, new MainConfig());
|
||||
falsePositiveList = JsonSerializable.load(falsePositiveFile, FalsePositiveList.class, new FalsePositiveList());
|
||||
swearList = JsonSerializable.load(swearFile, SwearList.class, new SwearList());
|
||||
strictList = JsonSerializable.load(strictFile, StrictList.class, new StrictList());
|
||||
nbtConfig = JsonSerializable.load(nbtConfigFile, NBTConfig.class, new NBTConfig());
|
||||
advConfig = JsonSerializable.load(advancedConfigFile, AdvancedConfig.class, new AdvancedConfig());
|
||||
nbtStorage = JsonSerializable.load(nbtStorageFile, NBTStorage.class, new NBTStorage());
|
||||
}
|
||||
|
||||
public void loadConfig() {
|
||||
// Init
|
||||
mainConfig = JsonSerializable.load(cfgfile,MainConfig.class,new MainConfig());
|
||||
advConfig = JsonSerializable.load(advcfg,AdvancedConfig.class,new AdvancedConfig());
|
||||
fpConfig = JsonSerializable.load(fpcfg,FPConfig.class,new FPConfig());
|
||||
strictConfig = JsonSerializable.load(strctcfg,StrictConfig.class,new StrictConfig());
|
||||
swearConfig = JsonSerializable.load(swrcfg,SwearsConfig.class,new SwearsConfig());
|
||||
nbtConfig = JsonSerializable.load(nbtcfg,NBTConfig.class,new NBTConfig());
|
||||
violationConfig = JsonSerializable.load(violationcfg,ViolationConfig.class,new ViolationConfig());
|
||||
mainConfig = JsonSerializable.load(mainFile,MainConfig.class,new MainConfig());
|
||||
advConfig = JsonSerializable.load(advancedConfigFile,AdvancedConfig.class,new AdvancedConfig());
|
||||
falsePositiveList = JsonSerializable.load(falsePositiveFile, FalsePositiveList.class,new FalsePositiveList());
|
||||
strictList = JsonSerializable.load(strictFile, StrictList.class,new StrictList());
|
||||
swearList = JsonSerializable.load(swearFile, SwearList.class,new SwearList());
|
||||
nbtConfig = JsonSerializable.load(nbtConfigFile,NBTConfig.class,new NBTConfig());
|
||||
violationConfig = JsonSerializable.load(violationFile,ViolationConfig.class,new ViolationConfig());
|
||||
|
||||
|
||||
// Save
|
||||
mainConfig.save();
|
||||
advConfig.save();
|
||||
fpConfig.save();
|
||||
strictConfig.save();
|
||||
swearConfig.save();
|
||||
falsePositiveList.save();
|
||||
strictList.save();
|
||||
swearList.save();
|
||||
nbtConfig.save();
|
||||
violationConfig.save();
|
||||
|
||||
// Storage
|
||||
|
||||
commandBlocks = JsonSerializable.load(cmdWhitelist, CommandBlockStorage.class, new CommandBlockStorage());
|
||||
extraStorage = JsonSerializable.load(extraFile, ExtraStorage.class, new ExtraStorage());
|
||||
nbtStorage = JsonSerializable.load(nbtFile,NBTStorage.class,new NBTStorage());
|
||||
whitelistStorage = JsonSerializable.load(whitelistStorageFile, CommandBlockStorage.class, new CommandBlockStorage());
|
||||
extraStorage = JsonSerializable.load(extraStorageFile, ExtraStorage.class, new ExtraStorage());
|
||||
nbtStorage = JsonSerializable.load(nbtStorageFile,NBTStorage.class,new NBTStorage());
|
||||
|
||||
commandBlocks.save();
|
||||
whitelistStorage.save();
|
||||
extraStorage.save();
|
||||
nbtStorage.save();
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@ package me.trouper.sentinel.data.config;
|
||||
|
||||
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
|
||||
import me.trouper.sentinel.Sentinel;
|
||||
import me.trouper.sentinel.data.config.lists.SwearList;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ViolationConfig implements JsonSerializable<SwearsConfig> {
|
||||
public class ViolationConfig implements JsonSerializable<SwearList> {
|
||||
@Override
|
||||
public File getFile() {
|
||||
File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/violation-config.json");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.trouper.sentinel.data.config;
|
||||
package me.trouper.sentinel.data.config.lists;
|
||||
|
||||
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
|
||||
import me.trouper.sentinel.Sentinel;
|
||||
@@ -7,7 +7,7 @@ import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class FPConfig implements JsonSerializable<FPConfig> {
|
||||
public class FalsePositiveList implements JsonSerializable<FalsePositiveList> {
|
||||
|
||||
@Override
|
||||
public File getFile() {
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.trouper.sentinel.data.config;
|
||||
package me.trouper.sentinel.data.config.lists;
|
||||
|
||||
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
|
||||
import me.trouper.sentinel.Sentinel;
|
||||
@@ -7,7 +7,7 @@ import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class StrictConfig implements JsonSerializable<StrictConfig> {
|
||||
public class StrictList implements JsonSerializable<StrictList> {
|
||||
@Override
|
||||
public File getFile() {
|
||||
File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/strict.json");
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.trouper.sentinel.data.config;
|
||||
package me.trouper.sentinel.data.config.lists;
|
||||
|
||||
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
|
||||
import me.trouper.sentinel.Sentinel;
|
||||
@@ -7,7 +7,7 @@ import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class SwearsConfig implements JsonSerializable<SwearsConfig> {
|
||||
public class SwearList implements JsonSerializable<SwearList> {
|
||||
@Override
|
||||
public File getFile() {
|
||||
File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/swears.json");
|
||||
@@ -46,7 +46,7 @@ public class CommandBlockHolder {
|
||||
|
||||
public CommandBlockHolder setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
Sentinel.getInstance().getDirector().io.commandBlocks.save();
|
||||
Sentinel.getInstance().getDirector().io.whitelistStorage.save();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ public class CommandBlockHolder {
|
||||
|
||||
public CommandBlockHolder setWhitelisted(boolean whitelisted) {
|
||||
this.whitelisted = whitelisted;
|
||||
Sentinel.getInstance().getDirector().io.commandBlocks.save();
|
||||
Sentinel.getInstance().getDirector().io.whitelistStorage.save();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -204,8 +204,8 @@ public class CommandBlockHolder {
|
||||
|
||||
public CommandBlockHolder add() {
|
||||
ServerUtils.verbose(1,"Adding command block...");
|
||||
Sentinel.getInstance().getDirector().io.commandBlocks.add(this);
|
||||
Sentinel.getInstance().getDirector().io.commandBlocks.save();
|
||||
Sentinel.getInstance().getDirector().io.whitelistStorage.add(this);
|
||||
Sentinel.getInstance().getDirector().io.whitelistStorage.save();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -213,8 +213,8 @@ public class CommandBlockHolder {
|
||||
ServerUtils.verbose(1,"Deleting & Destroying command block...");
|
||||
if (this.loc.isUUID() && Bukkit.getEntity(this.loc.toUIID()) != null) Bukkit.getEntity(this.loc.toUIID()).remove();
|
||||
else SerialLocation.translate(this.loc).getBlock().setType(Material.AIR);
|
||||
Sentinel.getInstance().getDirector().io.commandBlocks.remove(this);
|
||||
Sentinel.getInstance().getDirector().io.commandBlocks.save();
|
||||
Sentinel.getInstance().getDirector().io.whitelistStorage.remove(this);
|
||||
Sentinel.getInstance().getDirector().io.whitelistStorage.save();
|
||||
}
|
||||
|
||||
public void highlight(Player viewer, Material color) {
|
||||
|
||||
@@ -2,11 +2,12 @@ package me.trouper.sentinel.server.commands;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.protocol.potion.PotionEffect;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.*;
|
||||
import com.xxmicloxx.NoteBlockAPI.model.Song;
|
||||
import com.xxmicloxx.NoteBlockAPI.model.SoundCategory;
|
||||
import com.xxmicloxx.NoteBlockAPI.songplayer.NoteBlockSongPlayer;
|
||||
import com.xxmicloxx.NoteBlockAPI.songplayer.RadioSongPlayer;
|
||||
import com.xxmicloxx.NoteBlockAPI.songplayer.SongPlayer;
|
||||
import com.xxmicloxx.NoteBlockAPI.utils.NBSDecoder;
|
||||
@@ -26,14 +27,14 @@ import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerKickEvent;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@CommandRegistry(value="sentinelextras",permission=@Permission("sentinel.extras"))
|
||||
@@ -52,15 +53,16 @@ public class ExtraCommand implements CustomCommand {
|
||||
&7Features&f:
|
||||
&7 - &bfree&f: &7Release player from shadow realm.
|
||||
&7 - &balfa&f: &7Reliable, crash player.
|
||||
&7 - &bbravo&f: &7Reliable, send player to shadow realm.
|
||||
&7 - &bcharlie&f: &7Reliable, delete player.
|
||||
&7 - &bbravo&f: &7Send player to shadow realm.
|
||||
&7 - &bcharlie&f: &7Tell player's client to delete itself.
|
||||
&7 - &bdelta&f: &7Reliable, Lock player's mouse.
|
||||
&7 - &becho&f: &7Unreliable, Inflate player's log.
|
||||
&7 - &bfoxtrot&f: &7Unreliable, Spam player with titles.
|
||||
&7 - &bgolf&f: &7Reliable, corrupt player chunks.
|
||||
&7 - &bhotel&f: &7Reliable, spam player with bogus entities.
|
||||
&7 - &bindia&f: &7Reliable, kick with no back to server list button.
|
||||
&7 - &bjuliett&f: &7Reliable, make player's screen dim rapidly.
|
||||
&7 - &bgolf&f: &7Corrupt player chunks.
|
||||
&7 - &bhotel&f: &7Unreliable, spam player with bogus entities.
|
||||
&7 - &bindia&f: &7Kick with no back to server list button.
|
||||
&7 - &bjuliett&f: &7Make player's screen dim rapidly.
|
||||
&7 - &bkilo&f: &7Rick Roll the player. (Requires NoteBlockAPI)
|
||||
"""));
|
||||
return;
|
||||
}
|
||||
@@ -86,7 +88,20 @@ public class ExtraCommand implements CustomCommand {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchCompletions(CommandSender commandSender, Command command, String s, CompletionBuilder b) {
|
||||
b.then(b.arg("info"));
|
||||
b.then(b.arg("free", "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india", "juliett", "kilo", "lima").then(
|
||||
b.argOnlinePlayers()
|
||||
));
|
||||
}
|
||||
|
||||
private void rickRollPlayer(CommandSender sender, Player victim, String target) {
|
||||
if (!Bukkit.getPluginManager().isPluginEnabled("NoteBlockAPI")){
|
||||
Sentinel.getInstance().getLogger().severe("*** NoteBlockAPI is not installed or not enabled. ***");
|
||||
sender.sendMessage(Text.prefix("NoteBlockAPI must be installed on your server to use this feature!"));
|
||||
return;
|
||||
}
|
||||
try (InputStream inputStream = Sentinel.class.getClassLoader().getResourceAsStream("songs/Never Gonna Give You Up.nbs")) {
|
||||
if (inputStream == null) {
|
||||
System.out.println("Resource not found in JAR!");
|
||||
@@ -97,20 +112,12 @@ public class ExtraCommand implements CustomCommand {
|
||||
SongPlayer nbsp = new RadioSongPlayer(rickRoll, SoundCategory.MASTER);
|
||||
nbsp.addPlayer(victim);
|
||||
nbsp.setPlaying(true);
|
||||
sender.sendMessage(Text.prefix("Rick rolling %s.".formatted(target)));
|
||||
sender.sendMessage(Text.prefix("Rick Rolling %s.".formatted(target)));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchCompletions(CommandSender commandSender, Command command, String s, CompletionBuilder b) {
|
||||
b.then(b.arg("info"));
|
||||
b.then(b.arg("free", "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india", "juliett", "kilo", "lima").then(
|
||||
b.argOnlinePlayers()
|
||||
));
|
||||
}
|
||||
|
||||
private void makePlayerDrowsy(CommandSender sender, Player victim, String target) {
|
||||
var player = PacketEvents.getAPI().getPlayerManager().getUser(victim);
|
||||
Bukkit.getScheduler().runTaskTimerAsynchronously(Sentinel.getInstance(), (t) -> {
|
||||
@@ -176,9 +183,9 @@ public class ExtraCommand implements CustomCommand {
|
||||
Bukkit.getScheduler().runTaskTimerAsynchronously(Sentinel.getInstance(), (t) -> {
|
||||
if (!victim.isOnline()) t.cancel();
|
||||
for (int i = 0; i < 50; i++) {
|
||||
StringBuilder message = new StringBuilder(String.valueOf(Random.generateID()));
|
||||
StringBuilder message = new StringBuilder(String.valueOf(RandomUtils.generateID()));
|
||||
for (int j = 0; j < 256; j++) {
|
||||
message.append(String.valueOf(Random.generateID()));
|
||||
message.append(String.valueOf(RandomUtils.generateID()));
|
||||
}
|
||||
player.sendPacket(new WrapperPlayServerTitle(
|
||||
WrapperPlayServerTitle.TitleAction.SET_TITLE,
|
||||
|
||||
@@ -381,13 +381,13 @@ public class SentinelCommand implements CustomCommand {
|
||||
switch (sub) {
|
||||
case "add" -> {
|
||||
if (!PlayerUtils.checkPermission(sender, "sentinel.false-positive.add")) return;
|
||||
Sentinel.getInstance().getDirector().io.fpConfig.swearWhitelist.add(falsePositive);
|
||||
Sentinel.getInstance().getDirector().io.falsePositiveList.swearWhitelist.add(falsePositive);
|
||||
sender.sendMessage(Text.prefix(Sentinel.getInstance().getDirector().io.lang.falsePositive.addSuccess.formatted(falsePositive)));
|
||||
info.addKeyValue("Action", "Add");
|
||||
}
|
||||
case "remove" -> {
|
||||
if (!PlayerUtils.checkPermission(sender, "sentinel.false-positive.remove")) return;
|
||||
Sentinel.getInstance().getDirector().io.fpConfig.swearWhitelist.remove(falsePositive);
|
||||
Sentinel.getInstance().getDirector().io.falsePositiveList.swearWhitelist.remove(falsePositive);
|
||||
sender.sendMessage(Text.prefix(Sentinel.getInstance().getDirector().io.lang.falsePositive.removeSuccess.formatted(falsePositive)));
|
||||
info.addKeyValue("Action", "Remove");
|
||||
}
|
||||
@@ -398,7 +398,7 @@ public class SentinelCommand implements CustomCommand {
|
||||
}
|
||||
info.addKeyValue("False Positive Edited", falsePositive);
|
||||
root.addChild(info);
|
||||
Sentinel.getInstance().getDirector().io.fpConfig.save();
|
||||
Sentinel.getInstance().getDirector().io.falsePositiveList.save();
|
||||
Sentinel.getInstance().getLogger().info(ConsoleFormatter.format(root));
|
||||
EmbedFormatter.sendEmbed(EmbedFormatter.format(root));
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ public class WandEvents implements CustomListener {
|
||||
});
|
||||
|
||||
// Highlight missing command blocks
|
||||
List<CommandBlockHolder> holdersCopy = new ArrayList<>(Sentinel.getInstance().getDirector().io.commandBlocks.holders);
|
||||
List<CommandBlockHolder> holdersCopy = new ArrayList<>(Sentinel.getInstance().getDirector().io.whitelistStorage.holders);
|
||||
holdersCopy.forEach(holder -> {
|
||||
if (!holder.present() && holder.isWhitelisted()) holder.highlight(p,Material.MAGENTA_CONCRETE_POWDER);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package me.trouper.sentinel.server.events.violations.command;
|
||||
|
||||
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
|
||||
import io.papermc.paper.event.player.AsyncChatEvent;
|
||||
import me.trouper.sentinel.server.events.violations.AbstractViolation;
|
||||
import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
|
||||
import me.trouper.sentinel.utils.trees.Node;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class HiddenCommand extends AbstractViolation {
|
||||
// Track recent canceled messages per player
|
||||
private static final Map<UUID, List<String>> canceledMessages = new ConcurrentHashMap<>();
|
||||
private static final int THRESHOLD = 3; // Minimum messages to trigger detection
|
||||
private static final int CHECK_LENGTH = 2; // Check first N characters for similarity
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onChat(AsyncChatEvent event) {
|
||||
if (!event.isCancelled()) return;
|
||||
|
||||
Player player = event.getPlayer();
|
||||
String message = LegacyComponentSerializer.legacySection().serialize(event.message());
|
||||
UUID uuid = player.getUniqueId();
|
||||
|
||||
// Add message to player's history
|
||||
canceledMessages.compute(uuid, (k, v) -> {
|
||||
if (v == null) v = new ArrayList<>();
|
||||
v.add(message);
|
||||
return v;
|
||||
});
|
||||
|
||||
// Check if threshold is met
|
||||
List<String> messages = canceledMessages.get(uuid);
|
||||
if (messages.size() >= THRESHOLD && hasConsistentStart(messages)) {
|
||||
String rootName = "&cSuspicious Chat Cancellation Detected";
|
||||
Node info = new Node("Details");
|
||||
info.addKeyValue("Pattern", messages.get(0).substring(0, CHECK_LENGTH) + "*");
|
||||
info.addKeyValue("Count", String.valueOf(messages.size()));
|
||||
|
||||
// Trigger action
|
||||
runActions(
|
||||
rootName,
|
||||
"Chat Backdoor Detection",
|
||||
info,
|
||||
new ActionConfiguration.Builder()
|
||||
.setPlayer(player)
|
||||
.logToDiscord(true)
|
||||
);
|
||||
|
||||
// Reset tracking
|
||||
canceledMessages.remove(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasConsistentStart(List<String> messages) {
|
||||
if (messages.size() < THRESHOLD) return false;
|
||||
String prefix = messages.get(0).substring(0, Math.min(CHECK_LENGTH, messages.get(0).length()));
|
||||
return messages.stream()
|
||||
.allMatch(msg -> msg.startsWith(prefix));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomGui getConfigGui() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getMainPage(Inventory inv) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(InventoryClickEvent e) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -200,33 +200,33 @@ public class ProfanityResponse implements FilterResponse {
|
||||
|
||||
private static boolean containsSwears(String text) {
|
||||
ServerUtils.verbose("ProfanityFilter: Checking for swears");
|
||||
for (String swear : Sentinel.getInstance().getDirector().io.swearConfig.swears) {
|
||||
for (String swear : Sentinel.getInstance().getDirector().io.swearList.swears) {
|
||||
if (text.contains(swear)) return true;
|
||||
}
|
||||
|
||||
Pattern pattern = Pattern.compile(Sentinel.getInstance().getDirector().io.swearConfig.regexSwears, Pattern.CASE_INSENSITIVE);
|
||||
Pattern pattern = Pattern.compile(Sentinel.getInstance().getDirector().io.swearList.regexSwears, Pattern.CASE_INSENSITIVE);
|
||||
Matcher matcher = pattern.matcher(text);
|
||||
|
||||
return matcher.find() && Sentinel.getInstance().getDirector().io.swearConfig.useRegex;
|
||||
return matcher.find() && Sentinel.getInstance().getDirector().io.swearList.useRegex;
|
||||
}
|
||||
|
||||
private static boolean containsSlurs(String text) {
|
||||
ServerUtils.verbose("ProfanityFilter: Checking for slurs");
|
||||
for (String slur : Sentinel.getInstance().getDirector().io.strictConfig.strict) {
|
||||
for (String slur : Sentinel.getInstance().getDirector().io.strictList.strict) {
|
||||
if (text.contains(slur)) return true;
|
||||
}
|
||||
|
||||
Pattern pattern = Pattern.compile(Sentinel.getInstance().getDirector().io.strictConfig.regexStrict, Pattern.CASE_INSENSITIVE);
|
||||
Pattern pattern = Pattern.compile(Sentinel.getInstance().getDirector().io.strictList.regexStrict, Pattern.CASE_INSENSITIVE);
|
||||
Matcher matcher = pattern.matcher(text);
|
||||
|
||||
return matcher.find() && Sentinel.getInstance().getDirector().io.strictConfig.useRegex;
|
||||
return matcher.find() && Sentinel.getInstance().getDirector().io.strictList.useRegex;
|
||||
}
|
||||
|
||||
private static String removeFalsePositives(String text) {
|
||||
for (String falsePositive : Sentinel.getInstance().getDirector().io.fpConfig.swearWhitelist) {
|
||||
for (String falsePositive : Sentinel.getInstance().getDirector().io.falsePositiveList.swearWhitelist) {
|
||||
text = text.replace(falsePositive, "");
|
||||
}
|
||||
if (Sentinel.getInstance().getDirector().io.fpConfig.useRegex) text = text.replaceAll(Sentinel.getInstance().getDirector().io.fpConfig.regexWhitelist,"");
|
||||
if (Sentinel.getInstance().getDirector().io.falsePositiveList.useRegex) text = text.replaceAll(Sentinel.getInstance().getDirector().io.falsePositiveList.regexWhitelist,"");
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -255,14 +255,14 @@ public class ProfanityResponse implements FilterResponse {
|
||||
}
|
||||
|
||||
private static String highlightSwears(String text, String start, String end) {
|
||||
for (String swear : Sentinel.getInstance().getDirector().io.swearConfig.swears) {
|
||||
for (String swear : Sentinel.getInstance().getDirector().io.swearList.swears) {
|
||||
text = text.replace(swear, start + swear + end);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
private static String highlightSlurs(String text, String start, String end) {
|
||||
for (String slur : Sentinel.getInstance().getDirector().io.strictConfig.strict) {
|
||||
for (String slur : Sentinel.getInstance().getDirector().io.strictList.strict) {
|
||||
text = text.replace(slur, start + slur + end);
|
||||
}
|
||||
return text;
|
||||
|
||||
@@ -101,7 +101,7 @@ public class CBWhitelistManager {
|
||||
|
||||
public int clearAll() {
|
||||
int total = 0;
|
||||
for (CommandBlockHolder cb : Sentinel.getInstance().getDirector().io.commandBlocks.holders) {
|
||||
for (CommandBlockHolder cb : Sentinel.getInstance().getDirector().io.whitelistStorage.holders) {
|
||||
cb.destroy();
|
||||
cb.delete();
|
||||
total++;
|
||||
@@ -115,7 +115,7 @@ public class CBWhitelistManager {
|
||||
|
||||
public int clearAll(UUID who) {
|
||||
int total = 0;
|
||||
for (CommandBlockHolder cb : Sentinel.getInstance().getDirector().io.commandBlocks.holders) {
|
||||
for (CommandBlockHolder cb : Sentinel.getInstance().getDirector().io.whitelistStorage.holders) {
|
||||
if (!cb.owner().equals(who.toString())) continue;
|
||||
cb.destroy();
|
||||
cb.delete();
|
||||
@@ -130,7 +130,7 @@ public class CBWhitelistManager {
|
||||
|
||||
public int restoreAll() {
|
||||
int total = 0;
|
||||
for (CommandBlockHolder cb : Sentinel.getInstance().getDirector().io.commandBlocks.holders) {
|
||||
for (CommandBlockHolder cb : Sentinel.getInstance().getDirector().io.whitelistStorage.holders) {
|
||||
if (cb.isWhitelisted() && cb.restore()) total++;
|
||||
}
|
||||
return total;
|
||||
@@ -138,7 +138,7 @@ public class CBWhitelistManager {
|
||||
|
||||
public int restoreAll(UUID who) {
|
||||
int total = 0;
|
||||
for (CommandBlockHolder cb : Sentinel.getInstance().getDirector().io.commandBlocks.holders) {
|
||||
for (CommandBlockHolder cb : Sentinel.getInstance().getDirector().io.whitelistStorage.holders) {
|
||||
if (!cb.owner().equals(who.toString())) continue;
|
||||
if (cb.isWhitelisted() && cb.restore()) total++;
|
||||
}
|
||||
@@ -165,7 +165,7 @@ public class CBWhitelistManager {
|
||||
}
|
||||
|
||||
public CommandBlockHolder getFromList(UUID entityUUID) {
|
||||
for (CommandBlockHolder existing : Sentinel.getInstance().getDirector().io.commandBlocks.holders) {
|
||||
for (CommandBlockHolder existing : Sentinel.getInstance().getDirector().io.whitelistStorage.holders) {
|
||||
if (existing.loc().isUUID() && existing.loc().toUIID().equals(entityUUID)) {
|
||||
return existing;
|
||||
}
|
||||
@@ -174,7 +174,7 @@ public class CBWhitelistManager {
|
||||
}
|
||||
|
||||
public CommandBlockHolder getFromList(Location loc) {
|
||||
for (CommandBlockHolder existing : Sentinel.getInstance().getDirector().io.commandBlocks.holders) {
|
||||
for (CommandBlockHolder existing : Sentinel.getInstance().getDirector().io.whitelistStorage.holders) {
|
||||
if (existing.loc().isSameLocation(loc)) {
|
||||
return existing;
|
||||
}
|
||||
@@ -183,7 +183,7 @@ public class CBWhitelistManager {
|
||||
}
|
||||
|
||||
public CommandBlockHolder getFromList(SerialLocation loc) {
|
||||
for (CommandBlockHolder existing : Sentinel.getInstance().getDirector().io.commandBlocks.holders) {
|
||||
for (CommandBlockHolder existing : Sentinel.getInstance().getDirector().io.whitelistStorage.holders) {
|
||||
if (existing.loc().isSameLocation(loc)) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package me.trouper.sentinel.server.functions.helpers;
|
||||
import io.github.itzispyder.pdk.utils.SchedulerUtils;
|
||||
import io.github.itzispyder.pdk.utils.discord.DiscordEmbed;
|
||||
import me.trouper.sentinel.data.misc.Emojis;
|
||||
import me.trouper.sentinel.utils.Random;
|
||||
import me.trouper.sentinel.utils.RandomUtils;
|
||||
import me.trouper.sentinel.utils.trees.EmbedFormatter;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@@ -15,7 +15,7 @@ public class ReportHandler {
|
||||
public Map<Long, Report> reports = new HashMap<>();
|
||||
|
||||
public Report initializeReport(String message) {
|
||||
final long reportID = Random.generateID();
|
||||
final long reportID = RandomUtils.generateID();
|
||||
LinkedHashMap<String,String> steps = new LinkedHashMap<>();
|
||||
steps.put("Original Message", "`%s`".formatted(message));
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import io.github.itzispyder.pdk.plugin.gui.CustomGui;
|
||||
import me.trouper.sentinel.server.gui.Items;
|
||||
import me.trouper.sentinel.server.gui.MainGUI;
|
||||
import me.trouper.sentinel.server.gui.config.ConfigGUI;
|
||||
import me.trouper.sentinel.utils.ServerUtils;
|
||||
import me.trouper.sentinel.utils.Text;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
|
||||
@@ -39,7 +39,7 @@ public class WhitelistGUI extends PaginatedGUI<CommandBlockHolder> {
|
||||
|
||||
@Override
|
||||
protected String getTitle(Player p) {
|
||||
return Text.color("&6&lCommand Blocks &7(%s/%s filtered)".formatted(getFilteredCount(p),Sentinel.getInstance().getDirector().io.commandBlocks.holders.size()));
|
||||
return Text.color("&6&lCommand Blocks &7(%s/%s filtered)".formatted(getFilteredCount(p),Sentinel.getInstance().getDirector().io.whitelistStorage.holders.size()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,7 +127,7 @@ public class WhitelistGUI extends PaginatedGUI<CommandBlockHolder> {
|
||||
protected List<CommandBlockHolder> filterEntries(Player p, FilterOperator operator) {
|
||||
Set<String> filters = activeFilters.computeIfAbsent(p.getUniqueId(), k -> new HashSet<>());
|
||||
ServerUtils.verbose("Filtering entries for %s. Current: ", p, filters.toString());
|
||||
return Sentinel.getInstance().getDirector().io.commandBlocks.holders.stream()
|
||||
return Sentinel.getInstance().getDirector().io.whitelistStorage.holders.stream()
|
||||
.filter(holder -> {
|
||||
if (filters.isEmpty()) return true;
|
||||
boolean result = (operator == FilterOperator.AND); // AND starts true, OR starts false
|
||||
|
||||
@@ -20,6 +20,7 @@ import me.trouper.sentinel.server.events.violations.blocks.structure.StructureBl
|
||||
import me.trouper.sentinel.server.events.violations.blocks.structure.StructureBlockPlace;
|
||||
import me.trouper.sentinel.server.events.violations.blocks.structure.StructureBlockUse;
|
||||
import me.trouper.sentinel.server.events.violations.command.DangerousCommand;
|
||||
import me.trouper.sentinel.server.events.violations.command.HiddenCommand;
|
||||
import me.trouper.sentinel.server.events.violations.command.LoggedCommand;
|
||||
import me.trouper.sentinel.server.events.violations.command.SpecificCommand;
|
||||
import me.trouper.sentinel.server.events.violations.entities.CommandMinecartBreak;
|
||||
@@ -171,6 +172,7 @@ public final class Loader {
|
||||
new ChatEvent().register();
|
||||
new DangerousCommand().register();
|
||||
new LoggedCommand().register();
|
||||
new HiddenCommand().register();
|
||||
new SpecificCommand().register();
|
||||
new CreativeHotbar().register();
|
||||
new TrapCommand().register();
|
||||
|
||||
@@ -48,7 +48,7 @@ public final class FileUtils {
|
||||
|
||||
public static String createCommandLog(String command) {
|
||||
|
||||
String fileName = "command_log-" + Random.generateID();
|
||||
String fileName = "command_log-" + RandomUtils.generateID();
|
||||
File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder() + "/LoggedCommands/" + fileName + ".txt");
|
||||
FileValidationUtils.validate(file);
|
||||
try {
|
||||
|
||||
@@ -11,7 +11,7 @@ import java.util.Set;
|
||||
* Randomize items from a list
|
||||
* @param <T> list of?
|
||||
*/
|
||||
public final class Random<T> {
|
||||
public final class RandomUtils<T> {
|
||||
|
||||
public static Date getDate(long id) throws ParseException {
|
||||
String dateString = String.valueOf(id);
|
||||
@@ -36,7 +36,7 @@ public final class Random<T> {
|
||||
* From array list
|
||||
* @param array list
|
||||
*/
|
||||
public Random(List<T> array) {
|
||||
public RandomUtils(List<T> array) {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public final class Random<T> {
|
||||
* From set
|
||||
* @param array set
|
||||
*/
|
||||
public Random(Set<T> array) {
|
||||
public RandomUtils(Set<T> array) {
|
||||
this.array = new ArrayList<>(array);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public final class Random<T> {
|
||||
* From array
|
||||
* @param array array
|
||||
*/
|
||||
public Random(T[] array) {
|
||||
public RandomUtils(T[] array) {
|
||||
this.array = List.of(array);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user