Archived
0

Tweaks to command permissions

This commit is contained in:
Dico
2018-09-26 09:58:37 +01:00
parent 520ae530d2
commit e7dcf7ecc9
7 changed files with 221 additions and 177 deletions

View File

@@ -3,6 +3,7 @@ package io.dico.dicore.command;
import io.dico.dicore.exceptions.checkedfunctions.CheckedConsumer; import io.dico.dicore.exceptions.checkedfunctions.CheckedConsumer;
import io.dico.dicore.exceptions.checkedfunctions.CheckedRunnable; import io.dico.dicore.exceptions.checkedfunctions.CheckedRunnable;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@@ -52,10 +53,11 @@ public interface IContextFilter extends Comparable<IContextFilter> {
* @return comparison value * @return comparison value
*/ */
@Override @Override
default int compareTo(IContextFilter o) { default int compareTo(@NotNull IContextFilter o) {
return getPriority().compareTo(o.getPriority()); return getPriority().compareTo(o.getPriority());
} }
/*
default boolean isInheritable() { default boolean isInheritable() {
return false; return false;
} }
@@ -66,7 +68,7 @@ public interface IContextFilter extends Comparable<IContextFilter> {
} }
return this; return this;
} }*/
/** /**
* IContextFilter priorities. Executes from top to bottom. * IContextFilter priorities. Executes from top to bottom.
@@ -110,6 +112,8 @@ public interface IContextFilter extends Comparable<IContextFilter> {
*/ */
POST_PARAMETERS; POST_PARAMETERS;
private IContextFilter inheritor;
/** /**
* Get the context filter that inherits context filters from the parent of the same priority. * 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. * 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<IContextFilter> {
* @return the inheritor * @return the inheritor
*/ */
public IContextFilter getInheritor() { public IContextFilter getInheritor() {
if (inheritor == null) {
inheritor = InheritingContextFilter.inheritingPriority(this);
}
return inheritor; 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<IContextFilter> 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<IContextFilter> {
} }
static IContextFilter permission(String permission) { static IContextFilter permission(String permission) {
Objects.requireNonNull(permission); return new PermissionContextFilter(permission);
return filterSender(Priority.PERMISSION, sender -> Validate.isAuthorized(sender, permission));
} }
static IContextFilter permission(String permission, String failMessage) { static IContextFilter permission(String permission, String failMessage) {
Objects.requireNonNull(permission); return new PermissionContextFilter(permission, failMessage);
Objects.requireNonNull(failMessage); }
return filterSender(Priority.PERMISSION, sender -> Validate.isAuthorized(sender, permission, failMessage));
static IContextFilter inheritablePermission(String permission) {
return new PermissionContextFilter(permission, true);
} }
/** /**
@@ -236,87 +197,8 @@ public interface IContextFilter extends Comparable<IContextFilter> {
* @throws IllegalArgumentException if componentInsertionIndex is out of range * @throws IllegalArgumentException if componentInsertionIndex is out of range
*/ */
static IContextFilter inheritablePermission(String permission, int componentInsertionIndex, String failMessage) { static IContextFilter inheritablePermission(String permission, int componentInsertionIndex, String failMessage) {
Objects.requireNonNull(permission); return new PermissionContextFilter(permission, componentInsertionIndex, failMessage);
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);
}
};
} }
} }

View File

@@ -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<IContextFilter> 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;
}
};
}
}

View File

@@ -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;
}
}

View File

