2022-07-20 13:18:57 +02:00
|
|
|
|
package fr.pandacube.lib.permissions;
|
2021-08-15 03:26:50 +02:00
|
|
|
|
|
|
|
|
|
import java.util.Iterator;
|
|
|
|
|
import java.util.function.Function;
|
|
|
|
|
|
|
|
|
|
import com.fathzer.soft.javaluator.AbstractEvaluator;
|
|
|
|
|
import com.fathzer.soft.javaluator.BracketPair;
|
2021-08-15 14:58:41 +02:00
|
|
|
|
import com.fathzer.soft.javaluator.Constant;
|
2021-08-15 03:26:50 +02:00
|
|
|
|
import com.fathzer.soft.javaluator.Operator;
|
|
|
|
|
import com.fathzer.soft.javaluator.Operator.Associativity;
|
|
|
|
|
import com.fathzer.soft.javaluator.Parameters;
|
|
|
|
|
|
2022-08-10 03:04:12 +02:00
|
|
|
|
/**
|
|
|
|
|
* Class that evaluates a permission string as if it was a boolean expression with permission nodes as variables.
|
|
|
|
|
* <p>
|
|
|
|
|
* A permission expression contains permission nodes, boolean operators ({@code "||"}, {@code "&&"} and {@code "!"}) and
|
|
|
|
|
* literal values {@code "true"} and {@code "false"}.
|
|
|
|
|
* Here are some example of permission expressions:
|
|
|
|
|
* <pre>{@code
|
|
|
|
|
* "p1.cmd"
|
|
|
|
|
* "!p1.toto"
|
|
|
|
|
* "p1.cmd!"
|
|
|
|
|
* "p1.cmd || p1.toto"
|
|
|
|
|
* "p1.cmd && p1.toto"
|
|
|
|
|
* "p1.cmd && !p1.toto "
|
|
|
|
|
* "p1.cmd && true"
|
|
|
|
|
* "false || p2.cmd"
|
|
|
|
|
* }</pre>
|
|
|
|
|
* Notice that spaces around permission nodes and operators does not affect the results of the parsing.
|
|
|
|
|
*/
|
2021-08-15 03:26:50 +02:00
|
|
|
|
public class PermissionExpressionParser {
|
|
|
|
|
|
|
|
|
|
private static final PermissionEvaluator PERMISSION_EVALUATOR = new PermissionEvaluator();
|
|
|
|
|
|
2022-08-10 03:04:12 +02:00
|
|
|
|
/**
|
|
|
|
|
* Evaluate the provided permission expression, testing each permission with the provided permTester.
|
|
|
|
|
*
|
|
|
|
|
* @param permString the permission expression to evaluate.
|
|
|
|
|
* @param permTester a function that gives the value of the provided permission node. It is usually a method
|
|
|
|
|
* reference to the {@code hasPermission(String)} method the player we want to test the
|
|
|
|
|
* permissions.
|
|
|
|
|
* @throws IllegalArgumentException if the expression is not correct.
|
|
|
|
|
* @return the result of the evaluation of the permission expression.
|
|
|
|
|
*/
|
2023-06-20 00:15:46 +02:00
|
|
|
|
public static boolean evaluate(String permString, LiteralPermissionTester permTester) {
|
2021-08-15 03:26:50 +02:00
|
|
|
|
try {
|
|
|
|
|
return PERMISSION_EVALUATOR.evaluate(permString, permTester);
|
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
|
throw new IllegalArgumentException("Can’t evaluate the provided permission expression: '" + permString + "'", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-10 03:04:12 +02:00
|
|
|
|
/**
|
|
|
|
|
* Functional interface that converts a string into a boolean.
|
|
|
|
|
*/
|
2023-06-20 00:15:46 +02:00
|
|
|
|
public interface LiteralPermissionTester extends Function<String, Boolean> { }
|
2021-08-15 03:26:50 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
2021-08-15 14:58:41 +02:00
|
|
|
|
private static final Constant TRUE = new Constant("true");
|
|
|
|
|
private static final Constant FALSE = new Constant("false");
|
2021-08-15 03:26:50 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final Parameters PARAMETERS;
|
|
|
|
|
|
|
|
|
|
static {
|
|
|
|
|
PARAMETERS = new Parameters();
|
|
|
|
|
PARAMETERS.add(NOT);
|
|
|
|
|
PARAMETERS.add(AND);
|
|
|
|
|
PARAMETERS.add(OR);
|
2021-08-15 14:58:41 +02:00
|
|
|
|
PARAMETERS.add(TRUE);
|
|
|
|
|
PARAMETERS.add(FALSE);
|
2021-08-15 03:26:50 +02:00
|
|
|
|
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 + "'");
|
2023-06-20 00:15:46 +02:00
|
|
|
|
return evaluationContext instanceof LiteralPermissionTester pt ? pt.apply(literal) : false;
|
2021-08-15 03:26:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-15 14:58:41 +02:00
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected Boolean evaluate(Constant constant, Object evaluationContext) {
|
|
|
|
|
if (constant == TRUE)
|
|
|
|
|
return true;
|
|
|
|
|
if (constant == FALSE)
|
|
|
|
|
return false;
|
|
|
|
|
return super.evaluate(constant, evaluationContext);
|
|
|
|
|
}
|
2021-08-15 03:26:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|