From 016a1b3421344ddb2ac6d936883b4516895e5380 Mon Sep 17 00:00:00 2001 From: zml Date: Mon, 6 Jul 2020 11:40:47 -0700 Subject: [PATCH] Handle explicitly denied permissions with no perms plugin (#3419) to finally end the `/hat` saga, hopefully for good --- .../perm/impl/SuperpermsHandler.java | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/Essentials/src/com/earth2me/essentials/perm/impl/SuperpermsHandler.java b/Essentials/src/com/earth2me/essentials/perm/impl/SuperpermsHandler.java index 6ff6cef10..e0cee3081 100644 --- a/Essentials/src/com/earth2me/essentials/perm/impl/SuperpermsHandler.java +++ b/Essentials/src/com/earth2me/essentials/perm/impl/SuperpermsHandler.java @@ -3,7 +3,9 @@ package com.earth2me.essentials.perm.impl; import com.earth2me.essentials.perm.IPermissionsHandler; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.bukkit.permissions.Permission; import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; import java.util.Arrays; import java.util.List; @@ -36,6 +38,41 @@ public class SuperpermsHandler implements IPermissionsHandler { return hasPermission(base, "group." + group); } + /** + * Return whether a permission is registered and denied to ops. + * + *

The default permission value is {@link org.bukkit.permissions.PermissionDefault#OP}, so for a permission + * to be denied to ops it has to be both explicitly registered and have its default evaluate to false for an operator

+ * + * @param node node to check + * @return whether an op would, in absense of other permissions being set, have + */ + private boolean isDeniedToOps(final String node) { + final Permission perm = Bukkit.getServer().getPluginManager().getPermission(node); + return perm != null && !perm.getDefault().getValue(true); + } + + /** + * Perform a permissions check on {@code base}. + * + *

Unless {@link #emulateWildcards()} is overridden to disable wildcard emulation, + * wildcard assignments will be checked for permissions. This has a few subtleties in order + * to respect default-false assignments. {@link org.bukkit.permissions.Permissible#isPermissionSet(String)} + * will only return true for permissions that are set on an attachment, or that are a default that evaluates to true. + * When resolving wildcards, we also want to detect permissions that are not in an attachment, but also won't evaluate + * to true for operators &em; since these are ones we've explicitly set to {@code false} in the {@code plugin.yml}

+ * + *

For the resolution itself, we check whether the permission is either set on the permissible or explicitly not + * granted to ops (i.e. deviating from the default). If so, the permission's value is returned. Otherwise, the portion + * of the permission from the beginning to the last occurrence of {@code .} followed by a {@code *} is taken and the process is repeated.

+ * + *

Once a string without dots has been checked, if no result has been found the literal permission {@code *} is + * checked and the result of that check is returned.

+ * + * @param base Player to check permissions on + * @param node permission to check + * @return calculated value + */ @Override public boolean hasPermission(final Player base, String node) { if (!emulateWildcards()) { @@ -45,7 +82,9 @@ public class SuperpermsHandler implements IPermissionsHandler { String permCheck = node; int index; while (true) { - if (base.isPermissionSet(permCheck)) { + // Either explicitly set on the subject, or globally set to not be automatically granted + // by declaring in `plugin.yml` with a `default: false` value (as opposed to the default default value of OP) + if (base.isPermissionSet(permCheck) || isDeniedToOps(node)) { return base.hasPermission(permCheck); }