Replace command permissions with a new smarter permission system that allows for compound permissions
This commit is contained in:
parent
ce2fbe9746
commit
e8a1a9a6cf
15 changed files with 455 additions and 41 deletions
|
|
@ -28,6 +28,8 @@ import com.intellectualsites.commands.arguments.StaticArgument;
|
|||
import com.intellectualsites.commands.execution.CommandExecutionHandler;
|
||||
import com.intellectualsites.commands.meta.CommandMeta;
|
||||
import com.intellectualsites.commands.meta.SimpleCommandMeta;
|
||||
import com.intellectualsites.commands.permission.CommandPermission;
|
||||
import com.intellectualsites.commands.permission.Permission;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
|
@ -50,7 +52,7 @@ public class Command<C> {
|
|||
@Nonnull private final Map<CommandArgument<C, ?>, Description> arguments;
|
||||
@Nonnull private final CommandExecutionHandler<C> commandExecutionHandler;
|
||||
@Nullable private final Class<? extends C> senderType;
|
||||
@Nonnull private final String commandPermission;
|
||||
@Nonnull private final CommandPermission commandPermission;
|
||||
@Nonnull private final CommandMeta commandMeta;
|
||||
|
||||
/**
|
||||
|
|
@ -65,7 +67,7 @@ public class Command<C> {
|
|||
public Command(@Nonnull final Map<CommandArgument<C, ?>, Description> commandArguments,
|
||||
@Nonnull final CommandExecutionHandler<C> commandExecutionHandler,
|
||||
@Nullable final Class<? extends C> senderType,
|
||||
@Nonnull final String commandPermission,
|
||||
@Nonnull final CommandPermission commandPermission,
|
||||
@Nonnull final CommandMeta commandMeta) {
|
||||
this.arguments = Objects.requireNonNull(commandArguments, "Command arguments may not be null");
|
||||
if (this.arguments.size() == 0) {
|
||||
|
|
@ -103,7 +105,7 @@ public class Command<C> {
|
|||
@Nonnull final CommandExecutionHandler<C> commandExecutionHandler,
|
||||
@Nullable final Class<? extends C> senderType,
|
||||
@Nonnull final CommandMeta commandMeta) {
|
||||
this(commandArguments, commandExecutionHandler, senderType, "", commandMeta);
|
||||
this(commandArguments, commandExecutionHandler, senderType, Permission.empty(), commandMeta);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -116,7 +118,7 @@ public class Command<C> {
|
|||
*/
|
||||
public Command(@Nonnull final Map<CommandArgument<C, ?>, Description> commandArguments,
|
||||
@Nonnull final CommandExecutionHandler<C> commandExecutionHandler,
|
||||
@Nonnull final String commandPermission,
|
||||
@Nonnull final CommandPermission commandPermission,
|
||||
@Nonnull final CommandMeta commandMeta) {
|
||||
this(commandArguments, commandExecutionHandler, null, commandPermission, commandMeta);
|
||||
}
|
||||
|
|
@ -140,7 +142,7 @@ public class Command<C> {
|
|||
final Map<CommandArgument<C, ?>, Description> map = new LinkedHashMap<>();
|
||||
map.put(StaticArgument.required(commandName, aliases), description);
|
||||
return new Builder<>(null, commandMeta, null, map,
|
||||
new CommandExecutionHandler.NullCommandExecutionHandler<>(), "");
|
||||
new CommandExecutionHandler.NullCommandExecutionHandler<>(), Permission.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -160,7 +162,7 @@ public class Command<C> {
|
|||
final Map<CommandArgument<C, ?>, Description> map = new LinkedHashMap<>();
|
||||
map.put(StaticArgument.required(commandName, aliases), Description.empty());
|
||||
return new Builder<>(null, commandMeta, null, map,
|
||||
new CommandExecutionHandler.NullCommandExecutionHandler<>(), "");
|
||||
new CommandExecutionHandler.NullCommandExecutionHandler<>(), Permission.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -199,7 +201,7 @@ public class Command<C> {
|
|||
* @return Command permission
|
||||
*/
|
||||
@Nonnull
|
||||
public String getCommandPermission() {
|
||||
public CommandPermission getCommandPermission() {
|
||||
return this.commandPermission;
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +239,7 @@ public class Command<C> {
|
|||
@Nonnull private final Map<CommandArgument<C, ?>, Description> commandArguments;
|
||||
@Nonnull private final CommandExecutionHandler<C> commandExecutionHandler;
|
||||
@Nullable private final Class<? extends C> senderType;
|
||||
@Nonnull private final String commandPermission;
|
||||
@Nonnull private final CommandPermission commandPermission;
|
||||
@Nullable private final CommandManager<C> commandManager;
|
||||
|
||||
private Builder(@Nullable final CommandManager<C> commandManager,
|
||||
|
|
@ -245,7 +247,7 @@ public class Command<C> {
|
|||
@Nullable final Class<? extends C> senderType,
|
||||
@Nonnull final Map<CommandArgument<C, ?>, Description> commandArguments,
|
||||
@Nonnull final CommandExecutionHandler<C> commandExecutionHandler,
|
||||
@Nonnull final String commandPermission) {
|
||||
@Nonnull final CommandPermission commandPermission) {
|
||||
this.commandManager = commandManager;
|
||||
this.senderType = senderType;
|
||||
this.commandArguments = Objects.requireNonNull(commandArguments, "Arguments may not be null");
|
||||
|
|
@ -391,11 +393,23 @@ public class Command<C> {
|
|||
* @return New builder instance using the command permission
|
||||
*/
|
||||
@Nonnull
|
||||
public Builder<C> withPermission(@Nonnull final String permission) {
|
||||
public Builder<C> withPermission(@Nonnull final CommandPermission permission) {
|
||||
return new Builder<>(this.commandManager, this.commandMeta, this.senderType, this.commandArguments,
|
||||
this.commandExecutionHandler, permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a command permission
|
||||
*
|
||||
* @param permission Command permission
|
||||
* @return New builder instance using the command permission
|
||||
*/
|
||||
@Nonnull
|
||||
public Builder<C> withPermission(@Nonnull final String permission) {
|
||||
return new Builder<>(this.commandManager, this.commandMeta, this.senderType, this.commandArguments,
|
||||
this.commandExecutionHandler, Permission.of(permission));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a command using the builder instance
|
||||
*
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ import com.intellectualsites.commands.execution.preprocessor.CommandPreprocessin
|
|||
import com.intellectualsites.commands.execution.preprocessor.CommandPreprocessor;
|
||||
import com.intellectualsites.commands.internal.CommandRegistrationHandler;
|
||||
import com.intellectualsites.commands.meta.CommandMeta;
|
||||
import com.intellectualsites.commands.permission.CommandPermission;
|
||||
import com.intellectualsites.commands.permission.OrPermission;
|
||||
import com.intellectualsites.commands.permission.Permission;
|
||||
import com.intellectualsites.services.ServicePipeline;
|
||||
import com.intellectualsites.services.State;
|
||||
|
||||
|
|
@ -210,6 +213,29 @@ public abstract class CommandManager<C> {
|
|||
this.commandRegistrationHandler = commandRegistrationHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the command sender has the required permission. If the permission node is
|
||||
* empty, this should return {@code true}
|
||||
*
|
||||
* @param sender Command sender
|
||||
* @param permission Permission node
|
||||
* @return {@code true} if the sender has the permission, else {@code false}
|
||||
*/
|
||||
public boolean hasPermission(@Nonnull final C sender, @Nonnull final CommandPermission permission) {
|
||||
if (permission instanceof Permission) {
|
||||
return hasPermission(sender, permission.toString());
|
||||
}
|
||||
for (final CommandPermission innerPermission : permission.getPermissions()) {
|
||||
final boolean hasPermission = this.hasPermission(sender, innerPermission);
|
||||
if (permission instanceof OrPermission) {
|
||||
if (hasPermission) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return !(permission instanceof OrPermission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the command sender has the required permission. If the permission node is
|
||||
* empty, this should return {@code true}
|
||||
|
|
|
|||
|
|
@ -34,10 +34,13 @@ import com.intellectualsites.commands.exceptions.InvalidSyntaxException;
|
|||
import com.intellectualsites.commands.exceptions.NoCommandInLeafException;
|
||||
import com.intellectualsites.commands.exceptions.NoPermissionException;
|
||||
import com.intellectualsites.commands.exceptions.NoSuchCommandException;
|
||||
import com.intellectualsites.commands.permission.CommandPermission;
|
||||
import com.intellectualsites.commands.permission.OrPermission;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
|
@ -130,7 +133,7 @@ public final class CommandTree<C> {
|
|||
@Nonnull final CommandContext<C> commandContext,
|
||||
@Nonnull final Queue<String> commandQueue,
|
||||
@Nonnull final Node<CommandArgument<C, ?>> root) {
|
||||
String permission = this.isPermitted(commandContext.getSender(), root);
|
||||
CommandPermission permission = this.isPermitted(commandContext.getSender(), root);
|
||||
if (permission != null) {
|
||||
throw new NoPermissionException(permission, commandContext.getSender(), this.getChain(root)
|
||||
.stream()
|
||||
|
|
@ -213,7 +216,7 @@ public final class CommandTree<C> {
|
|||
@Nonnull final CommandContext<C> commandContext,
|
||||
@Nonnull final Node<CommandArgument<C, ?>> root,
|
||||
@Nonnull final Queue<String> commandQueue) {
|
||||
String permission;
|
||||
CommandPermission permission;
|
||||
final List<Node<CommandArgument<C, ?>>> children = root.getChildren();
|
||||
if (children.size() == 1 && !(children.get(0).getValue() instanceof StaticArgument)) {
|
||||
// The value has to be a variable
|
||||
|
|
@ -412,8 +415,8 @@ public final class CommandTree<C> {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
private String isPermitted(@Nonnull final C sender, @Nonnull final Node<CommandArgument<C, ?>> node) {
|
||||
final String permission = node.nodeMeta.get("permission");
|
||||
private CommandPermission isPermitted(@Nonnull final C sender, @Nonnull final Node<CommandArgument<C, ?>> node) {
|
||||
final CommandPermission permission = (CommandPermission) node.nodeMeta.get("permission");
|
||||
if (permission != null) {
|
||||
return this.commandManager.hasPermission(sender, permission) ? null : permission;
|
||||
}
|
||||
|
|
@ -422,22 +425,24 @@ public final class CommandTree<C> {
|
|||
Objects.requireNonNull(
|
||||
Objects.requireNonNull(node.value, "node.value").getOwningCommand(),
|
||||
"owning command").getCommandPermission())
|
||||
? null : Objects.requireNonNull(node.value.getOwningCommand(), "owning command").getCommandPermission();
|
||||
? null : Objects.requireNonNull(node.value.getOwningCommand(), "owning command")
|
||||
.getCommandPermission();
|
||||
}
|
||||
/*
|
||||
if any of the children would permit the execution, then the sender has a valid
|
||||
chain to execute, and so we allow them to execute the root
|
||||
*/
|
||||
final List<String> missingPermissions = new LinkedList<>();
|
||||
final List<CommandPermission> missingPermissions = new LinkedList<>();
|
||||
for (final Node<CommandArgument<C, ?>> child : node.getChildren()) {
|
||||
final String check = this.isPermitted(sender, child);
|
||||
final CommandPermission check = this.isPermitted(sender, child);
|
||||
if (check == null) {
|
||||
return null;
|
||||
} else {
|
||||
missingPermissions.add(check);
|
||||
}
|
||||
}
|
||||
return String.join(", ", missingPermissions);
|
||||
|
||||
return OrPermission.of(missingPermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -466,20 +471,23 @@ public final class CommandTree<C> {
|
|||
|
||||
// Register command permissions
|
||||
this.getLeavesRaw(this.internalTree).forEach(node -> {
|
||||
// noinspection all
|
||||
final CommandPermission commandPermission = node.getValue().getOwningCommand().getCommandPermission();
|
||||
/* All leaves must necessarily have an owning command */
|
||||
// noinspection all
|
||||
node.nodeMeta.put("permission", node.getValue().getOwningCommand().getCommandPermission());
|
||||
node.nodeMeta.put("permission", commandPermission);
|
||||
// Get chain and order it tail->head then skip the tail (leaf node)
|
||||
List<Node<CommandArgument<C, ?>>> chain = this.getChain(node);
|
||||
Collections.reverse(chain);
|
||||
chain = chain.subList(1, chain.size());
|
||||
// Go through all nodes from the tail upwards until a collision occurs
|
||||
for (final Node<CommandArgument<C, ?>> commandArgumentNode : chain) {
|
||||
if (commandArgumentNode.nodeMeta.containsKey("permission")
|
||||
&& !commandArgumentNode.nodeMeta.get("permission").equalsIgnoreCase(node.nodeMeta.get("permission"))) {
|
||||
commandArgumentNode.nodeMeta.put("permission", "");
|
||||
final CommandPermission existingPermission = (CommandPermission) commandArgumentNode.nodeMeta.get("permission");
|
||||
if (existingPermission != null) {
|
||||
commandArgumentNode.nodeMeta.put("permission",
|
||||
OrPermission.of(Arrays.asList(commandPermission, existingPermission)));
|
||||
} else {
|
||||
commandArgumentNode.nodeMeta.put("permission", node.nodeMeta.get("permission"));
|
||||
commandArgumentNode.nodeMeta.put("permission", commandPermission);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -589,7 +597,7 @@ public final class CommandTree<C> {
|
|||
*/
|
||||
public static final class Node<T> {
|
||||
|
||||
private final Map<String, String> nodeMeta = new HashMap<>();
|
||||
private final Map<String, Object> nodeMeta = new HashMap<>();
|
||||
private final List<Node<T>> children = new LinkedList<>();
|
||||
private final T value;
|
||||
private Node<T> parent;
|
||||
|
|
@ -640,7 +648,7 @@ public final class CommandTree<C> {
|
|||
* @return Node meta
|
||||
*/
|
||||
@Nonnull
|
||||
public Map<String, String> getNodeMeta() {
|
||||
public Map<String, Object> getNodeMeta() {
|
||||
return this.nodeMeta;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
package com.intellectualsites.commands.exceptions;
|
||||
|
||||
import com.intellectualsites.commands.arguments.CommandArgument;
|
||||
import com.intellectualsites.commands.permission.CommandPermission;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
|
|
@ -35,7 +36,7 @@ import java.util.List;
|
|||
@SuppressWarnings("unused")
|
||||
public class NoPermissionException extends CommandParseException {
|
||||
|
||||
private final String missingPermission;
|
||||
private final CommandPermission missingPermission;
|
||||
|
||||
/**
|
||||
* Construct a new no permission exception
|
||||
|
|
@ -44,7 +45,7 @@ public class NoPermissionException extends CommandParseException {
|
|||
* @param commandSender Command sender
|
||||
* @param currentChain Chain leading up to the exception
|
||||
*/
|
||||
public NoPermissionException(@Nonnull final String missingPermission,
|
||||
public NoPermissionException(@Nonnull final CommandPermission missingPermission,
|
||||
@Nonnull final Object commandSender,
|
||||
@Nonnull final List<CommandArgument<?, ?>> currentChain) {
|
||||
super(commandSender, currentChain);
|
||||
|
|
@ -63,7 +64,7 @@ public class NoPermissionException extends CommandParseException {
|
|||
*/
|
||||
@Nonnull
|
||||
public String getMissingPermission() {
|
||||
return this.missingPermission;
|
||||
return this.missingPermission.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Alexander Söderberg
|
||||
//
|
||||
// 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 com.intellectualsites.commands.permission;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A command permission string
|
||||
*/
|
||||
public interface CommandPermission {
|
||||
|
||||
/**
|
||||
* Get the permission nodes
|
||||
*
|
||||
* @return Permission nodes
|
||||
*/
|
||||
@Nonnull
|
||||
Collection<CommandPermission> getPermissions();
|
||||
|
||||
/**
|
||||
* Get a string representation of the permission
|
||||
*
|
||||
* @return String representation of the permission node
|
||||
*/
|
||||
@Override
|
||||
@Nonnull
|
||||
String toString();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Alexander Söderberg
|
||||
//
|
||||
// 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 com.intellectualsites.commands.permission;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Accepts as long as at least one of the permissions is accepted
|
||||
*/
|
||||
public final class OrPermission implements CommandPermission {
|
||||
|
||||
private final Collection<CommandPermission> permissions;
|
||||
|
||||
private OrPermission(@Nonnull final Collection<CommandPermission> permissions) {
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new OR permission
|
||||
*
|
||||
* @param permissions Permissions to join
|
||||
* @return Constructed permission
|
||||
*/
|
||||
@Nonnull
|
||||
public static CommandPermission of(@Nonnull final Collection<CommandPermission> permissions) {
|
||||
final Set<CommandPermission> permissionSet = new HashSet<>();
|
||||
for (final CommandPermission permission : permissions) {
|
||||
permissionSet.addAll(permission.getPermissions());
|
||||
}
|
||||
return new OrPermission(permissionSet);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Collection<CommandPermission> getPermissions() {
|
||||
return this.permissions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
final Iterator<CommandPermission> iterator = this.permissions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final CommandPermission permission = iterator.next();
|
||||
stringBuilder.append('(').append(permission.toString()).append(')');
|
||||
if (iterator.hasNext()) {
|
||||
stringBuilder.append('|');
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final OrPermission that = (OrPermission) o;
|
||||
return Objects.equals(getPermissions(), that.getPermissions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getPermissions());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Alexander Söderberg
|
||||
//
|
||||
// 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 com.intellectualsites.commands.permission;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* {@link com.intellectualsites.commands.arguments.CommandArgument} permission
|
||||
*/
|
||||
public final class Permission implements CommandPermission {
|
||||
|
||||
/**
|
||||
* Empty command permission
|
||||
*/
|
||||
private static final Permission EMPTY = Permission.of("");
|
||||
|
||||
private final String permission;
|
||||
|
||||
private Permission(@Nonnull final String permission) {
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an empty command permission
|
||||
*
|
||||
* @return Command permission
|
||||
*/
|
||||
@Nonnull
|
||||
public static Permission empty() {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a command permission instance
|
||||
*
|
||||
* @param string Command permission
|
||||
* @return Created command permission
|
||||
*/
|
||||
@Nonnull
|
||||
public static Permission of(@Nonnull final String string) {
|
||||
return new Permission(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the command permission
|
||||
*
|
||||
* @return Command permission
|
||||
*/
|
||||
@Nonnull
|
||||
public String getPermission() {
|
||||
return this.permission;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Collection<CommandPermission> getPermissions() {
|
||||
return Collections.singleton(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the command permission
|
||||
*
|
||||
* @return Command permission
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.permission;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Permission that = (Permission) o;
|
||||
return Objects.equals(getPermission(), that.getPermission());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getPermission());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Alexander Söderberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
/**
|
||||
* Command permissions
|
||||
*/
|
||||
package com.intellectualsites.commands.permission;
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Alexander Söderberg
|
||||
//
|
||||
// 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 com.intellectualsites.commands;
|
||||
|
||||
import com.intellectualsites.commands.execution.CommandExecutionCoordinator;
|
||||
import com.intellectualsites.commands.meta.CommandMeta;
|
||||
import com.intellectualsites.commands.meta.SimpleCommandMeta;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
class CommandPermissionTest {
|
||||
|
||||
private final static CommandManager<TestCommandSender> manager = new PermissionOutputtingCommandManager();
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
manager.command(manager.commandBuilder("test").literal("foo").withPermission("test.permission.one").build());
|
||||
manager.command(manager.commandBuilder("test").literal("bar").withPermission("test.permission.two").build());
|
||||
manager.command(manager.commandBuilder("test").literal("fizz").withPermission("test.permission.three").build());
|
||||
manager.command(manager.commandBuilder("test").literal("buzz").withPermission("test.permission.four").build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCompoundPermission() {
|
||||
Assertions.assertTrue(manager.suggest(new TestCommandSender(), "").isEmpty());
|
||||
}
|
||||
|
||||
private static final class PermissionOutputtingCommandManager extends CommandManager<TestCommandSender> {
|
||||
|
||||
public PermissionOutputtingCommandManager() {
|
||||
super(CommandExecutionCoordinator.simpleCoordinator(), cmd -> true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@Nonnull final TestCommandSender sender,
|
||||
@Nonnull final String permission) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CommandMeta createDefaultCommandMeta() {
|
||||
return SimpleCommandMeta.empty();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -40,6 +40,8 @@ import com.intellectualsites.commands.arguments.standard.ShortArgument;
|
|||
import com.intellectualsites.commands.arguments.standard.StringArgument;
|
||||
import com.intellectualsites.commands.context.CommandContext;
|
||||
import com.intellectualsites.commands.execution.preprocessor.CommandPreprocessingContext;
|
||||
import com.intellectualsites.commands.permission.CommandPermission;
|
||||
import com.intellectualsites.commands.permission.Permission;
|
||||
import com.mojang.brigadier.LiteralMessage;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
|
|
@ -243,14 +245,15 @@ public final class CloudBrigadierManager<C, S> {
|
|||
*/
|
||||
public LiteralCommandNode<S> createLiteralCommandNode(@Nonnull final String label,
|
||||
@Nonnull final Command<C> cloudCommand,
|
||||
@Nonnull final BiPredicate<S, String> permissionChecker,
|
||||
@Nonnull final BiPredicate<S, CommandPermission> permissionChecker,
|
||||
@Nonnull final com.mojang.brigadier.Command<S> executor) {
|
||||
final CommandTree.Node<CommandArgument<C, ?>> node = this.commandManager
|
||||
.getCommandTree().getNamedNode(cloudCommand.getArguments().get(0).getName());
|
||||
final SuggestionProvider<S> provider = (context, builder) -> this.buildSuggestions(node.getValue(), context, builder);
|
||||
final LiteralArgumentBuilder<S> literalArgumentBuilder = LiteralArgumentBuilder
|
||||
.<S>literal(label)
|
||||
.requires(sender -> permissionChecker.test(sender, node.getNodeMeta().getOrDefault("permission", "")));
|
||||
.requires(sender -> permissionChecker.test(sender, (CommandPermission) node.getNodeMeta()
|
||||
.getOrDefault("permission", Permission.empty())));
|
||||
literalArgumentBuilder.executes(executor);
|
||||
final LiteralCommandNode<S> constructedRoot = literalArgumentBuilder.build();
|
||||
for (final CommandTree.Node<CommandArgument<C, ?>> child : node.getChildren()) {
|
||||
|
|
@ -275,9 +278,10 @@ public final class CloudBrigadierManager<C, S> {
|
|||
@Nonnull final LiteralCommandNode<S> root,
|
||||
@Nonnull final SuggestionProvider<S> suggestionProvider,
|
||||
@Nonnull final com.mojang.brigadier.Command<S> executor,
|
||||
@Nonnull final BiPredicate<S, String> permissionChecker) {
|
||||
@Nonnull final BiPredicate<S, CommandPermission> permissionChecker) {
|
||||
final LiteralArgumentBuilder<S> literalArgumentBuilder = LiteralArgumentBuilder.<S>literal(root.getLiteral())
|
||||
.requires(sender -> permissionChecker.test(sender, cloudCommand.getNodeMeta().getOrDefault("permission", "")));
|
||||
.requires(sender -> permissionChecker.test(sender, (CommandPermission) cloudCommand.getNodeMeta()
|
||||
.getOrDefault("permission", Permission.empty())));
|
||||
if (cloudCommand.isLeaf() && cloudCommand.getValue() != null) {
|
||||
literalArgumentBuilder.executes(executor);
|
||||
}
|
||||
|
|
@ -291,14 +295,15 @@ public final class CloudBrigadierManager<C, S> {
|
|||
|
||||
private ArgumentBuilder<S, ?> constructCommandNode(final boolean forceExecutor,
|
||||
@Nonnull final CommandTree.Node<CommandArgument<C, ?>> root,
|
||||
@Nonnull final BiPredicate<S, String> permissionChecker,
|
||||
@Nonnull final BiPredicate<S, CommandPermission> permissionChecker,
|
||||
@Nonnull final com.mojang.brigadier.Command<S> executor,
|
||||
@Nonnull final SuggestionProvider<S> suggestionProvider) {
|
||||
|
||||
ArgumentBuilder<S, ?> argumentBuilder;
|
||||
if (root.getValue() instanceof StaticArgument) {
|
||||
argumentBuilder = LiteralArgumentBuilder.<S>literal(root.getValue().getName())
|
||||
.requires(sender -> permissionChecker.test(sender, root.getNodeMeta().getOrDefault("permission", "")))
|
||||
.requires(sender -> permissionChecker.test(sender, (CommandPermission) root.getNodeMeta()
|
||||
.getOrDefault("permission", Permission.empty())))
|
||||
.executes(executor);
|
||||
} else {
|
||||
final Pair<ArgumentType<?>, Boolean> pair = this.getArgument(root.getValue().getValueType(),
|
||||
|
|
@ -308,7 +313,8 @@ public final class CloudBrigadierManager<C, S> {
|
|||
argumentBuilder = RequiredArgumentBuilder
|
||||
.<S, Object>argument(root.getValue().getName(), (ArgumentType<Object>) pair.getLeft())
|
||||
.suggests(provider)
|
||||
.requires(sender -> permissionChecker.test(sender, root.getNodeMeta().getOrDefault("permission", "")));
|
||||
.requires(sender -> permissionChecker.test(sender, (CommandPermission) root.getNodeMeta()
|
||||
.getOrDefault("permission", Permission.empty())));
|
||||
}
|
||||
if (forceExecutor || root.isLeaf() || !root.getValue().isRequired()) {
|
||||
argumentBuilder.executes(executor);
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ final class BukkitCommand<C> extends org.bukkit.command.Command implements Plugi
|
|||
|
||||
@Override
|
||||
public String getPermission() {
|
||||
return this.cloudCommand.getCommandPermission();
|
||||
return this.cloudCommand.getCommandPermission().toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ class CloudCommodoreManager<C> extends BukkitPluginRegistrationHandler<C> {
|
|||
final com.mojang.brigadier.Command<?> cmd = o -> 1;
|
||||
final LiteralCommandNode<?> literalCommandNode = this.brigadierManager
|
||||
.createLiteralCommandNode(label, command, (o, p) -> true, cmd);
|
||||
this.commodore.register(bukkitCommand, literalCommandNode, p -> p.hasPermission(command.getCommandPermission()));
|
||||
this.commodore.register(bukkitCommand, literalCommandNode, p ->
|
||||
p.hasPermission(command.getCommandPermission().toString()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public final class BungeeCommand<C> extends Command implements TabExecutor {
|
|||
@Nonnull final CommandArgument<C, ?> command,
|
||||
@Nonnull final BungeeCommandManager<C> manager) {
|
||||
super(command.getName(),
|
||||
cloudCommand.getCommandPermission(),
|
||||
cloudCommand.getCommandPermission().toString(),
|
||||
((StaticArgument<C>) command).getAlternativeAliases().toArray(new String[0]));
|
||||
this.command = command;
|
||||
this.manager = manager;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ final class CloudburstCommand<C> extends PluginCommand<Plugin> {
|
|||
@Nonnull final CloudburstCommandManager<C> manager) {
|
||||
super(manager.getOwningPlugin(), CommandData.builder(label)
|
||||
.addAliases(aliases.toArray(new String[0]))
|
||||
.addPermission(cloudCommand.getCommandPermission())
|
||||
.addPermission(cloudCommand.getCommandPermission().toString())
|
||||
.setDescription(cloudCommand.getCommandMeta().getOrDefault("description", ""))
|
||||
.build());
|
||||
this.command = command;
|
||||
|
|
|
|||
|
|
@ -128,8 +128,8 @@ class PaperBrigadierListener<C> implements Listener {
|
|||
event.getLiteral(),
|
||||
event.getBrigadierCommand(),
|
||||
event.getBrigadierCommand(),
|
||||
(s, p) -> p.isEmpty()
|
||||
|| s.getBukkitSender().hasPermission(p)));
|
||||
(s, p) -> p.toString().isEmpty()
|
||||
|| s.getBukkitSender().hasPermission(p.toString())));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue