Support for permission expression (complex permissions that looks like boolean expressions)
This commit is contained in:
parent
dcfafb92cb
commit
2a3b32f489
@ -52,6 +52,12 @@
|
||||
<version>4.8.108</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fathzer</groupId>
|
||||
<artifactId>javaluator</artifactId>
|
||||
<version>3.0.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -101,12 +101,19 @@ public abstract class PermEntity {
|
||||
|
||||
public Boolean hasPermission(String permission, String server, String world) {
|
||||
Boolean ret = Permissions.resolver.getEffectivePermission(name, type, permission, server, world);
|
||||
if (Log.isDebugEnabled()) {
|
||||
Log.debug("[Perm] For " + type.toString().toLowerCase() + " " + getName() + ", '" + permission + "' is " + ret);
|
||||
}
|
||||
Log.debug("[Perm] For " + type.toString().toLowerCase() + " " + getName() + ", '" + permission + "' is " + ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean hasPermissionOr(String permission, String server, String world, boolean deflt) {
|
||||
Boolean ret = hasPermission(permission, server, world);
|
||||
return ret != null ? ret : deflt;
|
||||
}
|
||||
|
||||
public boolean hasPermissionExpression(String permExpression, String server, String world) {
|
||||
return PermissionExpressionParser.evaluate(permExpression, p -> hasPermissionOr(p, server, world, false));
|
||||
}
|
||||
|
||||
|
||||
public DisplayTreeNode debugPermission(String permission) {
|
||||
return debugPermission(permission, null, null);
|
||||
|
@ -0,0 +1,115 @@
|
||||
package fr.pandacube.lib.core.permissions;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.fathzer.soft.javaluator.AbstractEvaluator;
|
||||
import com.fathzer.soft.javaluator.BracketPair;
|
||||
import com.fathzer.soft.javaluator.Operator;
|
||||
import com.fathzer.soft.javaluator.Operator.Associativity;
|
||||
import com.fathzer.soft.javaluator.Parameters;
|
||||
|
||||
public class PermissionExpressionParser {
|
||||
|
||||
private static final PermissionEvaluator PERMISSION_EVALUATOR = new PermissionEvaluator();
|
||||
|
||||
public static boolean evaluate(String permString, LitteralPermissionTester permTester) {
|
||||
try {
|
||||
return PERMISSION_EVALUATOR.evaluate(permString, permTester);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException("Can’t evaluate the provided permission expression: '" + permString + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
public interface LitteralPermissionTester extends Function<String, Boolean> { }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static class PermissionEvaluator extends AbstractEvaluator<Boolean> {
|
||||
|
||||
private static final Operator NOT = new Operator("!", 1, Associativity.LEFT, 3);
|
||||
private static final Operator AND = new Operator("&&", 2, Associativity.LEFT, 2);
|
||||
private static final Operator OR = new Operator("||", 2, Associativity.LEFT, 1);
|
||||
|
||||
|
||||
private static final Parameters PARAMETERS;
|
||||
|
||||
static {
|
||||
PARAMETERS = new Parameters();
|
||||
PARAMETERS.add(NOT);
|
||||
PARAMETERS.add(AND);
|
||||
PARAMETERS.add(OR);
|
||||
PARAMETERS.addExpressionBracket(BracketPair.PARENTHESES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public PermissionEvaluator() {
|
||||
super(PARAMETERS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean toValue(String literal, Object evaluationContext) {
|
||||
if (literal.contains(" ") || literal.contains("|") || literal.contains("&"))
|
||||
throw new IllegalArgumentException("Unable to parse the following part of permission expression as one permission node: '" + literal + "'");
|
||||
return evaluationContext instanceof LitteralPermissionTester pt ? pt.apply(literal) : false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean evaluate(Operator operator, Iterator<Boolean> operands, Object evaluationContext) {
|
||||
if (operator == NOT) {
|
||||
return !operands.next();
|
||||
} else if (operator == OR) {
|
||||
Boolean o1 = operands.next();
|
||||
Boolean o2 = operands.next();
|
||||
return o1 || o2;
|
||||
} else if (operator == AND) {
|
||||
Boolean o1 = operands.next();
|
||||
Boolean o2 = operands.next();
|
||||
return o1 && o2;
|
||||
} else {
|
||||
return super.evaluate(operator, operands, evaluationContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public static void main(String[] args) {
|
||||
java.util.List<String> pList = java.util.Arrays.asList("p1.cmd", "p1.toto", "p2.lol");
|
||||
LitteralPermissionTester tester = p -> pList.contains(p);
|
||||
|
||||
for (String permExpr : java.util.Arrays.asList(
|
||||
"p1.cmd", // true
|
||||
"p1.notexist", // false
|
||||
"p2lol.lol", // false
|
||||
"!p1.notexist", // true
|
||||
"!p1.cmd", // false
|
||||
"p1.cmd!", // false
|
||||
"p1.cmd! p2.lol", // exception
|
||||
"p1.cmd || p1.toto", // true || true == true
|
||||
"p1.cmd || p1.notexist", // true || false == true
|
||||
"p1.fefef || p2.lol", // false || true == true
|
||||
"p1.fefef || p2.lolilol", // false || false == false
|
||||
"p1.cmd && p1.toto", // true && true == true
|
||||
"p1.cmd && p1.notexist", // true && false == false
|
||||
"p1.fefef && p2.lol", // false && true == false
|
||||
"p1.fefef && p2.lolilol", // false && false == false
|
||||
"p1.cmd && !p1.toto ", // true && !true == false
|
||||
" !p1.cmd && p1.toto", // !true && true == false
|
||||
"!p1.cmd & p1.toto", // exception
|
||||
"!p1.cmd | p1.toto", // exception
|
||||
"p1.not exist" // exception
|
||||
)) {
|
||||
try {
|
||||
System.out.println(permExpr + " -> " + evaluate(permExpr, tester));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
@ -122,6 +122,27 @@ public interface IOffPlayer {
|
||||
Boolean res = getPermissionUser().hasPermission(permission);
|
||||
return res != null ? res : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if this player has the permission resulted from the provided expression.
|
||||
* If the player is online, this will redirect the
|
||||
* method call to the {@link IOnlinePlayer} instance,
|
||||
* that MUST override this current method to avoid recussive
|
||||
* loop.
|
||||
* If the player is offline, it just call the Pandacube
|
||||
* permission system.
|
||||
* @param permission the permission node to test
|
||||
* @return whether this player has the provided permission
|
||||
*/
|
||||
public default boolean hasPermissionExpression(String permissionExpression) {
|
||||
IOnlinePlayer online = getOnlineInstance();
|
||||
|
||||
if (online != null)
|
||||
return online.hasPermissionExpression(permissionExpression);
|
||||
|
||||
// at this point, the player is offline
|
||||
return getPermissionUser().hasPermissionExpression(permissionExpression, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the this player is part of the specified group
|
||||
|
@ -70,6 +70,14 @@ public interface IOnlinePlayer extends IOffPlayer {
|
||||
* or it may result in a {@link StackOverflowError}.
|
||||
*/
|
||||
public abstract boolean hasPermission(String permission);
|
||||
|
||||
/**
|
||||
* Tells if this online player has the permission resulted from the provided expression.
|
||||
* @implSpec the implementation of this method must not directly or
|
||||
* indirectly call the method {@link IOffPlayer#hasPermissionExpression(String)},
|
||||
* or it may result in a {@link StackOverflowError}.
|
||||
*/
|
||||
public abstract boolean hasPermissionExpression(String permission);
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user