Tester made a file flooder... rate limits shall be implemented now!
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.
@@ -12,6 +12,7 @@ softdepend:
|
||||
- ViaBackwards
|
||||
- ViaRewind
|
||||
- Geyser-Spigot
|
||||
- NoChatReports
|
||||
load: POSTWORLD
|
||||
permissions:
|
||||
sentinel.admin:
|
||||
|
||||
Binary file not shown.
@@ -4,6 +4,7 @@ import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
|
||||
import me.trouper.sentinel.Sentinel;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class NBTConfig implements JsonSerializable<NBTConfig> {
|
||||
@Override
|
||||
@@ -13,6 +14,16 @@ public class NBTConfig implements JsonSerializable<NBTConfig> {
|
||||
return file;
|
||||
}
|
||||
|
||||
public RateLimit rateLimit = new RateLimit();
|
||||
|
||||
public class RateLimit {
|
||||
public int rateLimitBytes = 16348;
|
||||
public int byteDecay = 1024;
|
||||
public int rateLimitItems = 10;
|
||||
public int itemDecay = 2;
|
||||
public List<String> punishmentCommands = List.of("kick %player% Internal Exception: io.netty.handler.codec.DecoderException: java.lang.RuntimeException: Tried to read NBT tag that was too big; tried to allocate 28391038bytes where max allowed: 16348");
|
||||
}
|
||||
|
||||
public boolean allowName = true;
|
||||
public boolean allowLore = true;
|
||||
public boolean allowAttributes = false;
|
||||
@@ -21,6 +32,8 @@ public class NBTConfig implements JsonSerializable<NBTConfig> {
|
||||
public boolean allowCustomTools = false;
|
||||
public boolean allowBooks = false;
|
||||
public boolean allowRecursion = true;
|
||||
public int maxCustomData = 64;
|
||||
|
||||
public int globalMaxEnchant = 5;
|
||||
public int maxMending = 1;
|
||||
public int maxUnbreaking = 3;
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package me.trouper.sentinel.server.events.violations.players;
|
||||
|
||||
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
|
||||
import io.github.itzispyder.pdk.utils.misc.Pair;
|
||||
import me.trouper.sentinel.Sentinel;
|
||||
import me.trouper.sentinel.data.storage.NBTStorage;
|
||||
import me.trouper.sentinel.server.events.violations.AbstractViolation;
|
||||
import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
|
||||
import me.trouper.sentinel.server.functions.itemchecks.ItemCheck;
|
||||
import me.trouper.sentinel.server.functions.itemchecks.RateLimitCheck;
|
||||
import me.trouper.sentinel.server.gui.Items;
|
||||
import me.trouper.sentinel.server.gui.MainGUI;
|
||||
import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
|
||||
@@ -28,18 +30,36 @@ public class CreativeHotbar extends AbstractViolation {
|
||||
private void onNBTPull(InventoryCreativeEvent e) {
|
||||
//ServerUtils.verbose("NBT: Detected creative mode action");
|
||||
if (!Sentinel.getInstance().getDirector().io.violationConfig.creativeHotbarAction.enabled) return;
|
||||
ServerUtils.verbose("NBT: Enabled");
|
||||
//ServerUtils.verbose("NBT: Enabled");
|
||||
if (!(e.getWhoClicked() instanceof Player p)) return;
|
||||
ServerUtils.verbose("NBT: Clicker is a player");
|
||||
//ServerUtils.verbose("NBT: Clicker is a player");
|
||||
if (e.getCursor() == null) return; // Well it threw an exception during testing, so it isn't always false!
|
||||
ServerUtils.verbose("NBT: Cursor isn't null");
|
||||
//ServerUtils.verbose("NBT: Cursor isn't null");
|
||||
ItemStack i = e.getCursor();
|
||||
if (PlayerUtils.isTrusted(p)) return;
|
||||
ServerUtils.verbose("NBT: Not trusted");
|
||||
//ServerUtils.verbose("NBT: Not trusted");
|
||||
if (e.getCursor().getItemMeta() == null) return;
|
||||
ServerUtils.verbose("NBT: Cursor has meta");
|
||||
//ServerUtils.verbose("NBT: Cursor has meta");
|
||||
if (!(i.hasItemMeta() && i.getItemMeta() != null)) return;
|
||||
ServerUtils.verbose("NBT: Item has meta");
|
||||
if (!new RateLimitCheck().passes(new Pair<>(p,i))) {
|
||||
ServerUtils.verbose("Player flags rate limit, performing action");
|
||||
ActionConfiguration.Builder config = new ActionConfiguration.Builder()
|
||||
.setEvent(e)
|
||||
.setPlayer(p)
|
||||
.cancel(true)
|
||||
.punish(true)
|
||||
.deop(Sentinel.getInstance().getDirector().io.violationConfig.creativeHotbarAction.deop)
|
||||
.setPunishmentCommands(Sentinel.getInstance().getDirector().io.nbtConfig.rateLimit.punishmentCommands);
|
||||
|
||||
runActions(
|
||||
Sentinel.getInstance().getDirector().io.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.getInstance().getDirector().io.lang.violations.protections.rootName.grab, Sentinel.getInstance().getDirector().io.lang.violations.protections.rootName.nbtItem),
|
||||
Sentinel.getInstance().getDirector().io.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.getInstance().getDirector().io.lang.violations.protections.rootName.grab, Sentinel.getInstance().getDirector().io.lang.violations.protections.rootName.nbtItem),
|
||||
generatePlayerInfo(p),
|
||||
config
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
if (new ItemCheck().passes(i)) return;
|
||||
ServerUtils.verbose("NBT: Item doesn't pass, performing action");
|
||||
|
||||
|
||||
@@ -62,12 +62,6 @@ public class PluginCloakingPacket implements PacketListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
case PacketType.Play.Client.CHAT_COMMAND, PacketType.Play.Client.CHAT_COMMAND_UNSIGNED -> {
|
||||
WrapperPlayClientChatCommandUnsigned wrapper = new WrapperPlayClientChatCommandUnsigned(event);
|
||||
WrapperPlayClientChatCommand wrappers = new WrapperPlayClientChatCommand(event);
|
||||
wrapper.getCommand();
|
||||
wrappers.getCommand();
|
||||
}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ public class ActionConfiguration {
|
||||
this.punishmentCommands = builder.punishmentCommands;
|
||||
this.logToDiscord = builder.logToDiscord;
|
||||
this.actionNode = builder.actionNode;
|
||||
// Removed the actions being run here to prevent double execution
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.trouper.sentinel.server.functions.itemchecks;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import me.trouper.sentinel.Sentinel;
|
||||
import me.trouper.sentinel.data.config.NBTConfig;
|
||||
import me.trouper.sentinel.utils.InventoryUtils;
|
||||
import me.trouper.sentinel.utils.ServerUtils;
|
||||
import org.bukkit.Material;
|
||||
@@ -17,6 +18,7 @@ public class ItemCheck extends AbstractCheck<ItemStack> {
|
||||
@Override
|
||||
public boolean passes(ItemStack item) {
|
||||
ServerUtils.verbose("Checking item: " + item.getType().name());
|
||||
NBTConfig config = Sentinel.getInstance().getDirector().io.nbtConfig;
|
||||
|
||||
// No metadata? Nothing to check.
|
||||
if (item.getItemMeta() == null) {
|
||||
@@ -38,11 +40,11 @@ public class ItemCheck extends AbstractCheck<ItemStack> {
|
||||
// NBT-based checks (e.g. custom consumables/tools).
|
||||
var nbt = NBT.itemStackToNBT(item);
|
||||
var components = nbt.getCompound("components");
|
||||
if (!Sentinel.getInstance().getDirector().io.nbtConfig.allowCustomConsumables && components.getCompound("minecraft:consumable") != null) {
|
||||
if (!config.allowCustomConsumables && components.getCompound("minecraft:consumable") != null) {
|
||||
ServerUtils.verbose("Item is consumable and not allowed.");
|
||||
return false;
|
||||
}
|
||||
if (!Sentinel.getInstance().getDirector().io.nbtConfig.allowCustomTools && components.getCompound("minecraft:tool") != null) {
|
||||
if (!config.allowCustomTools && components.getCompound("minecraft:tool") != null) {
|
||||
ServerUtils.verbose("Item is custom tool and not allowed.");
|
||||
return false;
|
||||
}
|
||||
@@ -148,32 +150,32 @@ public class ItemCheck extends AbstractCheck<ItemStack> {
|
||||
}
|
||||
|
||||
// Name, lore, potion, attribute and enchantment checks.
|
||||
if (!Sentinel.getInstance().getDirector().io.nbtConfig.allowName && meta.hasDisplayName()) {
|
||||
if (!config.allowName && meta.hasDisplayName()) {
|
||||
ServerUtils.verbose("Custom names not allowed.");
|
||||
return false;
|
||||
}
|
||||
if (!Sentinel.getInstance().getDirector().io.nbtConfig.allowLore && meta.hasLore()) {
|
||||
if (!config.allowLore && meta.hasLore()) {
|
||||
ServerUtils.verbose("Custom lore not allowed.");
|
||||
return false;
|
||||
}
|
||||
if (!Sentinel.getInstance().getDirector().io.nbtConfig.allowPotions &&
|
||||
if (!config.allowPotions &&
|
||||
(item.getType().equals(Material.POTION) ||
|
||||
item.getType().equals(Material.SPLASH_POTION) ||
|
||||
item.getType().equals(Material.LINGERING_POTION))) {
|
||||
ServerUtils.verbose("Potions not allowed.");
|
||||
return false;
|
||||
}
|
||||
if (!Sentinel.getInstance().getDirector().io.nbtConfig.allowAttributes && meta.hasAttributeModifiers()) {
|
||||
if (!config.allowAttributes && meta.hasAttributeModifiers()) {
|
||||
ServerUtils.verbose("Attribute modifiers not allowed.");
|
||||
return false;
|
||||
}
|
||||
if (Sentinel.getInstance().getDirector().io.nbtConfig.globalMaxEnchant != 0 && new EnchantmentCheck().hasIllegalEnchants(item)) {
|
||||
if (config.globalMaxEnchant != 0 && new EnchantmentCheck().hasIllegalEnchants(item)) {
|
||||
ServerUtils.verbose("Illegal enchantments found.");
|
||||
return false;
|
||||
}
|
||||
// Recursion check for use-remainder items.
|
||||
if (meta.hasUseRemainder()) {
|
||||
if (!Sentinel.getInstance().getDirector().io.nbtConfig.allowRecursion) {
|
||||
if (!config.allowRecursion) {
|
||||
ServerUtils.verbose("Recursion not allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package me.trouper.sentinel.server.functions.itemchecks;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import io.github.itzispyder.pdk.utils.misc.Pair;
|
||||
import me.trouper.sentinel.Sentinel;
|
||||
import me.trouper.sentinel.utils.ServerUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class RateLimitCheck extends AbstractCheck<Pair<Player,ItemStack>> {
|
||||
|
||||
|
||||
public static Map<UUID, Integer> dataUsed = new HashMap<>();
|
||||
public static Map<UUID, Integer> itemsUsed = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean passes(Pair<Player,ItemStack> input) {
|
||||
Player player = input.left;
|
||||
UUID uuid = player.getUniqueId();
|
||||
ItemStack item = input.right;
|
||||
|
||||
return itemLimit(player,uuid,item) && dataLimit(player,uuid,item);
|
||||
}
|
||||
|
||||
private boolean itemLimit(Player player, UUID uuid, ItemStack item) {
|
||||
int currentUsed = itemsUsed.getOrDefault(uuid,0);
|
||||
ServerUtils.verbose("Current Player used items: " + currentUsed);
|
||||
currentUsed++;
|
||||
itemsUsed.put(uuid,currentUsed);
|
||||
return currentUsed <= Sentinel.getInstance().getDirector().io.nbtConfig.rateLimit.rateLimitItems;
|
||||
}
|
||||
|
||||
|
||||
private boolean dataLimit(Player player, UUID uuid, ItemStack item) {
|
||||
int itemData = 0;
|
||||
int currentData = dataUsed.getOrDefault(uuid,0);
|
||||
|
||||
ServerUtils.verbose("Current Player used data: " + currentData);
|
||||
try {
|
||||
NBTItem nbt = new NBTItem(item);
|
||||
itemData = nbt.toString().length();
|
||||
ServerUtils.verbose("Item data: " + itemData);
|
||||
currentData += itemData;
|
||||
} catch (Exception e) {
|
||||
Sentinel.getInstance().getLogger().warning("Could not determine size of item. Blocking.");
|
||||
Sentinel.getInstance().getLogger().warning(Arrays.toString(e.getStackTrace()));
|
||||
return false;
|
||||
}
|
||||
|
||||
dataUsed.put(uuid,currentData);
|
||||
|
||||
ServerUtils.verbose("New Player used data: " + currentData);
|
||||
|
||||
return currentData <= Sentinel.getInstance().getDirector().io.nbtConfig.rateLimit.rateLimitBytes;
|
||||
}
|
||||
|
||||
public static void decayData() {
|
||||
for (UUID uuid : dataUsed.keySet()) {
|
||||
int currentData = dataUsed.get(uuid);
|
||||
if (currentData > 0) {
|
||||
currentData -= Sentinel.getInstance().getDirector().io.nbtConfig.rateLimit.byteDecay;
|
||||
dataUsed.put(uuid, Math.max(0, currentData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void decayItems() {
|
||||
for (UUID uuid : itemsUsed.keySet()) {
|
||||
int currentItems = itemsUsed.get(uuid);
|
||||
if (currentItems > 0) {
|
||||
currentItems -= Sentinel.getInstance().getDirector().io.nbtConfig.rateLimit.itemDecay;
|
||||
itemsUsed.put(uuid, Math.max(0, currentItems));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import me.trouper.sentinel.server.events.violations.entities.CommandMinecartPlac
|
||||
import me.trouper.sentinel.server.events.violations.entities.CommandMinecartUse;
|
||||
import me.trouper.sentinel.server.functions.chatfilter.profanity.ProfanityFilter;
|
||||
import me.trouper.sentinel.server.functions.chatfilter.spam.SpamFilter;
|
||||
import me.trouper.sentinel.server.functions.itemchecks.RateLimitCheck;
|
||||
import me.trouper.sentinel.utils.Text;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
@@ -183,6 +184,8 @@ public final class Loader {
|
||||
Bukkit.getScheduler().runTaskTimer(Sentinel.getInstance(), SpamFilter::decayHeat,0, 20);
|
||||
Bukkit.getScheduler().runTaskTimer(Sentinel.getInstance(), ProfanityFilter::decayScore,0,1200);
|
||||
Bukkit.getScheduler().runTaskTimer(Sentinel.getInstance(), WandEvents::handleDisplay,0,1);
|
||||
Bukkit.getScheduler().runTaskTimer(Sentinel.getInstance(), RateLimitCheck::decayData,0,20*60);
|
||||
Bukkit.getScheduler().runTaskTimer(Sentinel.getInstance(), RateLimitCheck::decayItems,0,200);
|
||||
|
||||
if (Sentinel.getInstance().getDirector().io.mainConfig.backdoorDetection.enabled) Sentinel.getInstance().getDirector().backdoorDetection.init();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user