Compare commits

...
22 Commits
Author SHA1 Message Date
rayzsyt b53678764a Update version 2026-09-20 03:14:07 +02:00
rayzsyt 1f7743d089 Removed debug messages 2026-09-20 03:13:04 +02:00
rayzsyt a60b6896f7 Fixed that KICK_ON_FAILURE wasn't listened at anymore 2026-08-31 06:17:26 +02:00
rayzsyt 34c33df136 Add sanity check just in case 2026-08-25 22:37:13 +02:00
rayzsyt ef63674b0c Changed approach to detect commands for tab-completion 2026-08-21 19:11:06 +02:00
rayzsyt 130af1547d Ignore IgnoreStarPermission feature and instead made PAT able to recognise negated PAT permissions 2026-08-20 19:47:52 +02:00
rayzsyt cdb17c1ea8 Add option for PAT to ignore the Star permission 2026-08-19 22:32:55 +02:00
rayzsyt 8f4f4b6438 Remove debug message 2026-08-19 20:44:55 +02:00
rayzsyt 3a0fc6e579 Add feature to show non-existing commands in tab-completion when whitelisted, no matter if they exist or not. (Only for proxies in PAT groups) 2026-08-19 20:44:42 +02:00
rayzsyt e0747a5101 Fixed incompatibility issue with Skript commands 2026-08-15 23:48:46 +02:00
rayzsyt 5741dab763 Small logical change to improve performance by a tiny bit 2026-08-15 23:34:17 +02:00
rayzsyt 5d7a8bb4c5 Improved implementation of cached commands 2026-08-15 23:34:04 +02:00
rayzsyt 786b2fa560 Fixed logic when to send warning message 2026-08-15 23:33:51 +02:00
rayzsyt 5cf51052d2 Fixed exception when loading or reading list 2026-08-15 23:33:40 +02:00
rayzsyt 22eaecb17f Update version 2026-08-15 15:46:39 +02:00
rayzsyt 816354bb92 Implemented warning message when trying to use 'custom-unknown-command' feature while PAT is running in WHITELIST mode anyway 2026-08-15 15:43:27 +02:00
rayzsyt 2fc6d96bd9 Small adjustments 2026-08-15 15:43:00 +02:00
rayzsyt 3f472b0bf5 Moved REGISTER_CHANNELS to appropriate config section instead 2026-08-15 15:21:16 +02:00
rayzsyt 41417893be Implement hide-plugin-channels feature for Bungeecord 2026-08-15 15:20:54 +02:00
rayzsyt 64a7b80ec5 Implement hide-plugin-channels feature for Velocity 2026-08-15 15:04:05 +02:00
rayzsyt 65f136f2b8 Just moved a line bit further down lol 2026-08-15 15:03:15 +02:00
rayzsyt 618bee5e9b Implement plugin-spoofing fix via plugin-channels 2026-08-15 04:29:06 +02:00
23 changed files with 439 additions and 82 deletions

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>de.rayzs.pat</groupId>
<artifactId>ProAntiTab</artifactId>
<version>2.4.3</version>
<version>2.5.1</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
@@ -335,8 +335,11 @@ public class Storage {
public static final AllowGroupOverrulingSection ALLOW_GROUP_OVERRULING = new AllowGroupOverrulingSection();
public static final AutoLowercaseCommandsSection AUTO_LOWERCASE_COMMANDS = new AutoLowercaseCommandsSection();
public static final TurnBlacklistToWhitelistSection TURN_BLACKLIST_TO_WHITELIST = new TurnBlacklistToWhitelistSection();
public static final BlockNamespaceCommandsSection BLOCK_NAMESPACE_COMMANDS = new BlockNamespaceCommandsSection();
public static final HandleThroughProxySection HANDLE_THROUGH_PROXY = new HandleThroughProxySection();
public static final HidePluginChannelsSection HIDE_PLUGIN_CHANNELS = new HidePluginChannelsSection();
public static final TabCompletionForNotExistingCommandsSection TAB_COMPLETION_FOR_NOT_EXISTING_COMMANDS = new TabCompletionForNotExistingCommandsSection();
public static final InjectionFailedSection INJECTION_FAILED = new InjectionFailedSection();
public static final PatchExploitSection PATCH_EXPLOITS = new PatchExploitSection();
public static final CustomBrandSection CUSTOM_BRAND = new CustomBrandSection();
@@ -348,7 +351,6 @@ public class Storage {
public static final ForwardLuckPermsChangesSection FORWARD_LUCK_PERMS_CHANGES_SECTION = new ForwardLuckPermsChangesSection();
public static final CustomProtocolPingSection CUSTOM_PROTOCOL_PING = new CustomProtocolPingSection();
public static final CustomUnknownCommandSection CUSTOM_UNKNOWN_COMMAND = new CustomUnknownCommandSection();
public static final TurnBlacklistToWhitelistSection TURN_BLACKLIST_TO_WHITELIST = new TurnBlacklistToWhitelistSection();
public static final BaseCommandCaseSensitiveSection BASE_COMMAND_CASE_SENSITIVE = new BaseCommandCaseSensitiveSection();
public static final UpdateGroupsPerWorldSection UPDATE_GROUPS_PER_WORLD = new UpdateGroupsPerWorldSection();
public static final UpdateGroupsPerServerSection UPDATE_GROUPS_PER_SERVER = new UpdateGroupsPerServerSection();
@@ -1,6 +1,7 @@
package de.rayzs.pat.api.storage.config.settings;
import de.rayzs.pat.api.storage.storages.ConfigStorage;
import de.rayzs.pat.plugin.logger.Logger;
import de.rayzs.pat.utils.configuration.helper.*;
import de.rayzs.pat.api.storage.Storage;
import java.util.Collections;
@@ -18,8 +19,15 @@ public class CustomUnknownCommandSection extends ConfigStorage {
public void load() {
super.load();
if(Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED) return;
if (Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED) return;
ENABLED = new ConfigSectionHelper<Boolean>(this, "enabled", true).getOrSet();
MESSAGE = new MultipleMessagesHelper(this, "message", Collections.singletonList("&cThis command does not exist!"));
if (ENABLED && Storage.ConfigSections.Settings.TURN_BLACKLIST_TO_WHITELIST.ENABLED) {
Logger.warning("It's not recommended to use the 'custom-unknown-command' feature when you are already using ProAntiTab in WHITELIST mode! Since in this mode, all commands except the once you specifically allow, are blocked anyway. So instead, change the 'blocked' message to your desired message. It has the same effect.");
}
}
}
@@ -0,0 +1,37 @@
package de.rayzs.pat.api.storage.config.settings;
import de.rayzs.pat.api.storage.storages.ConfigStorage;
import de.rayzs.pat.utils.configuration.helper.ConfigSectionHelper;
import de.rayzs.pat.utils.configuration.helper.MultipleMessagesHelper;
import java.util.Arrays;
import java.util.HashSet;
public class HidePluginChannelsSection extends ConfigStorage {
public boolean ENABLED;
public MultipleMessagesHelper WHITELISTED_CHANNELS;
private final HashSet<String> REGISTER_CHANNELS = new HashSet<>(
Arrays.asList("register", "unregister", "minecraft:register", "minecraft:unregister")
);
public HidePluginChannelsSection() {
super("plugin-channels-hider");
}
@Override
public void load() {
super.load();
ENABLED = new ConfigSectionHelper<Boolean>(this, "enabled", false).getOrSet();
WHITELISTED_CHANNELS = new MultipleMessagesHelper(this, "whitelisted-channels", Arrays.asList(
"minecraft:brand",
"bungeecord:main",
"velocity:main"
));
}
public boolean isRegisterChannel(final String channelId) {
return REGISTER_CHANNELS.contains(channelId);
}
}
@@ -0,0 +1,22 @@
package de.rayzs.pat.api.storage.config.settings;
import de.rayzs.pat.api.storage.storages.ConfigStorage;
import de.rayzs.pat.utils.Reflection;
import de.rayzs.pat.utils.configuration.helper.ConfigSectionHelper;
public class TabCompletionForNotExistingCommandsSection extends ConfigStorage {
public boolean ENABLED;
public TabCompletionForNotExistingCommandsSection() {
super("tab-completion-for-not-existing-commands");
}
@Override
public void load() {
super.load();
if (!Reflection.isProxyServer()) return;
ENABLED = new ConfigSectionHelper<Boolean>(this, null, false).getOrSet();
}
}
@@ -45,9 +45,9 @@ import java.util.stream.Collectors;
public class BukkitLoader extends JavaPlugin implements PluginLoader {
private static List<String> commands = new ArrayList<>(),
allowedCommands = new ArrayList<>(),
disallowedCommands = new ArrayList<>();
private static List<String> allCommands = new ArrayList<>(),
allowedCommands = new ArrayList<>(),
disallowedCommands = new ArrayList<>();
private static Plugin plugin;
private static java.util.logging.Logger logger;
@@ -55,6 +55,7 @@ public class BukkitLoader extends JavaPlugin implements PluginLoader {
private final CommandsCache commandsCache = new CommandsCache();
private final List<String> offlinePlayerNames = new ArrayList<>();
private HashSet<String> registeredCommands = new HashSet<>();
private Map<String, Command> commandsMap = null;
private BukkitAntiTabListener bukkitAntiTabListener = null;
@@ -235,9 +236,7 @@ public class BukkitLoader extends JavaPlugin implements PluginLoader {
if (commandsMap == null)
return false;
loadAllCommands();
return getAllCommands().contains(command);
return registeredCommands.contains(command);
}
@Override
@@ -355,12 +354,10 @@ public class BukkitLoader extends JavaPlugin implements PluginLoader {
}
public static List<String> getAllCommands() {
return new ArrayList<>(commands);
return allCommands;
}
public static List<String> getAllowedCommands() {
return new ArrayList<>(allowedCommands);
}
public static List<String> getAllowedCommands() { return allowedCommands; }
public static List<String> getDisallowedCommands() {
return disallowedCommands;
@@ -442,50 +439,47 @@ public class BukkitLoader extends JavaPlugin implements PluginLoader {
}
private void loadAllCommands() {
if (Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED) return;
if (lastCommandsLoad != -1 && System.currentTimeMillis() - lastCommandsLoad < 1000)
return;
List<String> result = new ArrayList<>();
final HashSet<String> tmpCommands = new HashSet<>(Bukkit.getHelpMap().getHelpTopics().stream()
.map(topic -> {
String name = topic.getName();
if (commandsMap == null) {
result.addAll(
Bukkit.getHelpMap().getHelpTopics().stream()
.map(topic -> {
String name = topic.getName();
if (name.startsWith("/"))
name = name.substring(1);
if (name.startsWith("/"))
name = name.substring(1);
return name;
}).toList()
);
return;
}
return name;
}).toList());
commandsMap.entrySet().forEach(entry -> {
String key = entry.getKey();
Command command = entry.getValue();
final String key = entry.getKey();
final Command command = entry.getValue();
result.add(key);
tmpCommands.add(key);
if (!command.getAliases().isEmpty()) {
result.addAll(command.getAliases());
tmpCommands.addAll(command.getAliases());
}
});
boolean turn = Storage.ConfigSections.Settings.TURN_BLACKLIST_TO_WHITELIST.ENABLED;
List<String> allowedCommands = new ArrayList<>(result).stream().filter(command -> {
boolean contains = Storage.Blacklist.getBlacklist().getCommands().contains(command);
final boolean turn = Storage.ConfigSections.Settings.TURN_BLACKLIST_TO_WHITELIST.ENABLED;
final List<String> tmpAllowedCommands = tmpCommands.stream().filter(command -> {
final boolean contains = Storage.Blacklist.getBlacklist().getCommands().contains(command);
return turn == contains;
}).toList();
final List<String> tmpDisallowedCommands = tmpCommands.stream().filter(command ->
!allowedCommands.contains(command)
).toList();
lastCommandsLoad = System.currentTimeMillis();
BukkitLoader.commands = result;
BukkitLoader.allowedCommands = allowedCommands;
BukkitLoader.disallowedCommands = commands.stream().filter(command -> !allowedCommands.contains(command)).toList();
registeredCommands = tmpCommands;
allowedCommands = tmpAllowedCommands;
disallowedCommands = tmpDisallowedCommands;
}
public static Plugin getPlugin() {
@@ -42,7 +42,7 @@ import java.util.*;
@Plugin(name = "ProAntiTab",
id = "proantitab",
version = "2.4.3",
version = "2.5.1",
authors = "Rayzs_YT",
description = "Hides more than just your plugins.",
url = "https://www.rayzs.de/products/proantitab/page",
@@ -24,16 +24,17 @@ public class BukkitAntiTabListener implements Listener {
@EventHandler (priority = EventPriority.LOWEST)
public void onPlayerCommandSend(PlayerCommandSendEvent event) {
final Player player = event.getPlayer();
final CommandSender sender = CommandSender.from(player);
final UUID uuid = player.getUniqueId();
final boolean isOperator = player.isOp();
if (Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED) {
return;
}
final Player player = event.getPlayer();
final CommandSender sender = CommandSender.from(player);
final UUID uuid = player.getUniqueId();
final boolean isOperator = player.isOp();
if (player.isOp()) {
if (!knownOperators.contains(uuid)) {
knownOperators.add(uuid);
@@ -40,14 +40,8 @@ public class BukkitBlockCommandListener implements Listener {
if (PermissionUtil.hasBypassPermission(sender, isOperator))
return;
/* Removed since not necessary and only takes up unnecessary performance.
if (Storage.getLoader().doesCommandExist(command))
return;
*/
if (Bukkit.getHelpMap().getHelpTopic(rawCommand) != null)
return;
event.setCancelled(true);
MessageTranslator.send(player, Storage.ConfigSections.Settings.CUSTOM_UNKNOWN_COMMAND.MESSAGE, "%command%", command, "%world%", world.getName());
@@ -3,9 +3,11 @@ package de.rayzs.pat.plugin.listeners.velocity;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.command.CommandExecuteEvent;
import com.velocitypowered.api.command.CommandSource;
import de.rayzs.pat.plugin.logger.Logger;
import de.rayzs.pat.plugin.system.communication.Communicator;
import de.rayzs.pat.api.event.events.ExecuteCommandEvent;
import de.rayzs.pat.plugin.system.subargument.SubArgument;
import de.rayzs.pat.plugin.system.subargument.argument.Arguments;
import de.rayzs.pat.utils.group.Group;
import de.rayzs.pat.utils.group.GroupManager;
import de.rayzs.pat.utils.message.MessageTranslator;
@@ -139,7 +141,6 @@ public class VelocityBlockCommandListener {
if (!allowed) {
ExecuteCommandEvent executeCommandEvent = PATEventHandler.callExecuteCommandEvents(
sender,
event.getCommand(),
@@ -190,6 +191,22 @@ public class VelocityBlockCommandListener {
);
if (executeCommandEvent.isBlocked()) {
/*
if (event.getCommand().toLowerCase().contains("discord")) {
Logger.info("Blocked for " + player.getUsername() + " (" + command + " -> " + event.getCommand() + ")");
Logger.info("Groups: " + (groups.isEmpty() ? "None" : String.join(", ", groups.stream().map(Group::getGroupName).toList())));
Logger.info("Server: " + serverName + " (" + sender.getServerName() + ")");
Arguments argument = SubArgument.get().getPlayerArgument(sender);
if (argument != null) {
Logger.info("Chat Arguments: " + String.join(", ", argument.CHAT_ARGUMENTS.getAllInputs()));
Logger.info("Tab Arguments: " + String.join(", ", argument.TAB_ARGUMENTS.getAllInputs()));
} else Logger.info("Arguments: /");
}
*/
event.setResult(CommandExecuteEvent.CommandResult.denied());
MessageTranslator.send(
@@ -5,6 +5,10 @@ import de.rayzs.pat.plugin.packetanalyzer.bukkit.handlers.LegacyPacketHandler;
import de.rayzs.pat.plugin.packetanalyzer.bukkit.handlers.ModernCommandsNodeHandler;
import de.rayzs.pat.plugin.packetanalyzer.bukkit.handlers.ModernPacketHandler;
import de.rayzs.pat.utils.permission.PermissionUtil;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ConcurrentHashMap;
import de.rayzs.pat.api.storage.Storage;
import de.rayzs.pat.utils.ExpireCache;
@@ -16,6 +20,7 @@ import org.bukkit.entity.Player;
import io.netty.channel.*;
import org.bukkit.Bukkit;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class BukkitPacketAnalyzer {
@@ -49,7 +54,7 @@ public class BukkitPacketAnalyzer {
}
public static boolean inject(Player player) {
if (Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED)
if (Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED && !Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.ENABLED)
return true;
try {
@@ -81,6 +86,11 @@ public class BukkitPacketAnalyzer {
return success;
} catch (NoSuchFieldException noSuchFieldException) {
if (!Storage.ConfigSections.Settings.INJECTION_FAILED.ENABLED) {
return true;
}
Logger.warning("Failed to inject into " + player.getName() + " and kicked the player as result, to avoid any security risks.");
Logger.warning("You can read more about it here: https://www.rayzs.de/products/proantitab/pkafi");
Logger.warning("Error details: " + noSuchFieldException.getMessage());
@@ -110,7 +120,7 @@ public class BukkitPacketAnalyzer {
}
public static void uninject(Channel channel) {
if (Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED)
if (Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED && !Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.ENABLED)
return;
if (channel != null) {
@@ -151,13 +161,30 @@ public class BukkitPacketAnalyzer {
@Override
public void channelRead(ChannelHandlerContext channel, Object packetObj) {
try {
if (packetObj.getClass() == null || Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED) {
if (packetObj.getClass() == null) {
super.channelRead(channel, packetObj);
return;
}
String packetName = packetObj.getClass().getSimpleName();
if (Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.ENABLED && packetName.equalsIgnoreCase("ServerboundCustomPayloadPacket")) {
final Object newPacketObj = handlePluginChannelPacket(packetObj);
if (newPacketObj != null)
super.channelRead(channel, newPacketObj);
return;
}
if (Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED) {
super.channelRead(channel, packetObj);
return;
}
if (!packetName.equals("PacketPlayInTabComplete") && !packetName.equals("ServerboundCommandSuggestionPacket")) {
super.channelRead(channel, packetObj);
return;
@@ -177,13 +204,30 @@ public class BukkitPacketAnalyzer {
@Override
public void write(ChannelHandlerContext channel, Object packetObj, ChannelPromise promise) {
try {
if(packetObj.getClass() == null || Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED) {
if(packetObj.getClass() == null) {
super.write(channel, packetObj, promise);
return;
}
final String packetName = packetObj.getClass().getSimpleName();
if (Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.ENABLED && packetName.equalsIgnoreCase("ClientboundCustomPayloadPacket")) {
final Object newPacketObj = handlePluginChannelPacket(packetObj);
if (newPacketObj != null)
super.write(channel, newPacketObj, promise);
return;
}
if (Storage.ConfigSections.Settings.HANDLE_THROUGH_PROXY.ENABLED) {
super.write(channel, packetObj, promise);
return;
}
final boolean isCommandsPacket = packetName.equals("ClientboundCommandsPacket");
final boolean isTabCompletePacket = packetName.equals("PacketPlayOutTabComplete") || packetName.equals("ClientboundCommandSuggestionsPacket");
@@ -234,5 +278,75 @@ public class BukkitPacketAnalyzer {
return this.operatorStatus;
}
private Object handlePluginChannelPacket(Object packet) throws NoSuchFieldException, IllegalAccessException {
final Field payloadField = packet.getClass().getDeclaredField("payload");
payloadField.setAccessible(true);
final Object payloadObj = payloadField.get(packet);
Field channelField;
try {
channelField = payloadObj.getClass().getDeclaredField("id");
} catch (NoSuchFieldException noSuchFieldException) {
return packet;
}
channelField.setAccessible(true);
final Object channelIdObj = channelField.get(payloadObj);
final String channelId = channelIdObj.toString();
channelField.setAccessible(false);
if (!Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.isRegisterChannel(channelId)) {
return packet;
}
final Field dataField = payloadObj.getClass().getDeclaredField("data");
dataField.setAccessible(true);
final byte[] data = (byte[]) dataField.get(payloadObj);
dataField.setAccessible(true);
final String dataStr = new String(data, StandardCharsets.UTF_8);
final String[] channels = dataStr.split("\u0000");
final List<String> filteredChannels = new ArrayList<>(Arrays.asList(channels));
final AtomicBoolean changedAnything = new AtomicBoolean(false);
filteredChannels.removeIf(channel -> {
if (!Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.WHITELISTED_CHANNELS.getLines().contains(channel)) {
changedAnything.set(true);
return true;
}
return false;
});
if (!changedAnything.get()) {
return packet;
}
try {
final Class<?> customPayloadClass = packet.getClass().getConstructors()[0].getParameterTypes()[0];
final Class<?> discardPayloadClass = payloadObj.getClass();
final Constructor<?> discardPayloadConstr = discardPayloadClass.getConstructor(channelIdObj.getClass(), byte[].class);
final Object newDiscardPayloadObj = discardPayloadConstr.newInstance(
channelIdObj,
String.join("\u0000", filteredChannels).getBytes()
);
final Constructor<?> newPacketConstr = packet.getClass().getConstructor(customPayloadClass);
return newPacketConstr.newInstance(newDiscardPayloadObj);
} catch (Exception exception) {
exception.printStackTrace();
}
return packet;
}
}
}
@@ -1,9 +1,11 @@
package de.rayzs.pat.plugin.packetanalyzer.proxy;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import com.mojang.brigadier.tree.CommandNode;
@@ -146,16 +148,17 @@ public class BungeePacketAnalyzer {
final boolean ignore = PermissionUtil.hasBypassPermission(sender, false) || Storage.Blacklist.isDisabledServer(serverName);
ProxyCommandNodeHelper helper = new ProxyCommandNodeHelper<CommandNode>(commands.getRoot());
List<String> commandsAsString = new ArrayList<>(PROXY_COMMANDS);
final ProxyCommandNodeHelper helper = new ProxyCommandNodeHelper<CommandNode>(commands.getRoot());
final List<String> commandsAsString = new ArrayList<>(PROXY_COMMANDS);
commandsAsString.addAll(helper.getChildrenNames());
final List<Group> groups = ignore
? Collections.emptyList()
: GroupManager.getPlayerGroups(sender, false);
HashSet<String> playerCommands = new HashSet<>();
if (!ignore) {
final List<Group> groups = GroupManager.getPlayerGroups(sender, false);
final Map<String, CommandsCache> cache = Storage.getLoader().getPerServerCommandsCacheMap();
if (!cache.containsKey(serverName)) {
cache.put(serverName, new CommandsCache());
@@ -216,6 +219,14 @@ public class BungeePacketAnalyzer {
}
}
if (Storage.ConfigSections.Settings.TAB_COMPLETION_FOR_NOT_EXISTING_COMMANDS.ENABLED) {
for (Group group : groups) {
for (String groupCommands : group.getAllCommands(serverName)) {
helper.add(groupCommands, true);
}
}
}
if (!ignore) {
SubArgument.get().getCommandNodeHandler().handleCommandNode(helper, SubArgument.get().getPlayerArgument(sender));
}
@@ -240,6 +251,7 @@ public class BungeePacketAnalyzer {
}
}
private static class PacketDecoder extends MessageToMessageDecoder<PacketWrapper> {
private final ProxiedPlayer player;
@@ -262,6 +274,31 @@ public class BungeePacketAnalyzer {
if (CustomServerBrand.get().isEnabled() && CustomServerBrand.get().isBrandTag(pluginMessage.getTag())) {
return;
} else if (Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.ENABLED) {
final String channelId = pluginMessage.getTag();
if (Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.isRegisterChannel(channelId)) {
final String dataStr = new String(pluginMessage.getData(), StandardCharsets.UTF_8);
final String[] channels = dataStr.split("\u0000");
final List<String> filteredChannels = new ArrayList<>(Arrays.asList(channels));
final AtomicBoolean changedAnything = new AtomicBoolean(false);
filteredChannels.removeIf(channel -> {
if (!Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.WHITELISTED_CHANNELS.getLines().contains(channel)) {
changedAnything.set(true);
return true;
}
return false;
});
if (changedAnything.get()) {
pluginMessage.setData(String.join("\u0000", filteredChannels).getBytes());
player.unsafe().sendPacket(pluginMessage);
return;
}
}
}
} else if (wrapper.packet instanceof Commands response) {
@@ -1,17 +1,16 @@
package de.rayzs.pat.plugin.packetanalyzer.proxy;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.packet.AvailableCommandsPacket;
import com.velocitypowered.proxy.protocol.packet.PluginMessagePacket;
import com.velocitypowered.proxy.protocol.packet.TabCompleteRequestPacket;
import com.velocitypowered.proxy.protocol.packet.TabCompleteResponsePacket;
import com.velocitypowered.proxy.protocol.packet.*;
import com.velocitypowered.proxy.protocol.packet.chat.session.UnsignedPlayerCommandPacket;
import de.rayzs.pat.plugin.system.serverbrand.CustomServerBrand;
@@ -32,6 +31,8 @@ import de.rayzs.pat.utils.message.MessageTranslator;
import de.rayzs.pat.utils.node.ProxyCommandNodeHelper;
import de.rayzs.pat.utils.permission.PermissionUtil;
import de.rayzs.pat.utils.sender.CommandSender;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
@@ -206,6 +207,18 @@ public class VelocityPacketAnalyzer {
return !playerCommands.contains(str);
});
if (Storage.ConfigSections.Settings.TAB_COMPLETION_FOR_NOT_EXISTING_COMMANDS.ENABLED) {
for (Group group : groups) {
for (String groupServerName : group.getBlacklistServerNames(serverName)) {
if (Storage.isServer(groupServerName, serverName)) {
for (String groupCommands : group.getAllCommands(groupServerName)) {
helper.add(groupCommands, true);
}
}
}
}
}
if (Storage.ConfigSections.Settings.CUSTOM_VERSION.ALWAYS_TAB_COMPLETABLE) {
Storage.ConfigSections.Settings.CUSTOM_VERSION.COMMANDS.getLines().forEach(input -> helper.add(input, false));
}
@@ -217,6 +230,37 @@ public class VelocityPacketAnalyzer {
SubArgument.get().getCommandNodeHandler().handleCommandNode(helper, SubArgument.get().getPlayerArgument(sender));
}
private static void handlePluginMessageChannelsPacket(final PluginMessagePacket packet) {
final String channelId = packet.getChannel();
if (Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.isRegisterChannel(channelId)) {
final ByteBuf buf = packet.content();
final byte[] data = new byte[buf.readableBytes()];
buf.getBytes(buf.readerIndex(), data);
final String dataStr = new String(data, StandardCharsets.UTF_8);
final String[] channels = dataStr.split("\u0000");
final List<String> filteredChannels = new ArrayList<>(Arrays.asList(channels));
final AtomicBoolean changedAnything = new AtomicBoolean(false);
filteredChannels.removeIf(channel -> {
if (!Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.WHITELISTED_CHANNELS.getLines().contains(channel)) {
changedAnything.set(true);
return true;
}
return false;
});
if (changedAnything.get()) {
final ByteBuf newBuf = Unpooled.wrappedBuffer(String.join("\u0000", filteredChannels).getBytes());
packet.replace(newBuf);
}
}
}
private static class PacketDecoder extends ChannelDuplexHandler {
private final Player player;
@@ -253,6 +297,10 @@ public class VelocityPacketAnalyzer {
}
}
if (packet instanceof PluginMessagePacket pluginMessagePacket && Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.ENABLED) {
handlePluginMessageChannelsPacket(pluginMessagePacket);
}
if (packet instanceof UnsignedPlayerCommandPacket unsignedPlayerCommandPacket) {
if (!VelocityBlockCommandListener.handleCommand(player, unsignedPlayerCommandPacket.getCommand()).getResult().isAllowed())
return;
@@ -282,11 +330,13 @@ public class VelocityPacketAnalyzer {
MinecraftPacket packet = (MinecraftPacket) msg;
if (packet instanceof PluginMessagePacket pluginMessagePacket) {
if(CustomServerBrand.get().isEnabled() && CustomServerBrand.get().isBrandTag(pluginMessagePacket.getChannel()) && !player.getCurrentServer().isPresent()) {
if (CustomServerBrand.get().isEnabled() && CustomServerBrand.get().isBrandTag(pluginMessagePacket.getChannel()) && !player.getCurrentServer().isPresent()) {
final PacketUtils.BrandManipulate brandManipulatePacket = CustomServerBrand.get().createBrandPacket(player);
super.write(ctx, new PluginMessagePacket(pluginMessagePacket.getChannel(), brandManipulatePacket.getByteBuf()), promise);
return;
} else if (Storage.ConfigSections.Settings.HIDE_PLUGIN_CHANNELS.ENABLED) {
handlePluginMessageChannelsPacket(pluginMessagePacket);
}
} else if (packet instanceof TabCompleteResponsePacket response) {
@@ -98,6 +98,8 @@ public class CommandNodeHandler extends SubArgumentHandler {
break;
}
if (input == null) continue;
final Storage.Blacklist.BlockType type = Storage.Blacklist.BlockTypeFetcher.getType(input);
if (type == Storage.Blacklist.BlockType.CHAT) {
continue;
@@ -1,6 +1,7 @@
package de.rayzs.pat.plugin.system.subargument.handler.impl;
import de.rayzs.pat.api.storage.Storage;
import de.rayzs.pat.plugin.logger.Logger;
import de.rayzs.pat.plugin.system.subargument.handler.SubArgumentHandler;
import de.rayzs.pat.plugin.system.subargument.SubArgument;
import de.rayzs.pat.utils.StringUtils;
@@ -67,6 +68,16 @@ public class ExecuteHandler extends SubArgumentHandler {
listed = !turn;
}
/*
final boolean blocked = turn != listed;
if (blocked && command.contains("discord")) {
Logger.info("Yes, sub-argument was blocked! (" + sender.getName() + ", " + command + ")");
Logger.info("-> " + turn + ", " + listed + ", " + negated);
}
return blocked;
*/
return turn != listed;
}
@@ -116,7 +116,7 @@ public class CommandsCache {
String command = filteredCommands.get(i);
localFilteredCommands.add(command);
} catch (IndexOutOfBoundsException indexOutOfBoundsException) {
Logger.warning("Array is out of bounds " + i + "/" + max + "! " + indexOutOfBoundsException.getMessage());
//Logger.warning("Array is out of bounds " + i + "/" + max + "! " + indexOutOfBoundsException.getMessage());
break;
}
}
@@ -6,21 +6,21 @@ import java.util.*;
public class MultipleMessagesHelper implements Serializable {
private final ArrayList<String> lines;
private final List<String> lines;
public MultipleMessagesHelper(ConfigStorage config, String path, List<String> input) {
ConfigSectionHelper<ArrayList<String>> sectionHelper = new ConfigSectionHelper<>(config, path, input);
final ConfigSectionHelper<ArrayList<String>> sectionHelper = new ConfigSectionHelper<>(config, path, input);
final Object resultObj = sectionHelper.getOrSet();
if(!sectionHelper.exist()) {
lines = new ArrayList<>(input);
sectionHelper.set(lines);
if (resultObj instanceof List list) {
lines = (List<String>) list;
return;
}
lines = sectionHelper.get();
lines = input;
}
public ArrayList<String> getLines() {
public List<String> getLines() {
return lines;
}
}
@@ -209,8 +209,9 @@ public class LuckPermsHook {
private static boolean isRelevantPermission(Node node) {
final String key = node.getKey();
return key.startsWith("group.")
return key.equals("*")
|| key.startsWith("group.")
|| key.startsWith("proantitab.")
|| key.equals("*");
|| key.startsWith("-proantitab.");
}
}
@@ -92,12 +92,29 @@ public class PermissionUtil {
}
public static void setPermission(UUID uuid, String permission, boolean permitted) {
PermissionMap permissionMap;
PermissionMap permissionMap = MAP.get(uuid);
if(!MAP.containsKey(uuid)) {
if(permissionMap == null) {
permissionMap = new PermissionMap(uuid);
MAP.put(uuid, permissionMap);
} else permissionMap = MAP.get(uuid);
}
final boolean isNegatedPermission = permission.charAt(0) == '-';
// Ignore because set permission is negated.
if (!isNegatedPermission && permissionMap.isPermitted("-" + permission)) {
return;
}
if (isNegatedPermission) {
final String nonNegatedPermission = permission.substring(1);
if (permissionMap.isPermitted(nonNegatedPermission)) {
permissionMap.setState(nonNegatedPermission, false);
return;
}
}
permissionMap.setState(permission, permitted);
}
@@ -169,7 +186,9 @@ public class PermissionUtil {
}
}
return permissionMap.isPermitted("*") || permissionMap.isPermitted("proantitab.*") || permissionMap.isPermitted("proantitab." + permission);
return permissionMap.isPermitted("*")
|| permissionMap.isPermitted("proantitab.*")
|| permissionMap.isPermitted("proantitab." + permission);
}
public static boolean hasBypassPermission(Object targetObj, final boolean isOperator) {
+1 -1
View File
@@ -3,7 +3,7 @@ description: Hides more than just your plugins.
website: https://www.rayzs.de/products/proantitab/page
author: Rayzs_YT
version: 2.4.3
version: 2.5.1
main: de.rayzs.pat.plugin.BungeeLoader
softDepends: [LuckPerms, PAPIProxyBridge]
@@ -101,6 +101,28 @@ update-groups-per-world: false
# of the player accordingly.
auto-forward-luckperms-changes: false
# This option here works as a whitelist and hides certain plugins channels
# from the user, if they are not supposed to be able to register for any
# of the non-mentioned plugin channels below. This prevents modern plugin
# spoofing attempts that are now trying to find plugins via their plugin
# channel.
#
# (!) Warning:
# Currently only works on standalone Spigot servers >=1.20
# and proxies like Bungeecord/Velocity. It's also not
# recommended to enable this feature, unless you know
# what plugin channels are and which may be needed
# for your server, in case your server supports a specific
# minecraft client that relies on plugin channels for identification!
plugin-channels-hider:
enabled: false
whitelisted-channels:
- "minecraft:brand"
- "bungeecord:main"
- "velocity:main"
# Here you can customize the server version that is displayed on a ping. (The text at the player-count)
# (!) Warning: It's required to use Paper or Purpur to use this feature!
# (!) Supported server versions: 1.12.2 - latest
+26
View File
@@ -64,11 +64,37 @@ allow-group-overruling: false
# lpv (...) permission set proantitab.group.<group> server=<server>
update-groups-per-server: false
# If you whitelist a command using PAT that does not exist, it would still
# make the command tab-completable, even though it doesn't exist.
# (!) WARNING: Only works with PAT groups!
tab-completion-for-not-existing-commands: false
# Enabling this forwards the notification message to the backend
# server so it will be displayed there as well. (Only in console)
forward-console-notification-alerts: false
# This option here works as a whitelist and hides certain plugins channels
# from the user, if they are not supposed to be able to register for any
# of the non-mentioned plugin channels below. This prevents modern plugin
# spoofing attempts that are now trying to find plugins via their plugin
# channel.
#
# (!) Warning:
# Currently only works on standalone Spigot servers >=1.20
# and proxies like Bungeecord/Velocity. It's also not
# recommended to enable this feature, unless you know
# what plugin channels are and which may be needed
# for your server, in case your server supports a specific
# minecraft client that relies on plugin channels for identification!
plugin-channels-hider:
enabled: false
whitelisted-channels:
- "minecraft:brand"
- "bungeecord:main"
- "velocity:main"
# Here you can customize the server version that is displayed on a ping. (The text at the player-count)
custom-protocol-ping:
enabled: true
+1 -1
View File
@@ -3,7 +3,7 @@ description: Hides more than just your plugins.
website: https://www.rayzs.de/products/proantitab/page
author: Rayzs_YT
version: 2.4.3
version: 2.5.1
api-version: 1.13
folia-supported: true
main: de.rayzs.pat.plugin.BukkitLoader