Return more detailed information about exactly how a permission check result was determined

This commit is contained in:
Luck
2019-01-31 00:45:56 +00:00
Unverified
parent 83db00aef8
commit f6c0794691
30 changed files with 257 additions and 131 deletions
@@ -31,8 +31,8 @@ import me.lucko.luckperms.api.caching.PermissionData;
import me.lucko.luckperms.common.cacheddata.CacheMetadata;
import me.lucko.luckperms.common.calculator.CalculatorFactory;
import me.lucko.luckperms.common.calculator.PermissionCalculator;
import me.lucko.luckperms.common.calculator.result.TristateResult;
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Collections;
@@ -102,21 +102,18 @@ public class PermissionCache implements PermissionData {
return this.permissionsUnmodifiable;
}
@Override
public @NonNull Tristate getPermissionValue(@NonNull String permission) {
if (permission == null) {
throw new NullPointerException("permission");
}
return this.calculator.getPermissionValue(permission, PermissionCheckEvent.Origin.LUCKPERMS_API);
}
public Tristate getPermissionValue(String permission, PermissionCheckEvent.Origin origin) {
public TristateResult getPermissionValue(String permission, PermissionCheckEvent.Origin origin) {
if (permission == null) {
throw new NullPointerException("permission");
}
return this.calculator.getPermissionValue(permission, origin);
}
@Override
public @NonNull Tristate getPermissionValue(@NonNull String permission) {
return getPermissionValue(permission, PermissionCheckEvent.Origin.LUCKPERMS_API).result();
}
@Override
public @NonNull Contexts getContexts() {
return this.contexts;
@@ -26,14 +26,13 @@
package me.lucko.luckperms.common.calculator;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.cacheddata.CacheMetadata;
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
import me.lucko.luckperms.common.calculator.result.TristateResult;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.util.LoadingMap;
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List;
@@ -43,7 +42,7 @@ import java.util.function.Function;
/**
* Calculates and caches permissions
*/
public class PermissionCalculator implements Function<String, Tristate> {
public class PermissionCalculator implements Function<String, TristateResult> {
/**
* The plugin instance
@@ -63,7 +62,7 @@ public class PermissionCalculator implements Function<String, Tristate> {
/**
* Loading cache for permission checks
*/
private final LoadingMap<String, Tristate> lookupCache = LoadingMap.of(this);
private final LoadingMap<String, TristateResult> lookupCache = LoadingMap.of(this);
public PermissionCalculator(LuckPermsPlugin plugin, CacheMetadata metadata, ImmutableList<PermissionProcessor> processors) {
this.plugin = plugin;
@@ -80,9 +79,9 @@ public class PermissionCalculator implements Function<String, Tristate> {
* @param origin marks where this check originated from
* @return the result
*/
public Tristate getPermissionValue(String permission, PermissionCheckEvent.Origin origin) {
public TristateResult getPermissionValue(String permission, PermissionCheckEvent.Origin origin) {
// get the result
Tristate result = this.lookupCache.get(permission);
TristateResult result = this.lookupCache.get(permission);
// log this permission lookup to the verbose handler
this.plugin.getVerboseHandler().offerPermissionCheckEvent(origin, this.metadata.getObjectName(), this.metadata.getContext(), permission, result);
@@ -92,7 +91,7 @@ public class PermissionCalculator implements Function<String, Tristate> {
}
@Override
public Tristate apply(@NonNull String permission) {
public TristateResult apply(@NonNull String permission) {
// convert the permission to lowercase, as all values in the backing map are also lowercase.
// this allows fast case insensitive lookups
permission = permission.toLowerCase();
@@ -103,13 +102,13 @@ public class PermissionCalculator implements Function<String, Tristate> {
this.plugin.getPermissionRegistry().offer(permission);
for (PermissionProcessor processor : this.processors) {
Tristate result = processor.hasPermission(permission);
if (result != Tristate.UNDEFINED) {
TristateResult result = processor.hasPermission(permission);
if (result.result() != Tristate.UNDEFINED) {
return result;
}
}
return Tristate.UNDEFINED;
return TristateResult.UNDEFINED;
}
/**
@@ -26,12 +26,14 @@
package me.lucko.luckperms.common.calculator.processor;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculator.result.TristateResult;
public class MapProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
private static final TristateResult.Factory RESULT_FACTORY = new TristateResult.Factory(MapProcessor.class);
@Override
public Tristate hasPermission(String permission) {
return Tristate.fromNullableBoolean(this.sourceMap.get(permission));
public TristateResult hasPermission(String permission) {
return RESULT_FACTORY.result(Tristate.fromNullableBoolean(this.sourceMap.get(permission)));
}
}
@@ -25,8 +25,8 @@
package me.lucko.luckperms.common.calculator.processor;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculator.PermissionCalculator;
import me.lucko.luckperms.common.calculator.result.TristateResult;
import java.util.Map;
@@ -44,7 +44,7 @@ public interface PermissionProcessor {
* @param permission the permission
* @return a tristate
*/
Tristate hasPermission(String permission);
TristateResult hasPermission(String permission);
/**
* Sets the source permissions which should be used by this processor
@@ -26,9 +26,9 @@
package me.lucko.luckperms.common.calculator.processor;
import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.nodetype.types.RegexType;
import me.lucko.luckperms.common.calculator.result.TristateResult;
import me.lucko.luckperms.common.node.model.NodeTypes;
import java.util.Collections;
@@ -36,17 +36,19 @@ import java.util.Map;
import java.util.regex.Pattern;
public class RegexProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
private static final TristateResult.Factory RESULT_FACTORY = new TristateResult.Factory(RegexProcessor.class);
private Map<Pattern, Boolean> regexPermissions = Collections.emptyMap();
@Override
public Tristate hasPermission(String permission) {
public TristateResult hasPermission(String permission) {
for (Map.Entry<Pattern, Boolean> e : this.regexPermissions.entrySet()) {
if (e.getKey().matcher(permission).matches()) {
return Tristate.fromBoolean(e.getValue());
return RESULT_FACTORY.result(Tristate.fromBoolean(e.getValue()), "pattern: " + e.getKey().pattern());
}
}
return Tristate.UNDEFINED;
return TristateResult.UNDEFINED;
}
@Override
@@ -26,23 +26,25 @@
package me.lucko.luckperms.common.calculator.processor;
import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculator.result.TristateResult;
import me.lucko.luckperms.common.node.model.ImmutableNode;
import java.util.Collections;
import java.util.Map;
public class WildcardProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
private static final TristateResult.Factory RESULT_FACTORY = new TristateResult.Factory(WildcardProcessor.class);
public static final String WILDCARD_SUFFIX = ".*";
private static final String GLOBAL_WILDCARD = "*";
private static final String GLOBAL_WILDCARD_WITH_QUOTES = "'*'";
private static final String ROOT_WILDCARD = "*";
private static final String ROOT_WILDCARD_WITH_QUOTES = "'*'";
private Map<String, Boolean> wildcardPermissions = Collections.emptyMap();
private Tristate globalWildcardState = Tristate.UNDEFINED;
private TristateResult rootWildcardState = TristateResult.UNDEFINED;
@Override
public Tristate hasPermission(String permission) {
public TristateResult hasPermission(String permission) {
String node = permission;
while (true) {
@@ -55,12 +57,12 @@ public class WildcardProcessor extends AbstractPermissionProcessor implements Pe
if (!node.isEmpty()) {
Tristate t = Tristate.fromNullableBoolean(this.wildcardPermissions.get(node));
if (t != Tristate.UNDEFINED) {
return t;
return RESULT_FACTORY.result(t, "match: " + node);
}
}
}
return this.globalWildcardState;
return this.rootWildcardState;
}
@Override
@@ -76,11 +78,11 @@ public class WildcardProcessor extends AbstractPermissionProcessor implements Pe
}
this.wildcardPermissions = builder.build();
Tristate state = Tristate.fromNullableBoolean(this.sourceMap.get(GLOBAL_WILDCARD));
Tristate state = Tristate.fromNullableBoolean(this.sourceMap.get(ROOT_WILDCARD));
if (state == Tristate.UNDEFINED) {
state = Tristate.fromNullableBoolean(this.sourceMap.get(GLOBAL_WILDCARD_WITH_QUOTES));
state = Tristate.fromNullableBoolean(this.sourceMap.get(ROOT_WILDCARD_WITH_QUOTES));
}
this.globalWildcardState = state;
this.rootWildcardState = RESULT_FACTORY.result(state, "root");
}
}
@@ -0,0 +1,109 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* 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 me.lucko.luckperms.common.calculator.result;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculator.PermissionCalculator;
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
/**
* Represents the result of a {@link PermissionCalculator} lookup.
*/
public final class TristateResult {
public static final TristateResult UNDEFINED = new TristateResult(Tristate.UNDEFINED, null, null);
public static TristateResult of(Tristate result, Class<? extends PermissionProcessor> processorClass, String cause) {
if (result == Tristate.UNDEFINED) {
return UNDEFINED;
}
return new TristateResult(result, processorClass, cause);
}
public static TristateResult of(Tristate result, Class<? extends PermissionProcessor> processorClass) {
return of(result, processorClass, null);
}
public static TristateResult of(Tristate result) {
return of(result, null, null);
}
private final Tristate result;
private final Class<? extends PermissionProcessor> processorClass;
private final String cause;
private TristateResult(Tristate result, Class<? extends PermissionProcessor> processorClass, String cause) {
this.result = result;
this.processorClass = processorClass;
this.cause = cause;
}
public Tristate result() {
return this.result;
}
public Class<? extends PermissionProcessor> processorClass() {
return this.processorClass;
}
public String cause() {
return this.cause;
}
public static final class Factory {
private final Class<? extends PermissionProcessor> processorClass;
private final TristateResult trueResult;
private final TristateResult falseResult;
public Factory(Class<? extends PermissionProcessor> processorClass) {
this.processorClass = processorClass;
this.trueResult = of(Tristate.TRUE, processorClass);
this.falseResult = of(Tristate.FALSE, processorClass);
}
public TristateResult result(Tristate result) {
switch (result) {
case TRUE:
return this.trueResult;
case FALSE:
return this.falseResult;
case UNDEFINED:
return UNDEFINED;
default:
throw new AssertionError();
}
}
public TristateResult result(Tristate result, String cause) {
if (cause == null) {
return result(result);
}
return of(result, this.processorClass, cause);
}
}
}
@@ -299,7 +299,7 @@ public final class ArgumentPermissions {
}
PermissionCache permissionData = user.getCachedData().getPermissionData(Contexts.of(contextSet, Contexts.global().getSettings()));
return !permissionData.getPermissionValue(NodeFactory.groupNode(targetGroupName), PermissionCheckEvent.Origin.INTERNAL).asBoolean();
return !permissionData.getPermissionValue(NodeFactory.groupNode(targetGroupName), PermissionCheckEvent.Origin.INTERNAL).result().asBoolean();
}
private ArgumentPermissions() {}
@@ -70,7 +70,7 @@ public class CheckCommand extends SingleCommand {
return CommandResult.STATE_ERROR;
}
Tristate tristate = user.getCachedData().getPermissionData(plugin.getContextForUser(user).orElse(plugin.getContextManager().getStaticContexts())).getPermissionValue(permission, PermissionCheckEvent.Origin.INTERNAL);
Tristate tristate = user.getCachedData().getPermissionData(plugin.getContextForUser(user).orElse(plugin.getContextManager().getStaticContexts())).getPermissionValue(permission, PermissionCheckEvent.Origin.INTERNAL).result();
Message.CHECK_RESULT.send(sender, user.getFormattedDisplayName(), permission, MessageUtils.formatTristate(tristate));
return CommandResult.SUCCESS;
}
@@ -27,7 +27,6 @@ package me.lucko.luckperms.common.treeview;
import com.google.common.base.Splitter;
import com.google.gson.JsonObject;
import me.lucko.luckperms.common.cacheddata.type.PermissionCache;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.sender.Sender;
@@ -151,7 +150,7 @@ public class TreeView {
checks = new JObject();
for (Map.Entry<Integer, String> node : this.view.getNodeEndings()) {
String permission = prefix + node.getValue();
checks.add(permission, checker.getPermissionValue(permission, PermissionCheckEvent.Origin.INTERNAL).name().toLowerCase());
checks.add(permission, checker.getPermissionValue(permission, PermissionCheckEvent.Origin.INTERNAL).result().name().toLowerCase());
}
} else {
checks = null;
@@ -26,19 +26,17 @@
package me.lucko.luckperms.common.verbose;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.common.util.Scripting;
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
import me.lucko.luckperms.common.verbose.event.VerboseEvent;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import java.util.List;
import java.util.StringTokenizer;
import java.util.stream.Collectors;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
/**
* Represents a verbose filter expression.
*
@@ -278,7 +276,7 @@ public final class VerboseFilter {
this.value.equals("permission") ||
permissionEvent.getCheckTarget().equalsIgnoreCase(this.value) ||
permissionEvent.getPermission().toLowerCase().startsWith(this.value.toLowerCase()) ||
permissionEvent.getResult().name().equalsIgnoreCase(this.value)
permissionEvent.getResult().result().name().equalsIgnoreCase(this.value)
);
}
@@ -25,8 +25,8 @@
package me.lucko.luckperms.common.verbose;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.calculator.result.TristateResult;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.RepeatingTask;
@@ -73,7 +73,7 @@ public class VerboseHandler extends RepeatingTask {
* @param permission the permission which was checked for
* @param result the result of the permission check
*/
public void offerPermissionCheckEvent(PermissionCheckEvent.Origin origin, String checkTarget, ContextSet checkContext, String permission, Tristate result) {
public void offerPermissionCheckEvent(PermissionCheckEvent.Origin origin, String checkTarget, ContextSet checkContext, String permission, TristateResult result) {
// don't bother even processing the check if there are no listeners registered
if (!this.listening) {
return;
@@ -26,7 +26,6 @@
package me.lucko.luckperms.common.verbose;
import com.google.gson.JsonObject;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.command.utils.MessageUtils;
@@ -41,7 +40,6 @@ import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
import me.lucko.luckperms.common.verbose.event.VerboseEvent;
import me.lucko.luckperms.common.web.Bytebin;
import net.kyori.text.TextComponent;
import net.kyori.text.event.HoverEvent;
@@ -145,8 +143,8 @@ public class VerboseListener {
Message.VERBOSE_LOG_PERMISSION.send(this.notifiedSender,
permissionEvent.getCheckTarget(),
permissionEvent.getPermission(),
getTristateColor(permissionEvent.getResult()),
permissionEvent.getResult().name().toLowerCase()
getTristateColor(permissionEvent.getResult().result()),
permissionEvent.getResult().result().name().toLowerCase()
);
} else if (event instanceof MetaCheckEvent) {
MetaCheckEvent metaEvent = (MetaCheckEvent) event;
@@ -169,8 +167,8 @@ public class VerboseListener {
textComponent = Message.VERBOSE_LOG_PERMISSION.asComponent(this.notifiedSender.getPlugin().getLocaleManager(),
permissionEvent.getCheckTarget(),
permissionEvent.getPermission(),
getTristateColor(permissionEvent.getResult()),
permissionEvent.getResult().name().toLowerCase()
getTristateColor(permissionEvent.getResult().result()),
permissionEvent.getResult().result().name().toLowerCase()
);
} else if (event instanceof MetaCheckEvent) {
MetaCheckEvent metaEvent = (MetaCheckEvent) event;
@@ -25,8 +25,8 @@
package me.lucko.luckperms.common.verbose.event;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.calculator.result.TristateResult;
import me.lucko.luckperms.common.util.gson.JObject;
public class PermissionCheckEvent extends VerboseEvent {
@@ -44,9 +44,9 @@ public class PermissionCheckEvent extends VerboseEvent {
/**
* The result of the permission check
*/
private final Tristate result;
private final TristateResult result;
public PermissionCheckEvent(Origin origin, String checkTarget, ImmutableContextSet checkContext, StackTraceElement[] checkTrace, String permission, Tristate result) {
public PermissionCheckEvent(Origin origin, String checkTarget, ImmutableContextSet checkContext, StackTraceElement[] checkTrace, String permission, TristateResult result) {
super(checkTarget, checkContext, checkTrace);
this.origin = origin;
this.permission = permission;
@@ -61,16 +61,28 @@ public class PermissionCheckEvent extends VerboseEvent {
return this.permission;
}
public Tristate getResult() {
public TristateResult getResult() {
return this.result;
}
@Override
protected void serializeTo(JObject object) {
object.add("type", "permission")
.add("permission", this.permission)
.add("result", this.result.name().toLowerCase())
.add("origin", this.origin.name().toLowerCase());
object.add("type", "permission");
object.add("permission", this.permission);
object.add("result", this.result.result().name().toLowerCase());
if (this.result.processorClass() != null || this.result.cause() != null) {
JObject resultInfo = new JObject();
if (this.result.processorClass() != null) {
resultInfo.add("processorClass", this.result.processorClass().getName());
}
if (this.result.cause() != null) {
resultInfo.add("cause", this.result.cause());
}
object.add("resultInfo", resultInfo);
}
object.add("origin", this.origin.name().toLowerCase());
}
/**