diff --git a/src/main/java/dev/plex/Plex.java b/src/main/java/dev/plex/Plex.java index cd19578..5c89409 100644 --- a/src/main/java/dev/plex/Plex.java +++ b/src/main/java/dev/plex/Plex.java @@ -44,6 +44,7 @@ public class Plex extends JavaPlugin public Config config; public Config messages; public Config indefBans; + public Config commands; public File modulesFolder; private StorageType storageType = StorageType.SQLITE; @@ -79,6 +80,7 @@ public class Plex extends JavaPlugin config = new Config(this, "config.yml"); messages = new Config(this, "messages.yml"); indefBans = new Config(this, "indefbans.yml"); + commands = new Config(this, "commands.yml"); build.load(this); modulesFolder = new File(this.getDataFolder() + File.separator + "modules"); @@ -99,6 +101,7 @@ public class Plex extends JavaPlugin messages.load(); // Don't add default entries to indefinite ban file indefBans.load(false); + commands.load(false); sqlConnection = new SQLConnection(); mongoConnection = new MongoConnection(); diff --git a/src/main/java/dev/plex/command/blocking/BlockedCommand.java b/src/main/java/dev/plex/command/blocking/BlockedCommand.java new file mode 100644 index 0000000..648d1af --- /dev/null +++ b/src/main/java/dev/plex/command/blocking/BlockedCommand.java @@ -0,0 +1,16 @@ +package dev.plex.command.blocking; + +import com.google.common.collect.Lists; +import lombok.Data; + +import java.util.List; + +@Data +public class BlockedCommand +{ + private String message; + private String requiredLevel; + private String regex; + private String command; + private List commandAliases = Lists.newArrayList(); +} diff --git a/src/main/java/dev/plex/listener/impl/CommandListener.java b/src/main/java/dev/plex/listener/impl/CommandListener.java index b393952..0897815 100644 --- a/src/main/java/dev/plex/listener/impl/CommandListener.java +++ b/src/main/java/dev/plex/listener/impl/CommandListener.java @@ -1,7 +1,17 @@ package dev.plex.listener.impl; +import com.google.gson.Gson; +import dev.plex.cache.DataUtils; import dev.plex.cache.player.PlayerCache; +import dev.plex.command.blocking.BlockedCommand; import dev.plex.listener.PlexListener; +import dev.plex.player.PlexPlayer; +import dev.plex.rank.enums.Rank; +import dev.plex.services.impl.CommandBlockerService; +import dev.plex.util.PlexLog; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.apache.commons.lang.StringUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.Player; @@ -9,6 +19,12 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import java.util.Arrays; +import java.util.Locale; +import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public class CommandListener extends PlexListener { @EventHandler(priority = EventPriority.HIGHEST) @@ -24,4 +40,80 @@ public class CommandListener extends PlexListener } }); } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onCommandBlocking(PlayerCommandPreprocessEvent event) + { + Player player = event.getPlayer(); + PlexPlayer plexPlayer = DataUtils.getPlayer(player.getUniqueId()); + String commandName = event.getMessage().split(" ")[0].replace("/", ""); + String arguments = StringUtils.normalizeSpace(event.getMessage().replace(event.getMessage().split(" ")[0], "")); + PlexLog.debug("Checking Command: {0} with args {1}", commandName, arguments); + AtomicReference cmdRef = new AtomicReference<>(); + CommandBlockerService.getBLOCKED_COMMANDS().stream().filter(blockedCommand -> blockedCommand.getCommand() != null).findFirst().ifPresent(blockedCommand -> + { + if (event.getMessage().replace("/", "").toLowerCase(Locale.ROOT).startsWith(blockedCommand.getCommand().toLowerCase(Locale.ROOT))) + { + PlexLog.debug("Used blocked command exactly matched"); + cmdRef.set(blockedCommand); + return; + } + if (blockedCommand.getCommandAliases().stream().anyMatch(s -> s.equalsIgnoreCase(commandName))) + { + PlexLog.debug("Found a command name in a blocked command alias, checking arguments now."); + String[] commandArgs = blockedCommand.getCommand().split(" "); + if (arguments.toLowerCase(Locale.ROOT).startsWith(StringUtils.join(commandArgs, " ", 1, commandArgs.length).toLowerCase(Locale.ROOT))) + { + PlexLog.debug("Player attempted to use a blocked command with an alias."); + cmdRef.set(blockedCommand); + return; + } + } + }); + if (cmdRef.get() == null) + { + CommandBlockerService.getBLOCKED_COMMANDS().forEach(blockedCommand -> + { + if (blockedCommand.getRegex() != null) + { + Pattern pattern = Pattern.compile(blockedCommand.getRegex()); + Matcher matcher = pattern.matcher(event.getMessage().replace("/", "")); + if (matcher.find()) + { + PlexLog.debug("Found blocked regexed command"); + cmdRef.set(blockedCommand); + } + } + }); + } + if (cmdRef.get() != null) + { + BlockedCommand cmd = cmdRef.get(); + if (cmd.getRequiredLevel().equalsIgnoreCase("e")) + { + event.setCancelled(true); + event.getPlayer().sendMessage(Component.text(cmd.getMessage()).color(NamedTextColor.GRAY)); + return; + } + if (cmd.getRequiredLevel().equalsIgnoreCase("a")) + { + if (plexPlayer.getRankFromString().isAtLeast(Rank.ADMIN) && plexPlayer.isAdminActive()) + { + event.setCancelled(true); + event.getPlayer().sendMessage(Component.text(cmd.getMessage()).color(NamedTextColor.GRAY)); + return; + } + } + if (cmd.getRequiredLevel().equalsIgnoreCase("s")) + { + if (plexPlayer.getRankFromString().isAtLeast(Rank.SENIOR_ADMIN) && plexPlayer.isAdminActive()) + { + event.setCancelled(true); + event.getPlayer().sendMessage(Component.text(cmd.getMessage()).color(NamedTextColor.GRAY)); + return; + } + } + } + + } } diff --git a/src/main/java/dev/plex/services/ServiceManager.java b/src/main/java/dev/plex/services/ServiceManager.java index 10e9b83..3aeddb8 100644 --- a/src/main/java/dev/plex/services/ServiceManager.java +++ b/src/main/java/dev/plex/services/ServiceManager.java @@ -2,10 +2,7 @@ package dev.plex.services; import com.google.common.collect.Lists; import dev.plex.Plex; -import dev.plex.services.impl.AutoWipeService; -import dev.plex.services.impl.BanService; -import dev.plex.services.impl.GameRuleService; -import dev.plex.services.impl.UpdateCheckerService; +import dev.plex.services.impl.*; import org.bukkit.Bukkit; import org.bukkit.scheduler.BukkitTask; @@ -21,6 +18,7 @@ public class ServiceManager registerService(new GameRuleService()); registerService(new UpdateCheckerService()); registerService(new AutoWipeService()); + registerService(new CommandBlockerService()); } public void startServices() diff --git a/src/main/java/dev/plex/services/impl/CommandBlockerService.java b/src/main/java/dev/plex/services/impl/CommandBlockerService.java new file mode 100644 index 0000000..60939b8 --- /dev/null +++ b/src/main/java/dev/plex/services/impl/CommandBlockerService.java @@ -0,0 +1,71 @@ +package dev.plex.services.impl; + +import com.google.common.collect.Lists; +import dev.plex.command.blocking.BlockedCommand; +import dev.plex.services.AbstractService; +import dev.plex.util.PlexLog; +import lombok.Getter; +import org.apache.commons.lang.StringUtils; +import org.bukkit.command.Command; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class CommandBlockerService extends AbstractService +{ + @Getter + private static final List BLOCKED_COMMANDS = Lists.newArrayList(); + + public CommandBlockerService() + { + super(false, false); + } + + @Override + public void run() + { + BLOCKED_COMMANDS.clear(); + PlexLog.debug("RUNNING COMMAND BLOCKING SERVICE"); + plugin.commands.getStringList("commands").forEach(s -> { + BlockedCommand command = new BlockedCommand(); + String[] args = s.split(";"); + if (s.toLowerCase(Locale.ROOT).startsWith("r")) + { + command.setRequiredLevel(args[1]); + command.setRegex(args[2]); + command.setMessage(StringUtils.join(args, ";", 3, args.length)); + PlexLog.debug("=Found regex blocked="); + PlexLog.debug(" Regex: " + command.getRegex()); + PlexLog.debug(" Message: " + command.getMessage()); + PlexLog.debug("===================="); + } else if (s.toLowerCase(Locale.ROOT).startsWith("m")) + { + command.setRequiredLevel(args[1]); + command.setCommand(args[2]); + command.setMessage(StringUtils.join(args, ";", 3, args.length)); + Command cmd = plugin.getServer().getCommandMap().getCommand(command.getCommand().split(" ")[0]); + if (cmd == null) + { + PlexLog.error("Command '{0}' specified in the configuration was null!", command.getCommand().split(" ")[0]); + return; + } + command.setCommandAliases(cmd.getAliases()); + command.getCommandAliases().add(command.getCommand().split(" ")[0]); + PlexLog.debug("=Found command blocked="); + PlexLog.debug(" Required Level: " + command.getRequiredLevel()); + PlexLog.debug(" Command: " + command.getCommand()); + PlexLog.debug(" Message: " + command.getMessage()); + PlexLog.debug(" Aliases: " + Arrays.toString(command.getCommandAliases().toArray(new String[0]))); + PlexLog.debug("===================="); + } + BLOCKED_COMMANDS.add(command); + }); + } + + @Override + public int repeatInSeconds() + { + return 0; + } +} diff --git a/src/main/resources/commands.yml b/src/main/resources/commands.yml new file mode 100644 index 0000000..a46fd26 --- /dev/null +++ b/src/main/resources/commands.yml @@ -0,0 +1,20 @@ +# Plex Command Blocking File +# For documentation, please visit: https://plex.us.org + +# Format: +# - "::command name no slash:Block message" +# +# Symbols to use: +# - r for RegEx +# - m for matching +# - The ranks are "e" for everyone, "a" for admin and "s" for senior admin +# - The command is just the command without slashes. Optional arguments are specified as well +# - Finally the block message. MUST NOT CONTAIN ":". Use _ to use the default command blocked message as specified in messages.yml, or you can optionally put your own in +# +# So these would be valid: +# - "m:e:mail sendall:You cannot send messages to everyone on the server" +# - "r:e:(.*:):Plugin specific commands are disabled" + +commands: # Regexes and commands can't contain ';'. Don't try, commands can't contain ';' by default. + - "r;(^\w+:);"Plugin specific commands are disabled + - 'm;e;mail sendall;You cannot send messages to everyone on the server' \ No newline at end of file