From 94e7e11183c54039a7027c17390200edaa41d389 Mon Sep 17 00:00:00 2001 From: lucko Date: Sat, 10 May 2025 14:32:47 +0100 Subject: [PATCH] Add configurable read-only mode for commands (#4031) --- bukkit/src/main/resources/config.yml | 30 ++ bungee/src/main/resources/config.yml | 30 ++ .../common/command/CommandManager.java | 17 ++ .../command/access/CommandPermission.java | 268 +++++++++--------- .../luckperms/common/config/ConfigKeys.java | 20 ++ .../luckperms/common/locale/Message.java | 7 + .../plugin/AbstractLuckPermsPlugin.java | 11 +- .../common/sender/AbstractSender.java | 16 ++ .../common/sender/DummyConsoleSender.java | 12 + .../lucko/luckperms/common/sender/Sender.java | 4 +- .../main/resources/luckperms_en.properties | 1 + .../command/access/CommandPermissionTest.java | 83 ++++++ .../luckperms/fabric/LPFabricPlugin.java | 6 +- fabric/src/main/resources/luckperms.conf | 32 +++ .../lucko/luckperms/forge/LPForgePlugin.java | 6 +- forge/src/main/resources/luckperms.conf | 32 +++ .../luckperms/neoforge/LPNeoForgePlugin.java | 6 +- neoforge/src/main/resources/luckperms.conf | 32 +++ nukkit/src/main/resources/config.yml | 30 ++ sponge/src/main/resources/luckperms.conf | 32 +++ standalone/src/main/resources/config.yml | 30 ++ .../standalone/CommandsIntegrationTest.java | 38 +++ .../standalone/utils/CommandTester.java | 13 +- velocity/src/main/resources/config.yml | 30 ++ 24 files changed, 644 insertions(+), 142 deletions(-) create mode 100644 common/src/test/java/me/lucko/luckperms/common/command/access/CommandPermissionTest.java diff --git a/bukkit/src/main/resources/config.yml b/bukkit/src/main/resources/config.yml index e616b04ab..8080ba260 100644 --- a/bukkit/src/main/resources/config.yml +++ b/bukkit/src/main/resources/config.yml @@ -719,3 +719,33 @@ register-command-list-data: true # If LuckPerms should attempt to resolve Vanilla command target selectors for LP commands. # See here for more info: https://minecraft.wiki/w/Target_selectors resolve-command-selectors: false + +# If the plugin should run in "read-only" mode for commands. +# +# In this mode, players or the console will only be able to execute commands that read or view +# data, and will not be able to execute any LP commands that modify data. +# +# If enabling read-only mode for just players, be aware that some other plugins may allow players +# to execute commands as the console, allowing them to run LP commands indirectly. +# +# Note: This does not affect interactions with LuckPerms via the API. +commands-read-only-mode: + players: false + console: false + +# If LuckPerms commands should be disabled. When true, this will prevent all LP commands from being +# executed. In a sense this is a more extreme version of read-only mode (see above). +# +# LuckPerms will still act as the permission manager, but server administrators will be unable to +# make changes via commands. +# +# If disabling commands just for players, be aware that some other plugins may allow players to +# execute commands as the console, allowing them to run commands indirectly. +# +# If commands are disabled for both players and the console, LuckPerms will not attempt to register +# a command with the server at all & in a sense will be invisible to both players and admins. +# +# Note: This does not affect interactions with LuckPerms via the API. +disable-luckperms-commands: + players: false + console: false diff --git a/bungee/src/main/resources/config.yml b/bungee/src/main/resources/config.yml index be3313f0c..a1ee2f959 100644 --- a/bungee/src/main/resources/config.yml +++ b/bungee/src/main/resources/config.yml @@ -611,3 +611,33 @@ disable-bulkupdate: false # # - When this happens, the plugin will set their primary group back to default. prevent-primary-group-removal: false + +# If the plugin should run in "read-only" mode for commands. +# +# In this mode, players or the console will only be able to execute commands that read or view +# data, and will not be able to execute any LP commands that modify data. +# +# If enabling read-only mode for just players, be aware that some other plugins may allow players +# to execute commands as the console, allowing them to run LP commands indirectly. +# +# Note: This does not affect interactions with LuckPerms via the API. +commands-read-only-mode: + players: false + console: false + +# If LuckPerms commands should be disabled. When true, this will prevent all LP commands from being +# executed. In a sense this is a more extreme version of read-only mode (see above). +# +# LuckPerms will still act as the permission manager, but server administrators will be unable to +# make changes via commands. +# +# If disabling commands just for players, be aware that some other plugins may allow players to +# execute commands as the console, allowing them to run commands indirectly. +# +# If commands are disabled for both players and the console, LuckPerms will not attempt to register +# a command with the server at all & in a sense will be invisible to both players and admins. +# +# Note: This does not affect interactions with LuckPerms via the API. +disable-luckperms-commands: + players: false + console: false diff --git a/common/src/main/java/me/lucko/luckperms/common/command/CommandManager.java b/common/src/main/java/me/lucko/luckperms/common/command/CommandManager.java index 6fd381183..a0831bfd1 100644 --- a/common/src/main/java/me/lucko/luckperms/common/command/CommandManager.java +++ b/common/src/main/java/me/lucko/luckperms/common/command/CommandManager.java @@ -160,6 +160,15 @@ public class CommandManager { return CompletableFuture.completedFuture(null); } + boolean commandsDisabled = sender.isConsole() + ? this.plugin.getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_CONSOLE) + : this.plugin.getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_PLAYERS); + + if (commandsDisabled) { + Message.COMMANDS_DISABLED.send(sender); + return CompletableFuture.completedFuture(null); + } + SchedulerAdapter scheduler = this.plugin.getBootstrap().getScheduler(); List argsCopy = new ArrayList<>(args); @@ -286,6 +295,14 @@ public class CommandManager { } public List tabCompleteCommand(Sender sender, List arguments) { + boolean commandsDisabled = sender.isConsole() + ? this.plugin.getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_CONSOLE) + : this.plugin.getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_PLAYERS); + + if (commandsDisabled) { + return Collections.emptyList(); + } + applyConvenienceAliases(arguments, false); final List> mains = this.mainCommands.values().stream() diff --git a/common/src/main/java/me/lucko/luckperms/common/command/access/CommandPermission.java b/common/src/main/java/me/lucko/luckperms/common/command/access/CommandPermission.java index ed1ed15e3..fd1c1f91b 100644 --- a/common/src/main/java/me/lucko/luckperms/common/command/access/CommandPermission.java +++ b/common/src/main/java/me/lucko/luckperms/common/command/access/CommandPermission.java @@ -32,143 +32,143 @@ import me.lucko.luckperms.common.sender.Sender; */ public enum CommandPermission { - SYNC("sync", Type.NONE), - INFO("info", Type.NONE), - EDITOR("editor", Type.NONE), - VERBOSE("verbose", Type.NONE), - VERBOSE_COMMAND_OTHERS("verbose.command.others", Type.NONE), - TREE("tree", Type.NONE), - SEARCH("search", Type.NONE), - IMPORT("import", Type.NONE), - EXPORT("export", Type.NONE), - RELOAD_CONFIG("reloadconfig", Type.NONE), - BULK_UPDATE("bulkupdate", Type.NONE), - APPLY_EDITS("applyedits", Type.NONE), - TRUST_EDITOR("trusteditor", Type.NONE), - TRANSLATIONS("translations", Type.NONE), + SYNC("sync", Type.NONE, true), + INFO("info", Type.NONE, true), + EDITOR("editor", Type.NONE, true), + VERBOSE("verbose", Type.NONE, true), + VERBOSE_COMMAND_OTHERS("verbose.command.others", Type.NONE, false), + TREE("tree", Type.NONE, true), + SEARCH("search", Type.NONE, true), + IMPORT("import", Type.NONE, false), + EXPORT("export", Type.NONE, true), + RELOAD_CONFIG("reloadconfig", Type.NONE, true), + BULK_UPDATE("bulkupdate", Type.NONE, false), + APPLY_EDITS("applyedits", Type.NONE, false), + TRUST_EDITOR("trusteditor", Type.NONE, false), + TRANSLATIONS("translations", Type.NONE, true), - CREATE_GROUP("creategroup", Type.NONE), - DELETE_GROUP("deletegroup", Type.NONE), - LIST_GROUPS("listgroups", Type.NONE), + CREATE_GROUP("creategroup", Type.NONE, false), + DELETE_GROUP("deletegroup", Type.NONE, false), + LIST_GROUPS("listgroups", Type.NONE, true), - CREATE_TRACK("createtrack", Type.NONE), - DELETE_TRACK("deletetrack", Type.NONE), - LIST_TRACKS("listtracks", Type.NONE), + CREATE_TRACK("createtrack", Type.NONE, false), + DELETE_TRACK("deletetrack", Type.NONE, false), + LIST_TRACKS("listtracks", Type.NONE, true), - USER_INFO("info", Type.USER), - USER_PERM_INFO("permission.info", Type.USER), - USER_PERM_SET("permission.set", Type.USER), - USER_PERM_UNSET("permission.unset", Type.USER), - USER_PERM_SET_TEMP("permission.settemp", Type.USER), - USER_PERM_UNSET_TEMP("permission.unsettemp", Type.USER), - USER_PERM_CHECK("permission.check", Type.USER), - USER_PERM_CLEAR("permission.clear", Type.USER), - USER_PARENT_INFO("parent.info", Type.USER), - USER_PARENT_SET("parent.set", Type.USER), - USER_PARENT_SET_TRACK("parent.settrack", Type.USER), - USER_PARENT_ADD("parent.add", Type.USER), - USER_PARENT_REMOVE("parent.remove", Type.USER), - USER_PARENT_ADD_TEMP("parent.addtemp", Type.USER), - USER_PARENT_REMOVE_TEMP("parent.removetemp", Type.USER), - USER_PARENT_CLEAR("parent.clear", Type.USER), - USER_PARENT_CLEAR_TRACK("parent.cleartrack", Type.USER), - USER_PARENT_SWITCHPRIMARYGROUP("parent.switchprimarygroup", Type.USER), - USER_META_INFO("meta.info", Type.USER), - USER_META_SET("meta.set", Type.USER), - USER_META_UNSET("meta.unset", Type.USER), - USER_META_SET_TEMP("meta.settemp", Type.USER), - USER_META_UNSET_TEMP("meta.unsettemp", Type.USER), - USER_META_ADD_PREFIX("meta.addprefix", Type.USER), - USER_META_ADD_SUFFIX("meta.addsuffix", Type.USER), - USER_META_SET_PREFIX("meta.setprefix", Type.USER), - USER_META_SET_SUFFIX("meta.setsuffix", Type.USER), - USER_META_REMOVE_PREFIX("meta.removeprefix", Type.USER), - USER_META_REMOVE_SUFFIX("meta.removesuffix", Type.USER), - USER_META_ADD_TEMP_PREFIX("meta.addtempprefix", Type.USER), - USER_META_ADD_TEMP_SUFFIX("meta.addtempsuffix", Type.USER), - USER_META_SET_TEMP_PREFIX("meta.settempprefix", Type.USER), - USER_META_SET_TEMP_SUFFIX("meta.settempsuffix", Type.USER), - USER_META_REMOVE_TEMP_PREFIX("meta.removetempprefix", Type.USER), - USER_META_REMOVE_TEMP_SUFFIX("meta.removetempsuffix", Type.USER), - USER_META_CLEAR("meta.clear", Type.USER), - USER_EDITOR("editor", Type.USER), - USER_SHOW_TRACKS("showtracks", Type.USER), - USER_PROMOTE("promote", Type.USER), - USER_DEMOTE("demote", Type.USER), - USER_CLEAR("clear", Type.USER), - USER_CLONE("clone", Type.USER), + USER_INFO("info", Type.USER, true), + USER_PERM_INFO("permission.info", Type.USER, true), + USER_PERM_SET("permission.set", Type.USER, false), + USER_PERM_UNSET("permission.unset", Type.USER, false), + USER_PERM_SET_TEMP("permission.settemp", Type.USER, false), + USER_PERM_UNSET_TEMP("permission.unsettemp", Type.USER, false), + USER_PERM_CHECK("permission.check", Type.USER, true), + USER_PERM_CLEAR("permission.clear", Type.USER, false), + USER_PARENT_INFO("parent.info", Type.USER, true), + USER_PARENT_SET("parent.set", Type.USER, false), + USER_PARENT_SET_TRACK("parent.settrack", Type.USER, false), + USER_PARENT_ADD("parent.add", Type.USER, false), + USER_PARENT_REMOVE("parent.remove", Type.USER, false), + USER_PARENT_ADD_TEMP("parent.addtemp", Type.USER, false), + USER_PARENT_REMOVE_TEMP("parent.removetemp", Type.USER, false), + USER_PARENT_CLEAR("parent.clear", Type.USER, false), + USER_PARENT_CLEAR_TRACK("parent.cleartrack", Type.USER, false), + USER_PARENT_SWITCHPRIMARYGROUP("parent.switchprimarygroup", Type.USER, false), + USER_META_INFO("meta.info", Type.USER, true), + USER_META_SET("meta.set", Type.USER, false), + USER_META_UNSET("meta.unset", Type.USER, false), + USER_META_SET_TEMP("meta.settemp", Type.USER, false), + USER_META_UNSET_TEMP("meta.unsettemp", Type.USER, false), + USER_META_ADD_PREFIX("meta.addprefix", Type.USER, false), + USER_META_ADD_SUFFIX("meta.addsuffix", Type.USER, false), + USER_META_SET_PREFIX("meta.setprefix", Type.USER, false), + USER_META_SET_SUFFIX("meta.setsuffix", Type.USER, false), + USER_META_REMOVE_PREFIX("meta.removeprefix", Type.USER, false), + USER_META_REMOVE_SUFFIX("meta.removesuffix", Type.USER, false), + USER_META_ADD_TEMP_PREFIX("meta.addtempprefix", Type.USER, false), + USER_META_ADD_TEMP_SUFFIX("meta.addtempsuffix", Type.USER, false), + USER_META_SET_TEMP_PREFIX("meta.settempprefix", Type.USER, false), + USER_META_SET_TEMP_SUFFIX("meta.settempsuffix", Type.USER, false), + USER_META_REMOVE_TEMP_PREFIX("meta.removetempprefix", Type.USER, false), + USER_META_REMOVE_TEMP_SUFFIX("meta.removetempsuffix", Type.USER, false), + USER_META_CLEAR("meta.clear", Type.USER, false), + USER_EDITOR("editor", Type.USER, true), + USER_SHOW_TRACKS("showtracks", Type.USER, true), + USER_PROMOTE("promote", Type.USER, false), + USER_DEMOTE("demote", Type.USER, false), + USER_CLEAR("clear", Type.USER, false), + USER_CLONE("clone", Type.USER, false), - GROUP_INFO("info", Type.GROUP), - GROUP_PERM_INFO("permission.info", Type.GROUP), - GROUP_PERM_SET("permission.set", Type.GROUP), - GROUP_PERM_UNSET("permission.unset", Type.GROUP), - GROUP_PERM_SET_TEMP("permission.settemp", Type.GROUP), - GROUP_PERM_UNSET_TEMP("permission.unsettemp", Type.GROUP), - GROUP_PERM_CHECK("permission.check", Type.GROUP), - GROUP_PERM_CLEAR("permission.clear", Type.GROUP), - GROUP_PARENT_INFO("parent.info", Type.GROUP), - GROUP_PARENT_SET("parent.set", Type.GROUP), - GROUP_PARENT_SET_TRACK("parent.settrack", Type.GROUP), - GROUP_PARENT_ADD("parent.add", Type.GROUP), - GROUP_PARENT_REMOVE("parent.remove", Type.GROUP), - GROUP_PARENT_ADD_TEMP("parent.addtemp", Type.GROUP), - GROUP_PARENT_REMOVE_TEMP("parent.removetemp", Type.GROUP), - GROUP_PARENT_CLEAR("parent.clear", Type.GROUP), - GROUP_PARENT_CLEAR_TRACK("parent.cleartrack", Type.GROUP), - GROUP_META_INFO("meta.info", Type.GROUP), - GROUP_META_SET("meta.set", Type.GROUP), - GROUP_META_UNSET("meta.unset", Type.GROUP), - GROUP_META_SET_TEMP("meta.settemp", Type.GROUP), - GROUP_META_UNSET_TEMP("meta.unsettemp", Type.GROUP), - GROUP_META_ADD_PREFIX("meta.addprefix", Type.GROUP), - GROUP_META_ADD_SUFFIX("meta.addsuffix", Type.GROUP), - GROUP_META_SET_PREFIX("meta.setprefix", Type.GROUP), - GROUP_META_SET_SUFFIX("meta.setsuffix", Type.GROUP), - GROUP_META_REMOVE_PREFIX("meta.removeprefix", Type.GROUP), - GROUP_META_REMOVE_SUFFIX("meta.removesuffix", Type.GROUP), - GROUP_META_ADD_TEMP_PREFIX("meta.addtempprefix", Type.GROUP), - GROUP_META_ADD_TEMP_SUFFIX("meta.addtempsuffix", Type.GROUP), - GROUP_META_SET_TEMP_PREFIX("meta.settempprefix", Type.GROUP), - GROUP_META_SET_TEMP_SUFFIX("meta.settempsuffix", Type.GROUP), - GROUP_META_REMOVE_TEMP_PREFIX("meta.removetempprefix", Type.GROUP), - GROUP_META_REMOVE_TEMP_SUFFIX("meta.removetempsuffix", Type.GROUP), - GROUP_META_CLEAR("meta.clear", Type.GROUP), - GROUP_EDITOR("editor", Type.GROUP), - GROUP_LIST_MEMBERS("listmembers", Type.GROUP), - GROUP_SHOW_TRACKS("showtracks", Type.GROUP), - GROUP_SET_WEIGHT("setweight", Type.GROUP), - GROUP_SET_DISPLAY_NAME("setdisplayname", Type.GROUP), - GROUP_CLEAR("clear", Type.GROUP), - GROUP_RENAME("rename", Type.GROUP), - GROUP_CLONE("clone", Type.GROUP), + GROUP_INFO("info", Type.GROUP, true), + GROUP_PERM_INFO("permission.info", Type.GROUP, true), + GROUP_PERM_SET("permission.set", Type.GROUP, false), + GROUP_PERM_UNSET("permission.unset", Type.GROUP, false), + GROUP_PERM_SET_TEMP("permission.settemp", Type.GROUP, false), + GROUP_PERM_UNSET_TEMP("permission.unsettemp", Type.GROUP, false), + GROUP_PERM_CHECK("permission.check", Type.GROUP, true), + GROUP_PERM_CLEAR("permission.clear", Type.GROUP, false), + GROUP_PARENT_INFO("parent.info", Type.GROUP, true), + GROUP_PARENT_SET("parent.set", Type.GROUP, false), + GROUP_PARENT_SET_TRACK("parent.settrack", Type.GROUP, false), + GROUP_PARENT_ADD("parent.add", Type.GROUP, false), + GROUP_PARENT_REMOVE("parent.remove", Type.GROUP, false), + GROUP_PARENT_ADD_TEMP("parent.addtemp", Type.GROUP, false), + GROUP_PARENT_REMOVE_TEMP("parent.removetemp", Type.GROUP, false), + GROUP_PARENT_CLEAR("parent.clear", Type.GROUP, false), + GROUP_PARENT_CLEAR_TRACK("parent.cleartrack", Type.GROUP, false), + GROUP_META_INFO("meta.info", Type.GROUP, true), + GROUP_META_SET("meta.set", Type.GROUP, false), + GROUP_META_UNSET("meta.unset", Type.GROUP, false), + GROUP_META_SET_TEMP("meta.settemp", Type.GROUP, false), + GROUP_META_UNSET_TEMP("meta.unsettemp", Type.GROUP, false), + GROUP_META_ADD_PREFIX("meta.addprefix", Type.GROUP, false), + GROUP_META_ADD_SUFFIX("meta.addsuffix", Type.GROUP, false), + GROUP_META_SET_PREFIX("meta.setprefix", Type.GROUP, false), + GROUP_META_SET_SUFFIX("meta.setsuffix", Type.GROUP, false), + GROUP_META_REMOVE_PREFIX("meta.removeprefix", Type.GROUP, false), + GROUP_META_REMOVE_SUFFIX("meta.removesuffix", Type.GROUP, false), + GROUP_META_ADD_TEMP_PREFIX("meta.addtempprefix", Type.GROUP, false), + GROUP_META_ADD_TEMP_SUFFIX("meta.addtempsuffix", Type.GROUP, false), + GROUP_META_SET_TEMP_PREFIX("meta.settempprefix", Type.GROUP, false), + GROUP_META_SET_TEMP_SUFFIX("meta.settempsuffix", Type.GROUP, false), + GROUP_META_REMOVE_TEMP_PREFIX("meta.removetempprefix", Type.GROUP, false), + GROUP_META_REMOVE_TEMP_SUFFIX("meta.removetempsuffix", Type.GROUP, false), + GROUP_META_CLEAR("meta.clear", Type.GROUP, false), + GROUP_EDITOR("editor", Type.GROUP, true), + GROUP_LIST_MEMBERS("listmembers", Type.GROUP, true), + GROUP_SHOW_TRACKS("showtracks", Type.GROUP, true), + GROUP_SET_WEIGHT("setweight", Type.GROUP, false), + GROUP_SET_DISPLAY_NAME("setdisplayname", Type.GROUP, false), + GROUP_CLEAR("clear", Type.GROUP, false), + GROUP_RENAME("rename", Type.GROUP, false), + GROUP_CLONE("clone", Type.GROUP, false), - TRACK_INFO("info", Type.TRACK), - TRACK_EDITOR("editor", Type.TRACK), - TRACK_APPEND("append", Type.TRACK), - TRACK_INSERT("insert", Type.TRACK), - TRACK_REMOVE("remove", Type.TRACK), - TRACK_CLEAR("clear", Type.TRACK), - TRACK_RENAME("rename", Type.TRACK), - TRACK_CLONE("clone", Type.TRACK), + TRACK_INFO("info", Type.TRACK, true), + TRACK_EDITOR("editor", Type.TRACK, true), + TRACK_APPEND("append", Type.TRACK, false), + TRACK_INSERT("insert", Type.TRACK, false), + TRACK_REMOVE("remove", Type.TRACK, false), + TRACK_CLEAR("clear", Type.TRACK, false), + TRACK_RENAME("rename", Type.TRACK, false), + TRACK_CLONE("clone", Type.TRACK, false), - LOG_RECENT("recent", Type.LOG), - LOG_USER_HISTORY("userhistory", Type.LOG), - LOG_GROUP_HISTORY("grouphistory", Type.LOG), - LOG_TRACK_HISTORY("trackhistory", Type.LOG), - LOG_SEARCH("search", Type.LOG), - LOG_NOTIFY("notify", Type.LOG), + LOG_RECENT("recent", Type.LOG, true), + LOG_USER_HISTORY("userhistory", Type.LOG, true), + LOG_GROUP_HISTORY("grouphistory", Type.LOG, true), + LOG_TRACK_HISTORY("trackhistory", Type.LOG, true), + LOG_SEARCH("search", Type.LOG, true), + LOG_NOTIFY("notify", Type.LOG, true), - SPONGE_PERMISSION_INFO("permission.info", Type.SPONGE), - SPONGE_PERMISSION_SET("permission.set", Type.SPONGE), - SPONGE_PERMISSION_CLEAR("permission.clear", Type.SPONGE), - SPONGE_PARENT_INFO("parent.info", Type.SPONGE), - SPONGE_PARENT_ADD("parent.add", Type.SPONGE), - SPONGE_PARENT_REMOVE("parent.remove", Type.SPONGE), - SPONGE_PARENT_CLEAR("parent.clear", Type.SPONGE), - SPONGE_OPTION_INFO("option.info", Type.SPONGE), - SPONGE_OPTION_SET("option.set", Type.SPONGE), - SPONGE_OPTION_UNSET("option.unset", Type.SPONGE), - SPONGE_OPTION_CLEAR("option.clear", Type.SPONGE); + SPONGE_PERMISSION_INFO("permission.info", Type.SPONGE, true), + SPONGE_PERMISSION_SET("permission.set", Type.SPONGE, false), + SPONGE_PERMISSION_CLEAR("permission.clear", Type.SPONGE, false), + SPONGE_PARENT_INFO("parent.info", Type.SPONGE, true), + SPONGE_PARENT_ADD("parent.add", Type.SPONGE, false), + SPONGE_PARENT_REMOVE("parent.remove", Type.SPONGE, false), + SPONGE_PARENT_CLEAR("parent.clear", Type.SPONGE, false), + SPONGE_OPTION_INFO("option.info", Type.SPONGE, true), + SPONGE_OPTION_SET("option.set", Type.SPONGE, false), + SPONGE_OPTION_UNSET("option.unset", Type.SPONGE, false), + SPONGE_OPTION_CLEAR("option.clear", Type.SPONGE, false); public static final String ROOT = "luckperms."; @@ -176,9 +176,11 @@ public enum CommandPermission { private final String permission; private final Type type; + private final boolean readOnly; - CommandPermission(String node, Type type) { + CommandPermission(String node, Type type, boolean readOnly) { this.type = type; + this.readOnly = readOnly; if (type == Type.NONE) { this.node = node; @@ -205,6 +207,10 @@ public enum CommandPermission { return this.type; } + public boolean isReadOnly() { + return this.readOnly; + } + public enum Type { NONE(null), diff --git a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java index 3a394545b..5df036256 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java @@ -246,6 +246,26 @@ public final class ConfigKeys { */ public static final ConfigKey REQUIRE_SENDER_GROUP_MEMBERSHIP_TO_MODIFY = booleanKey("require-sender-group-membership-to-modify", false); + /** + * If the plugin is in read-only mode for players + */ + public static final ConfigKey READ_ONLY_MODE_PLAYERS = booleanKey("commands-read-only-mode.players", false); + + /** + * If the plugin is in read-only mode for the server console + */ + public static final ConfigKey READ_ONLY_MODE_CONSOLE = booleanKey("commands-read-only-mode.console", false); + + /** + * If LuckPerms commands are disabled for players + */ + public static final ConfigKey DISABLE_LUCKPERMS_COMMANDS_PLAYERS = booleanKey("disable-luckperms-commands.players", false); + + /** + * If LuckPerms commands are disabled for the server console + */ + public static final ConfigKey DISABLE_LUCKPERMS_COMMANDS_CONSOLE = booleanKey("disable-luckperms-commands.console", false); + /** * If wildcards are being applied */ diff --git a/common/src/main/java/me/lucko/luckperms/common/locale/Message.java b/common/src/main/java/me/lucko/luckperms/common/locale/Message.java index bd527b793..b56d95128 100644 --- a/common/src/main/java/me/lucko/luckperms/common/locale/Message.java +++ b/common/src/main/java/me/lucko/luckperms/common/locale/Message.java @@ -179,6 +179,13 @@ public interface Message { .color(GRAY) ); + Args0 COMMANDS_DISABLED = () -> prefixed(translatable() + // "&3LuckPerms commands are disabled." + .key("luckperms.commandsystem.commands-disabled") + .color(DARK_AQUA) + .append(FULL_STOP) + ); + Args2 FIRST_TIME_SETUP = (label, username) -> joinNewline( // "&3It seems that no permissions have been setup yet!" // "&3Before you can use any of the LuckPerms commands in-game, you need to use the console to give yourself access." diff --git a/common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java index 1e5d747ef..ba6b25428 100644 --- a/common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java +++ b/common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java @@ -208,7 +208,11 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin { this.syncTaskBuffer = new SyncTask.Buffer(this); // register commands - registerCommands(); + if (skipCommandRegistration()) { + getLogger().warn("LuckPerms commands are disabled in the configuration for both console and players. Skipping command registration."); + } else { + registerCommands(); + } // load internal managers getLogger().info("Loading internal permission managers..."); @@ -388,6 +392,11 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin { return configFile; } + protected boolean skipCommandRegistration() { + return getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_CONSOLE) && + getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_PLAYERS); + } + @Override public PluginLogger getLogger() { return getBootstrap().getPluginLogger(); diff --git a/common/src/main/java/me/lucko/luckperms/common/sender/AbstractSender.java b/common/src/main/java/me/lucko/luckperms/common/sender/AbstractSender.java index 01eb96988..5f6d135ad 100644 --- a/common/src/main/java/me/lucko/luckperms/common/sender/AbstractSender.java +++ b/common/src/main/java/me/lucko/luckperms/common/sender/AbstractSender.java @@ -26,6 +26,9 @@ package me.lucko.luckperms.common.sender; import com.google.common.collect.Iterables; +import me.lucko.luckperms.common.command.access.CommandPermission; +import me.lucko.luckperms.common.config.ConfigKeys; +import me.lucko.luckperms.common.config.generic.key.ConfigKey; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.JoinConfiguration; @@ -98,6 +101,19 @@ public final class AbstractSender implements Sender { return isConsole() || this.factory.hasPermission(this.sender, permission); } + @Override + public boolean hasPermission(CommandPermission permission) { + boolean readOnlyMode = isConsole() + ? this.plugin.getConfiguration().get(ConfigKeys.READ_ONLY_MODE_CONSOLE) + : this.plugin.getConfiguration().get(ConfigKeys.READ_ONLY_MODE_PLAYERS); + + if (readOnlyMode && !permission.isReadOnly()) { + return false; + } + + return hasPermission(permission.getPermission()); + } + @Override public void performCommand(String commandLine) { this.factory.performCommand(this.sender, commandLine); diff --git a/common/src/main/java/me/lucko/luckperms/common/sender/DummyConsoleSender.java b/common/src/main/java/me/lucko/luckperms/common/sender/DummyConsoleSender.java index 76c9af57e..93d2498f4 100644 --- a/common/src/main/java/me/lucko/luckperms/common/sender/DummyConsoleSender.java +++ b/common/src/main/java/me/lucko/luckperms/common/sender/DummyConsoleSender.java @@ -25,6 +25,8 @@ package me.lucko.luckperms.common.sender; +import me.lucko.luckperms.common.command.access.CommandPermission; +import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import net.luckperms.api.util.Tristate; @@ -47,6 +49,16 @@ public abstract class DummyConsoleSender implements Sender { return true; } + @Override + public boolean hasPermission(CommandPermission permission) { + boolean readOnlyMode = this.platform.getConfiguration().get(ConfigKeys.READ_ONLY_MODE_CONSOLE); + if (readOnlyMode && !permission.isReadOnly()) { + return false; + } + + return true; + } + @Override public void performCommand(String commandLine) { diff --git a/common/src/main/java/me/lucko/luckperms/common/sender/Sender.java b/common/src/main/java/me/lucko/luckperms/common/sender/Sender.java index 03073647b..9aa77f557 100644 --- a/common/src/main/java/me/lucko/luckperms/common/sender/Sender.java +++ b/common/src/main/java/me/lucko/luckperms/common/sender/Sender.java @@ -132,9 +132,7 @@ public interface Sender { * @param permission the permission to check for * @return true if the sender has the permission */ - default boolean hasPermission(CommandPermission permission) { - return hasPermission(permission.getPermission()); - } + boolean hasPermission(CommandPermission permission); /** * Makes the sender perform a command. diff --git a/common/src/main/resources/luckperms_en.properties b/common/src/main/resources/luckperms_en.properties index 9239b6045..33cfa7d13 100644 --- a/common/src/main/resources/luckperms_en.properties +++ b/common/src/main/resources/luckperms_en.properties @@ -14,6 +14,7 @@ luckperms.commandsystem.command-not-recognised=Command not recognised luckperms.commandsystem.no-permission=You do not have permission to use this command! luckperms.commandsystem.no-permission-subcommands=You do not have permission to use any sub commands luckperms.commandsystem.already-executing-command=Another command is being executed, waiting for it to finish... +luckperms.commandsystem.commands-disabled=LuckPerms commands are disabled luckperms.commandsystem.usage.sub-commands-header=Sub Commands luckperms.commandsystem.usage.usage-header=Command Usage luckperms.commandsystem.usage.arguments-header=Arguments diff --git a/common/src/test/java/me/lucko/luckperms/common/command/access/CommandPermissionTest.java b/common/src/test/java/me/lucko/luckperms/common/command/access/CommandPermissionTest.java new file mode 100644 index 000000000..b19f6f066 --- /dev/null +++ b/common/src/test/java/me/lucko/luckperms/common/command/access/CommandPermissionTest.java @@ -0,0 +1,83 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.command.access; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.testcontainers.shaded.com.google.common.collect.ImmutableSet; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CommandPermissionTest { + + private static final ImmutableSet ALLOWED_READ_ONLY = ImmutableSet.of( + CommandPermission.SYNC, + CommandPermission.INFO, + CommandPermission.EDITOR, + CommandPermission.VERBOSE, + CommandPermission.TREE, + CommandPermission.SEARCH, + CommandPermission.EXPORT, + CommandPermission.RELOAD_CONFIG, + CommandPermission.TRANSLATIONS, + CommandPermission.LIST_GROUPS, + CommandPermission.LIST_TRACKS, + CommandPermission.USER_INFO, + CommandPermission.USER_PERM_INFO, + CommandPermission.USER_PERM_CHECK, + CommandPermission.USER_PARENT_INFO, + CommandPermission.USER_META_INFO, + CommandPermission.USER_EDITOR, + CommandPermission.USER_SHOW_TRACKS, + CommandPermission.GROUP_INFO, + CommandPermission.GROUP_PERM_INFO, + CommandPermission.GROUP_PERM_CHECK, + CommandPermission.GROUP_PARENT_INFO, + CommandPermission.GROUP_META_INFO, + CommandPermission.GROUP_EDITOR, + CommandPermission.GROUP_LIST_MEMBERS, + CommandPermission.GROUP_SHOW_TRACKS, + CommandPermission.TRACK_INFO, + CommandPermission.TRACK_EDITOR, + CommandPermission.LOG_RECENT, + CommandPermission.LOG_USER_HISTORY, + CommandPermission.LOG_GROUP_HISTORY, + CommandPermission.LOG_TRACK_HISTORY, + CommandPermission.LOG_SEARCH, + CommandPermission.LOG_NOTIFY, + CommandPermission.SPONGE_PERMISSION_INFO, + CommandPermission.SPONGE_PARENT_INFO, + CommandPermission.SPONGE_OPTION_INFO + ); + + @ParameterizedTest + @EnumSource(CommandPermission.class) + public void testReadOnly(CommandPermission permission) { + String name = permission.name(); + assertEquals(ALLOWED_READ_ONLY.contains(permission), permission.isReadOnly(), name); + } + +} diff --git a/fabric/src/main/java/me/lucko/luckperms/fabric/LPFabricPlugin.java b/fabric/src/main/java/me/lucko/luckperms/fabric/LPFabricPlugin.java index 40f422203..137dde224 100644 --- a/fabric/src/main/java/me/lucko/luckperms/fabric/LPFabricPlugin.java +++ b/fabric/src/main/java/me/lucko/luckperms/fabric/LPFabricPlugin.java @@ -90,8 +90,10 @@ public class LPFabricPlugin extends AbstractLuckPermsPlugin { new FabricPermissionsApiListener(this).registerListeners(); // Command registration also need to occur early, and will persist across game states as well. - this.commandManager = new FabricCommandExecutor(this); - this.commandManager.register(); + if (!skipCommandRegistration()) { + this.commandManager = new FabricCommandExecutor(this); + this.commandManager.register(); + } new FabricOtherListeners(this).registerListeners(); } diff --git a/fabric/src/main/resources/luckperms.conf b/fabric/src/main/resources/luckperms.conf index 599bc2a00..87391c372 100644 --- a/fabric/src/main/resources/luckperms.conf +++ b/fabric/src/main/resources/luckperms.conf @@ -650,3 +650,35 @@ update-client-command-list = true # If LuckPerms should attempt to resolve Vanilla command target selectors for LP commands. # See here for more info: https://minecraft.wiki/w/Target_selectors resolve-command-selectors = false + +# If the plugin should run in "read-only" mode for commands. +# +# In this mode, players or the console will only be able to execute commands that read or view +# data, and will not be able to execute any LP commands that modify data. +# +# If enabling read-only mode for just players, be aware that some other plugins may allow players +# to execute commands as the console, allowing them to run LP commands indirectly. +# +# Note: This does not affect interactions with LuckPerms via the API. +commands-read-only-mode { + players = false + console = false + + +# If LuckPerms commands should be disabled. When true, this will prevent all LP commands from being +# executed. In a sense this is a more extreme version of read-only mode (see above). +# +# LuckPerms will still act as the permission manager, but server administrators will be unable to +# make changes via commands. +# +# If disabling commands just for players, be aware that some other plugins may allow players to +# execute commands as the console, allowing them to run commands indirectly. +# +# If commands are disabled for both players and the console, LuckPerms will not attempt to register +# a command with the server at all & in a sense will be invisible to both players and admins. +# +# Note: This does not affect interactions with LuckPerms via the API. +disable-luckperms-commands { + players = false + console = false +} diff --git a/forge/src/main/java/me/lucko/luckperms/forge/LPForgePlugin.java b/forge/src/main/java/me/lucko/luckperms/forge/LPForgePlugin.java index 2f3520c92..62e275d30 100644 --- a/forge/src/main/java/me/lucko/luckperms/forge/LPForgePlugin.java +++ b/forge/src/main/java/me/lucko/luckperms/forge/LPForgePlugin.java @@ -99,8 +99,10 @@ public class LPForgePlugin extends AbstractLuckPermsPlugin { ForgePermissionHandlerListener permissionHandlerListener = new ForgePermissionHandlerListener(this); this.bootstrap.registerListeners(permissionHandlerListener); - this.commandManager = new ForgeCommandExecutor(this); - this.bootstrap.registerListeners(this.commandManager); + if (!skipCommandRegistration()) { + this.commandManager = new ForgeCommandExecutor(this); + this.bootstrap.registerListeners(this.commandManager); + } PluginMessageMessenger.registerChannel(); } diff --git a/forge/src/main/resources/luckperms.conf b/forge/src/main/resources/luckperms.conf index 8d5d47919..78808728b 100644 --- a/forge/src/main/resources/luckperms.conf +++ b/forge/src/main/resources/luckperms.conf @@ -639,3 +639,35 @@ update-client-command-list = true # If LuckPerms should attempt to resolve Vanilla command target selectors for LP commands. # See here for more info: https://minecraft.wiki/w/Target_selectors resolve-command-selectors = false + +# If the plugin should run in "read-only" mode for commands. +# +# In this mode, players or the console will only be able to execute commands that read or view +# data, and will not be able to execute any LP commands that modify data. +# +# If enabling read-only mode for just players, be aware that some other plugins may allow players +# to execute commands as the console, allowing them to run LP commands indirectly. +# +# Note: This does not affect interactions with LuckPerms via the API. +commands-read-only-mode { + players = false + console = false + + +# If LuckPerms commands should be disabled. When true, this will prevent all LP commands from being +# executed. In a sense this is a more extreme version of read-only mode (see above). +# +# LuckPerms will still act as the permission manager, but server administrators will be unable to +# make changes via commands. +# +# If disabling commands just for players, be aware that some other plugins may allow players to +# execute commands as the console, allowing them to run commands indirectly. +# +# If commands are disabled for both players and the console, LuckPerms will not attempt to register +# a command with the server at all & in a sense will be invisible to both players and admins. +# +# Note: This does not affect interactions with LuckPerms via the API. +disable-luckperms-commands { + players = false + console = false +} diff --git a/neoforge/src/main/java/me/lucko/luckperms/neoforge/LPNeoForgePlugin.java b/neoforge/src/main/java/me/lucko/luckperms/neoforge/LPNeoForgePlugin.java index c2bf68c46..21352edc3 100644 --- a/neoforge/src/main/java/me/lucko/luckperms/neoforge/LPNeoForgePlugin.java +++ b/neoforge/src/main/java/me/lucko/luckperms/neoforge/LPNeoForgePlugin.java @@ -95,8 +95,10 @@ public class LPNeoForgePlugin extends AbstractLuckPermsPlugin { NeoForgePermissionHandlerListener permissionHandlerListener = new NeoForgePermissionHandlerListener(this); this.bootstrap.registerListeners(permissionHandlerListener); - this.commandManager = new NeoForgeCommandExecutor(this); - this.bootstrap.registerListeners(this.commandManager); + if (!skipCommandRegistration()) { + this.commandManager = new NeoForgeCommandExecutor(this); + this.bootstrap.registerListeners(this.commandManager); + } PluginMessageMessenger.registerChannel(); } diff --git a/neoforge/src/main/resources/luckperms.conf b/neoforge/src/main/resources/luckperms.conf index 8d5d47919..78808728b 100644 --- a/neoforge/src/main/resources/luckperms.conf +++ b/neoforge/src/main/resources/luckperms.conf @@ -639,3 +639,35 @@ update-client-command-list = true # If LuckPerms should attempt to resolve Vanilla command target selectors for LP commands. # See here for more info: https://minecraft.wiki/w/Target_selectors resolve-command-selectors = false + +# If the plugin should run in "read-only" mode for commands. +# +# In this mode, players or the console will only be able to execute commands that read or view +# data, and will not be able to execute any LP commands that modify data. +# +# If enabling read-only mode for just players, be aware that some other plugins may allow players +# to execute commands as the console, allowing them to run LP commands indirectly. +# +# Note: This does not affect interactions with LuckPerms via the API. +commands-read-only-mode { + players = false + console = false + + +# If LuckPerms commands should be disabled. When true, this will prevent all LP commands from being +# executed. In a sense this is a more extreme version of read-only mode (see above). +# +# LuckPerms will still act as the permission manager, but server administrators will be unable to +# make changes via commands. +# +# If disabling commands just for players, be aware that some other plugins may allow players to +# execute commands as the console, allowing them to run commands indirectly. +# +# If commands are disabled for both players and the console, LuckPerms will not attempt to register +# a command with the server at all & in a sense will be invisible to both players and admins. +# +# Note: This does not affect interactions with LuckPerms via the API. +disable-luckperms-commands { + players = false + console = false +} diff --git a/nukkit/src/main/resources/config.yml b/nukkit/src/main/resources/config.yml index a176bf3f6..33ca323f5 100644 --- a/nukkit/src/main/resources/config.yml +++ b/nukkit/src/main/resources/config.yml @@ -653,3 +653,33 @@ disable-bulkupdate: false # # - When this happens, the plugin will set their primary group back to default. prevent-primary-group-removal: false + +# If the plugin should run in "read-only" mode for commands. +# +# In this mode, players or the console will only be able to execute commands that read or view +# data, and will not be able to execute any LP commands that modify data. +# +# If enabling read-only mode for just players, be aware that some other plugins may allow players +# to execute commands as the console, allowing them to run LP commands indirectly. +# +# Note: This does not affect interactions with LuckPerms via the API. +commands-read-only-mode: + players: false + console: false + +# If LuckPerms commands should be disabled. When true, this will prevent all LP commands from being +# executed. In a sense this is a more extreme version of read-only mode (see above). +# +# LuckPerms will still act as the permission manager, but server administrators will be unable to +# make changes via commands. +# +# If disabling commands just for players, be aware that some other plugins may allow players to +# execute commands as the console, allowing them to run commands indirectly. +# +# If commands are disabled for both players and the console, LuckPerms will not attempt to register +# a command with the server at all & in a sense will be invisible to both players and admins. +# +# Note: This does not affect interactions with LuckPerms via the API. +disable-luckperms-commands: + players: false + console: false diff --git a/sponge/src/main/resources/luckperms.conf b/sponge/src/main/resources/luckperms.conf index 1f2ab6a7a..f0b0beb5b 100644 --- a/sponge/src/main/resources/luckperms.conf +++ b/sponge/src/main/resources/luckperms.conf @@ -637,3 +637,35 @@ update-client-command-list = true # If LuckPerms should attempt to resolve Vanilla command target selectors for LP commands. # See here for more info: https://minecraft.wiki/w/Target_selectors resolve-command-selectors = false + +# If the plugin should run in "read-only" mode for commands. +# +# In this mode, players or the console will only be able to execute commands that read or view +# data, and will not be able to execute any LP commands that modify data. +# +# If enabling read-only mode for just players, be aware that some other plugins may allow players +# to execute commands as the console, allowing them to run LP commands indirectly. +# +# Note: This does not affect interactions with LuckPerms via the API. +commands-read-only-mode { + players = false + console = false + + +# If LuckPerms commands should be disabled. When true, this will prevent all LP commands from being +# executed. In a sense this is a more extreme version of read-only mode (see above). +# +# LuckPerms will still act as the permission manager, but server administrators will be unable to +# make changes via commands. +# +# If disabling commands just for players, be aware that some other plugins may allow players to +# execute commands as the console, allowing them to run commands indirectly. +# +# If commands are disabled for both players and the console, LuckPerms will not attempt to register +# a command with the server at all & in a sense will be invisible to both players and admins. +# +# Note: This does not affect interactions with LuckPerms via the API. +disable-luckperms-commands { + players = false + console = false +} diff --git a/standalone/src/main/resources/config.yml b/standalone/src/main/resources/config.yml index e685caabb..d7c041854 100644 --- a/standalone/src/main/resources/config.yml +++ b/standalone/src/main/resources/config.yml @@ -576,3 +576,33 @@ disable-bulkupdate: false # # - When this happens, the plugin will set their primary group back to default. prevent-primary-group-removal: false + +# If the plugin should run in "read-only" mode for commands. +# +# In this mode, players or the console will only be able to execute commands that read or view +# data, and will not be able to execute any LP commands that modify data. +# +# If enabling read-only mode for just players, be aware that some other plugins may allow players +# to execute commands as the console, allowing them to run LP commands indirectly. +# +# Note: This does not affect interactions with LuckPerms via the API. +commands-read-only-mode: + players: false + console: false + +# If LuckPerms commands should be disabled. When true, this will prevent all LP commands from being +# executed. In a sense this is a more extreme version of read-only mode (see above). +# +# LuckPerms will still act as the permission manager, but server administrators will be unable to +# make changes via commands. +# +# If disabling commands just for players, be aware that some other plugins may allow players to +# execute commands as the console, allowing them to run commands indirectly. +# +# If commands are disabled for both players and the console, LuckPerms will not attempt to register +# a command with the server at all & in a sense will be invisible to both players and admins. +# +# Note: This does not affect interactions with LuckPerms via the API. +disable-luckperms-commands: + players: false + console: false diff --git a/standalone/src/test/java/me/lucko/luckperms/standalone/CommandsIntegrationTest.java b/standalone/src/test/java/me/lucko/luckperms/standalone/CommandsIntegrationTest.java index 4e5780141..bdd4f2472 100644 --- a/standalone/src/test/java/me/lucko/luckperms/standalone/CommandsIntegrationTest.java +++ b/standalone/src/test/java/me/lucko/luckperms/standalone/CommandsIntegrationTest.java @@ -1407,4 +1407,42 @@ public class CommandsIntegrationTest { }); } + @Test + public void testReadOnlyMode(@TempDir Path tempDir) { + Map config = new HashMap<>(CONFIG); + config.put("commands-read-only-mode.players", "true"); + + TestPluginProvider.use(tempDir, config, (app, bootstrap, plugin) -> { + CommandExecutor executor = app.getCommandExecutor(); + + new CommandTester(executor) + .givenHasPermissions("luckperms.group.permission.info") + .whenRunCommand("group default permission info") + .thenExpect("[LP] default does not have any permissions set.") + + .givenHasPermissions("luckperms.group.permission.info", "luckperms.group.permission.set") + .whenRunCommand("group default permission set test true") + .thenExpect("[LP] You do not have permission to use this command!", false) + + .givenHasAllPermissions() + .whenRunCommand("group default permission set test true") + .thenExpect("[LP] You do not have permission to use this command!"); + }); + } + + @Test + public void testCommandsDisabled(@TempDir Path tempDir) { + Map config = new HashMap<>(CONFIG); + config.put("disable-luckperms-commands.players", "true"); + + TestPluginProvider.use(tempDir, config, (app, bootstrap, plugin) -> { + CommandExecutor executor = app.getCommandExecutor(); + + new CommandTester(executor) + .givenHasAllPermissions() + .whenRunCommand("info") + .thenExpect("[LP] LuckPerms commands are disabled."); + }); + } + } diff --git a/standalone/src/test/java/me/lucko/luckperms/standalone/utils/CommandTester.java b/standalone/src/test/java/me/lucko/luckperms/standalone/utils/CommandTester.java index 3b9d29f79..852fd1bff 100644 --- a/standalone/src/test/java/me/lucko/luckperms/standalone/utils/CommandTester.java +++ b/standalone/src/test/java/me/lucko/luckperms/standalone/utils/CommandTester.java @@ -154,10 +154,21 @@ public final class CommandTester implements Consumer, Function