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:
@@ -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