From bbd703ad72390e07a48ef6c793bb294e9581cb6c Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 7 Sep 2026 15:09:53 -0600 Subject: [PATCH 1/4] Require dedicated bulk command permission --- .../api/command/PlayerCommandHandler.java | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/command/PlayerCommandHandler.java b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/command/PlayerCommandHandler.java index 389bbd839c..11474877ff 100644 --- a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/command/PlayerCommandHandler.java +++ b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/command/PlayerCommandHandler.java @@ -1,6 +1,8 @@ package com.bencodez.advancedcore.api.command; -import org.bukkit.command.CommandSender; +import org.bukkit.command.CommandSender; + +import java.util.regex.Pattern; import com.bencodez.advancedcore.AdvancedCorePlugin; @@ -29,17 +31,20 @@ public PlayerCommandHandler(AdvancedCorePlugin plugin, String[] args, String per figureOutPlayerArg(); } - public PlayerCommandHandler(AdvancedCorePlugin plugin, String[] args, String perm, String helpMessage, - boolean allowConsole, boolean forceConsole) { - super(plugin, args, perm, helpMessage, allowConsole); + public PlayerCommandHandler(AdvancedCorePlugin plugin, String[] args, String perm, String helpMessage, + boolean allowConsole, boolean forceConsole) { + super(plugin, args, perm, helpMessage, allowConsole, forceConsole); figureOutPlayerArg(); } @Override public void execute(CommandSender sender, String[] args) { if (playerArg >= 0) { - if (args[playerArg].equalsIgnoreCase("all")) { - executeAll(sender, args); + if (args[playerArg].equalsIgnoreCase("all")) { + if (hasAllPermission(sender)) { + executeAll(sender, args); + } + return; } } executeSinglePlayer(sender, args); @@ -47,7 +52,35 @@ public void execute(CommandSender sender, String[] args) { public abstract void executeAll(CommandSender sender, String[] args); - public abstract void executeSinglePlayer(CommandSender sender, String[] args); + public abstract void executeSinglePlayer(CommandSender sender, String[] args); + + /** + * Checks the stronger permission required for the special {@code all} target. + * The first configured permission is treated as the granular command permission + * and receives an {@code .All} suffix. Any alternative permissions, such as an + * administrator permission, continue to act as overrides. + * + * @param sender command sender + * @return whether bulk execution is authorized + */ + public boolean hasAllPermission(CommandSender sender) { + String permission = getPerm(); + if (permission == null || permission.isEmpty()) { + return false; + } + String[] permissions = permission.split(Pattern.quote("|")); + if (sender.hasPermission(permissions[0] + ".All")) { + return true; + } + if (isAllowMultiplePermissions()) { + for (int i = 1; i < permissions.length; i++) { + if (sender.hasPermission(permissions[i])) { + return true; + } + } + } + return false; + } private void figureOutPlayerArg() { for (int i = 0; i < getArgs().length; i++) { From b7bdfcb8e1fe1fc9bcff20e0b8bc887468ce80b6 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 7 Sep 2026 15:10:00 -0600 Subject: [PATCH 2/4] Test player command authorization --- .../api/command/PlayerCommandHandlerTest.java | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 AdvancedCore/src/test/java/com/bencodez/advancedcore/api/command/PlayerCommandHandlerTest.java diff --git a/AdvancedCore/src/test/java/com/bencodez/advancedcore/api/command/PlayerCommandHandlerTest.java b/AdvancedCore/src/test/java/com/bencodez/advancedcore/api/command/PlayerCommandHandlerTest.java new file mode 100644 index 0000000000..cf600f6d5a --- /dev/null +++ b/AdvancedCore/src/test/java/com/bencodez/advancedcore/api/command/PlayerCommandHandlerTest.java @@ -0,0 +1,66 @@ +package com.bencodez.advancedcore.api.command; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.bukkit.command.CommandSender; +import org.junit.jupiter.api.Test; + +import com.bencodez.advancedcore.AdvancedCorePlugin; +import com.bencodez.advancedcore.AdvancedCoreConfigOptions; + +class PlayerCommandHandlerTest { + + @Test + void forceConsoleConstructorForwardsFlag() { + TestHandler handler = handler(true); + + assertTrue(handler.isForceConsole()); + } + + @Test + void bulkTargetRequiresDedicatedPermission() { + TestHandler handler = handler(false); + CommandSender sender = mock(CommandSender.class); + when(sender.hasPermission("example.command")).thenReturn(true); + + assertFalse(handler.hasAllPermission(sender)); + + when(sender.hasPermission("example.command.All")).thenReturn(true); + assertTrue(handler.hasAllPermission(sender)); + } + + @Test + void administratorAlternativeStillAuthorizesBulkTarget() { + TestHandler handler = handler(false); + CommandSender sender = mock(CommandSender.class); + when(sender.hasPermission("example.admin")).thenReturn(true); + + assertTrue(handler.hasAllPermission(sender)); + } + + private TestHandler handler(boolean forceConsole) { + AdvancedCorePlugin plugin = mock(AdvancedCorePlugin.class); + AdvancedCoreConfigOptions options = mock(AdvancedCoreConfigOptions.class); + when(plugin.getOptions()).thenReturn(options); + when(options.isMultiplePermissionChecks()).thenReturn(true); + return new TestHandler(plugin, forceConsole); + } + + private static final class TestHandler extends PlayerCommandHandler { + private TestHandler(AdvancedCorePlugin plugin, boolean forceConsole) { + super(plugin, new String[] { "user", "(player)" }, "example.command|example.admin", "help", true, + forceConsole); + } + + @Override + public void executeAll(CommandSender sender, String[] args) { + } + + @Override + public void executeSinglePlayer(CommandSender sender, String[] args) { + } + } +} From 0016f0863cc27cbbead2ae445534b181f83d7908 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 7 Sep 2026 16:35:07 -0600 Subject: [PATCH 3/4] Expose bulk permissions for permission listings --- .../api/command/PlayerCommandHandler.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/command/PlayerCommandHandler.java b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/command/PlayerCommandHandler.java index 11474877ff..4c7ca99029 100644 --- a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/command/PlayerCommandHandler.java +++ b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/command/PlayerCommandHandler.java @@ -3,6 +3,8 @@ import org.bukkit.command.CommandSender; import java.util.regex.Pattern; +import java.util.Collections; +import java.util.List; import com.bencodez.advancedcore.AdvancedCorePlugin; @@ -81,6 +83,21 @@ public boolean hasAllPermission(CommandSender sender) { } return false; } + + /** + * Returns permissions used by special player targets in addition to the normal + * command permission. Permission-listing commands can use this without granting + * the bulk permission during ordinary command checks. + * + * @return the dedicated permission for the {@code all} target + */ + public List getAdditionalPermissions() { + String permission = getPerm(); + if (permission == null || permission.isEmpty()) { + return Collections.emptyList(); + } + return Collections.singletonList(permission.split(Pattern.quote("|"))[0] + ".All"); + } private void figureOutPlayerArg() { for (int i = 0; i < getArgs().length; i++) { From 1a2310b3af1cc461d95edae90fd253f94e0ff9e9 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 7 Sep 2026 16:35:19 -0600 Subject: [PATCH 4/4] Expose bulk permissions for permission listings --- .../advancedcore/api/command/PlayerCommandHandlerTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AdvancedCore/src/test/java/com/bencodez/advancedcore/api/command/PlayerCommandHandlerTest.java b/AdvancedCore/src/test/java/com/bencodez/advancedcore/api/command/PlayerCommandHandlerTest.java index cf600f6d5a..9224d68e91 100644 --- a/AdvancedCore/src/test/java/com/bencodez/advancedcore/api/command/PlayerCommandHandlerTest.java +++ b/AdvancedCore/src/test/java/com/bencodez/advancedcore/api/command/PlayerCommandHandlerTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -41,6 +42,12 @@ void administratorAlternativeStillAuthorizesBulkTarget() { assertTrue(handler.hasAllPermission(sender)); } + @Test + void exposesBulkPermissionForPermissionListings() { + assertEquals(java.util.Collections.singletonList("example.command.All"), + handler(false).getAdditionalPermissions()); + } + private TestHandler handler(boolean forceConsole) { AdvancedCorePlugin plugin = mock(AdvancedCorePlugin.class); AdvancedCoreConfigOptions options = mock(AdvancedCoreConfigOptions.class);