From e7dcf7ecc9d448e3a07ef22843ef058d72dcb225 Mon Sep 17 00:00:00 2001 From: Dico Date: Wed, 26 Sep 2018 09:58:37 +0100 Subject: Tweaks to command permissions --- .../io/dico/dicore/command/IContextFilter.java | 152 +++------------------ .../dicore/command/InheritingContextFilter.java | 64 +++++++++ .../dicore/command/PermissionContextFilter.java | 93 +++++++++++++ .../reflect/ReflectiveRegistration.java | 2 +- .../io/dico/parcels2/command/CommandsDebug.kt | 8 +- .../dico/parcels2/command/ParcelCommandBuilder.kt | 80 ++++++----- .../command/ParcelOptionsInteractCommand.kt | 1 + 7 files changed, 222 insertions(+), 178 deletions(-) create mode 100644 dicore3/command/src/main/java/io/dico/dicore/command/InheritingContextFilter.java create mode 100644 dicore3/command/src/main/java/io/dico/dicore/command/PermissionContextFilter.java diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/IContextFilter.java b/dicore3/command/src/main/java/io/dico/dicore/command/IContextFilter.java index a60c34e..4a4c06d 100644 --- a/dicore3/command/src/main/java/io/dico/dicore/command/IContextFilter.java +++ b/dicore3/command/src/main/java/io/dico/dicore/command/IContextFilter.java @@ -3,6 +3,7 @@ package io.dico.dicore.command; import io.dico.dicore.exceptions.checkedfunctions.CheckedConsumer; import io.dico.dicore.exceptions.checkedfunctions.CheckedRunnable; import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Objects; @@ -52,10 +53,11 @@ public interface IContextFilter extends Comparable { * @return comparison value */ @Override - default int compareTo(IContextFilter o) { + default int compareTo(@NotNull IContextFilter o) { return getPriority().compareTo(o.getPriority()); } + /* default boolean isInheritable() { return false; } @@ -66,7 +68,7 @@ public interface IContextFilter extends Comparable { } return this; - } + }*/ /** * IContextFilter priorities. Executes from top to bottom. @@ -110,6 +112,8 @@ public interface IContextFilter extends Comparable { */ POST_PARAMETERS; + private IContextFilter inheritor; + /** * Get the context filter that inherits context filters from the parent of the same priority. * If this filter is also present at the parent, it will do the same for the parent's parent, and so on. @@ -117,56 +121,12 @@ public interface IContextFilter extends Comparable { * @return the inheritor */ public IContextFilter getInheritor() { + if (inheritor == null) { + inheritor = InheritingContextFilter.inheritingPriority(this); + } return inheritor; } - private static String[] addParent(String[] path, String parent) { - String[] out = new String[path.length + 1]; - System.arraycopy(path, 0, out, 0, path.length); - out[0] = parent; - return out; - } - - final IContextFilter inheritor = new IContextFilter() { - @Override - public void filterContext(ExecutionContext context) throws CommandException { - ICommandAddress address = context.getAddress(); - - String[] traversedPath = new String[0]; - do { - traversedPath = addParent(traversedPath, address.getMainKey()); - address = address.getParent(); - - if (address != null && address.hasCommand()) { - boolean doBreak = true; - - Command command = address.getCommand(); - List contextFilterList = command.getContextFilters(); - for (IContextFilter filter : contextFilterList) { - if (filter.getPriority() == Priority.this) { - if (filter == this) { - // do the same for next parent - // this method is necessary to keep traversedPath information - doBreak = false; - } else { - filter.filterSubContext(context, traversedPath); - } - } - } - - if (doBreak) { - break; - } - } - } while (address != null); - } - - @Override - public Priority getPriority() { - return Priority.this; - } - }; - } /** @@ -215,14 +175,15 @@ public interface IContextFilter extends Comparable { } static IContextFilter permission(String permission) { - Objects.requireNonNull(permission); - return filterSender(Priority.PERMISSION, sender -> Validate.isAuthorized(sender, permission)); + return new PermissionContextFilter(permission); } static IContextFilter permission(String permission, String failMessage) { - Objects.requireNonNull(permission); - Objects.requireNonNull(failMessage); - return filterSender(Priority.PERMISSION, sender -> Validate.isAuthorized(sender, permission, failMessage)); + return new PermissionContextFilter(permission, failMessage); + } + + static IContextFilter inheritablePermission(String permission) { + return new PermissionContextFilter(permission, true); } /** @@ -236,87 +197,8 @@ public interface IContextFilter extends Comparable { * @throws IllegalArgumentException if componentInsertionIndex is out of range */ static IContextFilter inheritablePermission(String permission, int componentInsertionIndex, String failMessage) { - Objects.requireNonNull(permission); - Objects.requireNonNull(failMessage); - if (componentInsertionIndex > permission.split("\\.").length || componentInsertionIndex < -1) { - throw new IllegalArgumentException("componentInsertionIndex out of range"); - } - - - return new IContextFilter() { - private String getInheritedPermission(String[] components) { - int insertedAmount = components.length; - String[] currentComponents = permission.split("\\."); - int currentAmount = currentComponents.length; - String[] targetArray = new String[currentAmount + insertedAmount]; - - int insertionIndex; - //int newInsertionIndex; - if (componentInsertionIndex == -1) { - insertionIndex = currentAmount; - //newInsertionIndex = -1; - } else { - insertionIndex = componentInsertionIndex; - //newInsertionIndex = insertionIndex + insertedAmount; - } - - // copy the current components up to insertionIndex - System.arraycopy(currentComponents, 0, targetArray, 0, insertionIndex); - // copy the new components into the array at insertionIndex - System.arraycopy(components, 0, targetArray, insertionIndex, insertedAmount); - // copy the current components from insertionIndex + inserted amount - System.arraycopy(currentComponents, insertionIndex, targetArray, insertionIndex + insertedAmount, currentAmount - insertionIndex); - - return String.join(".", targetArray); - } - - @Override - public void filterContext(ExecutionContext context) throws CommandException { - Validate.isAuthorized(context.getSender(), permission, failMessage); - } - - @Override - public void filterSubContext(ExecutionContext subContext, String... path) throws CommandException { - Validate.isAuthorized(subContext.getSender(), getInheritedPermission(path), failMessage); - } - - @Override - public Priority getPriority() { - return Priority.PERMISSION; - } - - @Override - public boolean isInheritable() { - return true; - } - - @Override - public IContextFilter inherit(String... components) { - int insertedAmount = components.length; - String[] currentComponents = permission.split("\\."); - int currentAmount = currentComponents.length; - String[] targetArray = new String[currentAmount + insertedAmount]; - - int insertionIndex; - int newInsertionIndex; - if (componentInsertionIndex == -1) { - insertionIndex = currentAmount; - newInsertionIndex = -1; - } else { - insertionIndex = componentInsertionIndex; - newInsertionIndex = insertionIndex + insertedAmount; - } - - // copy the current components up to insertionIndex - System.arraycopy(currentComponents, 0, targetArray, 0, insertionIndex); - // copy the new components into the array at insertionIndex - System.arraycopy(components, 0, targetArray, insertionIndex, insertedAmount); - // copy the current components from insertionIndex + inserted amount - System.arraycopy(currentComponents, insertionIndex, targetArray, insertionIndex + insertedAmount, currentAmount - insertionIndex); - - return inheritablePermission(String.join(".", targetArray), newInsertionIndex, failMessage); - } - }; + return new PermissionContextFilter(permission, componentInsertionIndex, failMessage); } } + diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/InheritingContextFilter.java b/dicore3/command/src/main/java/io/dico/dicore/command/InheritingContextFilter.java new file mode 100644 index 0000000..2f06ea7 --- /dev/null +++ b/dicore3/command/src/main/java/io/dico/dicore/command/InheritingContextFilter.java @@ -0,0 +1,64 @@ +package io.dico.dicore.command; + +import java.util.List; + +public abstract class InheritingContextFilter implements IContextFilter { + private static final String[] emptyStringArray = new String[0]; + + private static String[] addParent(String[] path, String parent) { + String[] out = new String[path.length + 1]; + System.arraycopy(path, 0, out, 0, path.length); + out[0] = parent; + return out; + } + + protected abstract boolean isInherited(IContextFilter filter); + + @Override + public void filterContext(ExecutionContext context) throws CommandException { + ICommandAddress address = context.getAddress(); + + String[] traversedPath = emptyStringArray; + do { + traversedPath = addParent(traversedPath, address.getMainKey()); + address = address.getParent(); + + if (address != null && address.hasCommand()) { + boolean doBreak = true; + + Command command = address.getCommand(); + List contextFilterList = command.getContextFilters(); + for (IContextFilter filter : contextFilterList) { + if (isInherited(filter)) { + if (filter == this) { + // do the same for next parent + // this method is necessary to keep traversedPath information + doBreak = false; + } else { + filter.filterSubContext(context, traversedPath); + } + } + } + + if (doBreak) { + break; + } + } + } while (address != null); + } + + static InheritingContextFilter inheritingPriority(Priority priority) { + return new InheritingContextFilter() { + @Override + protected boolean isInherited(IContextFilter filter) { + return filter.getPriority() == priority; + } + + @Override + public Priority getPriority() { + return priority; + } + }; + } + +} diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/PermissionContextFilter.java b/dicore3/command/src/main/java/io/dico/dicore/command/PermissionContextFilter.java new file mode 100644 index 0000000..6492677 --- /dev/null +++ b/dicore3/command/src/main/java/io/dico/dicore/command/PermissionContextFilter.java @@ -0,0 +1,93 @@ +package io.dico.dicore.command; + +import java.util.Objects; + +public class PermissionContextFilter implements IContextFilter { + private String permission; + private String[] permissionComponents; + private int componentInsertionIndex; + private String failMessage; + + public PermissionContextFilter(String permission) { + this.permission = Objects.requireNonNull(permission); + } + + public PermissionContextFilter(String permission, String failMessage) { + this(permission); + this.failMessage = failMessage; + } + + public PermissionContextFilter(String permission, boolean inheritable) { + this(permission, null, inheritable); + } + + public PermissionContextFilter(String permission, String failMessage, boolean inheritable) { + this(permission, failMessage); + if (inheritable) { + setupInheritability(-1); + } + } + + public PermissionContextFilter(String permission, int componentInsertionIndex, String failMessage) { + this(permission, failMessage); + setupInheritability(componentInsertionIndex); + } + + private void setupInheritability(int componentInsertionIndex) { + this.permissionComponents = permission.split("\\."); + this.componentInsertionIndex = componentInsertionIndex < 0 ? permissionComponents.length : componentInsertionIndex; + if (componentInsertionIndex > permissionComponents.length) throw new IllegalArgumentException(); + } + + private void doFilter(ExecutionContext context, String permission) throws CommandException { + if (failMessage != null) { + Validate.isAuthorized(context.getSender(), permission, failMessage); + } else { + Validate.isAuthorized(context.getSender(), permission); + } + } + + @Override + public void filterContext(ExecutionContext context) throws CommandException { + doFilter(context, permission); + } + + private String getInheritedPermission(String[] components) { + int insertedAmount = components.length; + String[] currentComponents = permissionComponents; + int currentAmount = currentComponents.length; + String[] targetArray = new String[currentAmount + insertedAmount]; + + int insertionIndex; + //int newInsertionIndex; + if (componentInsertionIndex == -1) { + insertionIndex = currentAmount; + //newInsertionIndex = -1; + } else { + insertionIndex = componentInsertionIndex; + //newInsertionIndex = insertionIndex + insertedAmount; + } + + // copy the current components up to insertionIndex + System.arraycopy(currentComponents, 0, targetArray, 0, insertionIndex); + // copy the new components into the array at insertionIndex + System.arraycopy(components, 0, targetArray, insertionIndex, insertedAmount); + // copy the current components from insertionIndex + inserted amount + System.arraycopy(currentComponents, insertionIndex, targetArray, insertionIndex + insertedAmount, currentAmount - insertionIndex); + + return String.join(".", targetArray); + } + + @Override + public void filterSubContext(ExecutionContext subContext, String... path) throws CommandException { + if (permissionComponents != null) { + doFilter(subContext, getInheritedPermission(path)); + } + } + + @Override + public Priority getPriority() { + return Priority.PERMISSION; + } + +} diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java b/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java index 0c64533..1279c2b 100644 --- a/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java +++ b/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java @@ -350,7 +350,7 @@ public class ReflectiveRegistration { try { //noinspection unchecked - String flagPermission = flag == null ? null : flag.permission(); + String flagPermission = flag == null || flag.permission().isEmpty() ? null : flag.permission(); return new Parameter<>(name, descString, parameterType, parameterInfo, type.isPrimitive(), name.startsWith("-"), flagPermission); } catch (Exception ex) { throw new CommandParseException("Invalid parameter", ex); diff --git a/src/main/kotlin/io/dico/parcels2/command/CommandsDebug.kt b/src/main/kotlin/io/dico/parcels2/command/CommandsDebug.kt index b6c7acd..60518af 100644 --- a/src/main/kotlin/io/dico/parcels2/command/CommandsDebug.kt +++ b/src/main/kotlin/io/dico/parcels2/command/CommandsDebug.kt @@ -13,6 +13,7 @@ import org.bukkit.Bukkit import org.bukkit.Material import org.bukkit.block.BlockFace import org.bukkit.block.data.Directional +import org.bukkit.command.CommandSender import org.bukkit.entity.Player import java.util.Random @@ -86,7 +87,12 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) { fun cmdForceVisitors(): Any? { val workers = plugin.workDispatcher.workers plugin.workDispatcher.completeAllTasks() - return "Task count: ${workers.size}" + return "Completed task count: ${workers.size}" + } + + @Cmd("hasperm") + fun cmdHasperm(sender: CommandSender, target: Player, permission: String): Any? { + return target.hasPermission(permission).toString() } } \ No newline at end of file diff --git a/src/main/kotlin/io/dico/parcels2/command/ParcelCommandBuilder.kt b/src/main/kotlin/io/dico/parcels2/command/ParcelCommandBuilder.kt index 1f1e4a7..7be112d 100644 --- a/src/main/kotlin/io/dico/parcels2/command/ParcelCommandBuilder.kt +++ b/src/main/kotlin/io/dico/parcels2/command/ParcelCommandBuilder.kt @@ -9,54 +9,52 @@ import java.util.LinkedList import java.util.Queue @Suppress("UsePropertyAccessSyntax") -fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher = - with(CommandBuilder()) { - val parcelsAddress = SpecialCommandAddress() - - setChatController(ParcelsChatController()) - addParameterType(false, ParcelParameterType(plugin.parcelProvider)) - addParameterType(false, ProfileParameterType()) - addParameterType(true, ParcelTarget.PType(plugin.parcelProvider, parcelsAddress)) - - group(parcelsAddress, "parcel", "plot", "plots", "p") { - addRequiredPermission("parcels.command") - registerCommands(CommandsGeneral(plugin, parcelsAddress)) - registerCommands(CommandsPrivilegesLocal(plugin)) - - group("option", "opt", "o") { - setGroupDescription( - "changes interaction options for this parcel", - "Sets whether players who are not allowed to", - "build here can interact with certain things." - ) - - group("interact", "i") { - val command = ParcelOptionsInteractCommand(plugin.parcelProvider) - Interactables.classesById.forEach { - addSubCommand(it.name, command) - } +fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher = CommandBuilder().apply { + val parcelsAddress = SpecialCommandAddress() + + setChatController(ParcelsChatController()) + addParameterType(false, ParcelParameterType(plugin.parcelProvider)) + addParameterType(false, ProfileParameterType()) + addParameterType(true, ParcelTarget.PType(plugin.parcelProvider, parcelsAddress)) + + group(parcelsAddress, "parcel", "plot", "plots", "p") { + addContextFilter(IContextFilter.inheritablePermission("parcels.command")) + registerCommands(CommandsGeneral(plugin, parcelsAddress)) + registerCommands(CommandsPrivilegesLocal(plugin)) + + group("option", "opt", "o") { + setGroupDescription( + "changes interaction options for this parcel", + "Sets whether players who are not allowed to", + "build here can interact with certain things." + ) + + group("interact", "i") { + val command = ParcelOptionsInteractCommand(plugin.parcelProvider) + Interactables.classesById.forEach { + addSubCommand(it.name, command) } } + } - group("global", "g") { - registerCommands(CommandsPrivilegesGlobal(plugin)) - } + group("global", "g") { + registerCommands(CommandsPrivilegesGlobal(plugin)) + } - group("admin", "a") { - registerCommands(CommandsAdmin(plugin)) - } + group("admin", "a") { + registerCommands(CommandsAdmin(plugin)) + } - if (!logger.isDebugEnabled) return@group + if (!logger.isDebugEnabled) return@group - group("debug", "d") { - registerCommands(CommandsDebug(plugin)) - } + group("debug", "d") { + registerCommands(CommandsDebug(plugin)) } - - generateHelpAndSyntaxCommands() - getDispatcher() } + generateHelpAndSyntaxCommands(parcelsAddress) +}.getDispatcher() + inline fun CommandBuilder.group(name: String, vararg aliases: String, config: CommandBuilder.() -> Unit) { group(name, *aliases) config() @@ -69,8 +67,8 @@ inline fun CommandBuilder.group(address: ICommandAddress, name: String, vararg a parent() } -private fun CommandBuilder.generateHelpAndSyntaxCommands(): CommandBuilder { - generateCommands(dispatcher as ICommandAddress, "help", "syntax") +private fun CommandBuilder.generateHelpAndSyntaxCommands(root: ICommandAddress): CommandBuilder { + generateCommands(root, "help", "syntax") return this } diff --git a/src/main/kotlin/io/dico/parcels2/command/ParcelOptionsInteractCommand.kt b/src/main/kotlin/io/dico/parcels2/command/ParcelOptionsInteractCommand.kt index 2923173..8ba2d93 100644 --- a/src/main/kotlin/io/dico/parcels2/command/ParcelOptionsInteractCommand.kt +++ b/src/main/kotlin/io/dico/parcels2/command/ParcelOptionsInteractCommand.kt @@ -15,6 +15,7 @@ class ParcelOptionsInteractCommand(val parcelProvider: ParcelProvider) : Command init { addContextFilter(IContextFilter.PLAYER_ONLY) + addContextFilter(IContextFilter.INHERIT_PERMISSIONS) addParameter("allowed", "allowed", ParameterTypes.BOOLEAN) } -- cgit v1.2.3