@@ -350,7 +350,7 @@ public class ReflectiveRegistration {
try { try {
//noinspection unchecked //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); return new Parameter<>(name, descString, parameterType, parameterInfo, type.isPrimitive(), name.startsWith("-"), flagPermission);
} catch (Exception ex) { } catch (Exception ex) {
throw new CommandParseException("Invalid parameter", ex); throw new CommandParseException("Invalid parameter", ex);

View File

@@ -13,6 +13,7 @@ import org.bukkit.Bukkit
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.block.BlockFace import org.bukkit.block.BlockFace
import org.bukkit.block.data.Directional import org.bukkit.block.data.Directional
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player import org.bukkit.entity.Player
import java.util.Random import java.util.Random
@@ -86,7 +87,12 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
fun cmdForceVisitors(): Any? { fun cmdForceVisitors(): Any? {
val workers = plugin.workDispatcher.workers val workers = plugin.workDispatcher.workers
plugin.workDispatcher.completeAllTasks() 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()
} }
} }

View File

@@ -9,54 +9,52 @@ import java.util.LinkedList
import java.util.Queue import java.util.Queue
@Suppress("UsePropertyAccessSyntax") @Suppress("UsePropertyAccessSyntax")
fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher = fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher = CommandBuilder().apply {
with(CommandBuilder()) { val parcelsAddress = SpecialCommandAddress()
val parcelsAddress = SpecialCommandAddress()
setChatController(ParcelsChatController()) setChatController(ParcelsChatController())
addParameterType(false, ParcelParameterType(plugin.parcelProvider)) addParameterType(false, ParcelParameterType(plugin.parcelProvider))
addParameterType(false, ProfileParameterType()) addParameterType(false, ProfileParameterType())
addParameterType(true, ParcelTarget.PType(plugin.parcelProvider, parcelsAddress)) addParameterType(true, ParcelTarget.PType(plugin.parcelProvider, parcelsAddress))
group(parcelsAddress, "parcel", "plot", "plots", "p") { group(parcelsAddress, "parcel", "plot", "plots", "p") {
addRequiredPermission("parcels.command") addContextFilter(IContextFilter.inheritablePermission("parcels.command"))
registerCommands(CommandsGeneral(plugin, parcelsAddress)) registerCommands(CommandsGeneral(plugin, parcelsAddress))
registerCommands(CommandsPrivilegesLocal(plugin)) registerCommands(CommandsPrivilegesLocal(plugin))
group("option", "opt", "o") { group("option", "opt", "o") {
setGroupDescription( setGroupDescription(
"changes interaction options for this parcel", "changes interaction options for this parcel",
"Sets whether players who are not allowed to", "Sets whether players who are not allowed to",
"build here can interact with certain things." "build here can interact with certain things."
) )
group("interact", "i") { group("interact", "i") {
val command = ParcelOptionsInteractCommand(plugin.parcelProvider) val command = ParcelOptionsInteractCommand(plugin.parcelProvider)
Interactables.classesById.forEach { Interactables.classesById.forEach {
addSubCommand(it.name, command) addSubCommand(it.name, command)
}
} }
} }
group("global", "g") {
registerCommands(CommandsPrivilegesGlobal(plugin))
}
group("admin", "a") {
registerCommands(CommandsAdmin(plugin))
}
if (!logger.isDebugEnabled) return@group
group("debug", "d") {
registerCommands(CommandsDebug(plugin))
}
} }
generateHelpAndSyntaxCommands() group("global", "g") {
getDispatcher() registerCommands(CommandsPrivilegesGlobal(plugin))
}
group("admin", "a") {
registerCommands(CommandsAdmin(plugin))
}
if (!logger.isDebugEnabled) return@group
group("debug", "d") {
registerCommands(CommandsDebug(plugin))
}
} }
generateHelpAndSyntaxCommands(parcelsAddress)
}.getDispatcher()
inline fun CommandBuilder.group(name: String, vararg aliases: String, config: CommandBuilder.() -> Unit) { inline fun CommandBuilder.group(name: String, vararg aliases: String, config: CommandBuilder.() -> Unit) {
group(name, *aliases) group(name, *aliases)
config() config()
@@ -69,8 +67,8 @@ inline fun CommandBuilder.group(address: ICommandAddress, name: String, vararg a
parent() parent()
} }
private fun CommandBuilder.generateHelpAndSyntaxCommands(): CommandBuilder { private fun CommandBuilder.generateHelpAndSyntaxCommands(root: ICommandAddress): CommandBuilder {
generateCommands(dispatcher as ICommandAddress, "help", "syntax") generateCommands(root, "help", "syntax")
return this return this
} }

View File

@@ -15,6 +15,7 @@ class ParcelOptionsInteractCommand(val parcelProvider: ParcelProvider) : Command
init { init {
addContextFilter(IContextFilter.PLAYER_ONLY) addContextFilter(IContextFilter.PLAYER_ONLY)
addContextFilter(IContextFilter.INHERIT_PERMISSIONS)
addParameter("allowed", "allowed", ParameterTypes.BOOLEAN) addParameter("allowed", "allowed", ParameterTypes.BOOLEAN)
} }