Give false default permissions priority over wildcards

I think this is a good compromise. It won't apply to registered permissions that are defaulted to 'op' (Bukkit) or 'undefined' (Sponge), only to those that are specifically set to false.

The change is configurable, enabled by default for new installs of LP.

Will hopefully go some way to resolving:
- #2787
- https://v2.nucleuspowered.org/docs/nowildcard.html
- NucleusPowered/Nucleus#1093 (and related)

cc: @dualspiral @slipcor
This commit is contained in:
Luck 2020-12-23 14:36:31 +00:00
parent 8dfeef9575
commit 8167fbf73f
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
19 changed files with 160 additions and 40 deletions

View File

@ -45,14 +45,8 @@ import net.luckperms.api.query.QueryOptions;
public class BukkitCalculatorFactory implements CalculatorFactory { public class BukkitCalculatorFactory implements CalculatorFactory {
private final LPBukkitPlugin plugin; private final LPBukkitPlugin plugin;
private final DefaultsProcessor opDefaultsProcessor;
private final DefaultsProcessor nonOpDefaultsProcessor;
public BukkitCalculatorFactory(LPBukkitPlugin plugin) { public BukkitCalculatorFactory(LPBukkitPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
this.opDefaultsProcessor = new DefaultsProcessor(this.plugin, true);
this.nonOpDefaultsProcessor = new DefaultsProcessor(this.plugin, false);
} }
@Override @Override
@ -79,7 +73,8 @@ public class BukkitCalculatorFactory implements CalculatorFactory {
boolean op = queryOptions.option(BukkitContextManager.OP_OPTION).orElse(false); boolean op = queryOptions.option(BukkitContextManager.OP_OPTION).orElse(false);
if (metadata.getHolderType() == HolderType.USER && this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS)) { if (metadata.getHolderType() == HolderType.USER && this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS)) {
processors.add(op ? this.opDefaultsProcessor : this.nonOpDefaultsProcessor); boolean overrideWildcards = this.plugin.getConfiguration().get(ConfigKeys.APPLY_DEFAULT_NEGATIONS_BEFORE_WILDCARDS);
processors.add(new DefaultsProcessor(this.plugin, overrideWildcards, op));
} }
if (op) { if (op) {

View File

@ -27,11 +27,14 @@ package me.lucko.luckperms.bukkit.calculator;
import me.lucko.luckperms.bukkit.LPBukkitPlugin; import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor; import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
import me.lucko.luckperms.common.calculator.processor.SpongeWildcardProcessor;
import me.lucko.luckperms.common.calculator.processor.WildcardProcessor;
import me.lucko.luckperms.common.calculator.result.TristateResult; import me.lucko.luckperms.common.calculator.result.TristateResult;
import net.luckperms.api.util.Tristate; import net.luckperms.api.util.Tristate;
import org.bukkit.permissions.Permission; import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
/** /**
* Permission Processor for Bukkits "default" permission system. * Permission Processor for Bukkits "default" permission system.
@ -41,15 +44,38 @@ public class DefaultsProcessor implements PermissionProcessor {
private static final TristateResult.Factory PERMISSION_MAP_RESULT_FACTORY = new TristateResult.Factory(DefaultsProcessor.class, "permission map"); private static final TristateResult.Factory PERMISSION_MAP_RESULT_FACTORY = new TristateResult.Factory(DefaultsProcessor.class, "permission map");
private final LPBukkitPlugin plugin; private final LPBukkitPlugin plugin;
private final boolean overrideWildcards;
private final boolean isOp; private final boolean isOp;
public DefaultsProcessor(LPBukkitPlugin plugin, boolean isOp) { public DefaultsProcessor(LPBukkitPlugin plugin, boolean overrideWildcards, boolean isOp) {
this.plugin = plugin; this.plugin = plugin;
this.overrideWildcards = overrideWildcards;
this.isOp = isOp; this.isOp = isOp;
} }
private boolean canOverrideWildcard(TristateResult prev) {
return this.overrideWildcards &&
(prev.processorClass() == WildcardProcessor.class || prev.processorClass() == SpongeWildcardProcessor.class) &&
prev.result() == Tristate.TRUE;
}
@Override @Override
public TristateResult hasPermission(String permission) { public TristateResult hasPermission(TristateResult prev, String permission) {
if (prev != TristateResult.UNDEFINED) {
// Check to see if the result should be overridden
if (canOverrideWildcard(prev)) {
Permission defPerm = this.plugin.getPermissionMap().get(permission);
if (defPerm != null) {
PermissionDefault def = defPerm.getDefault();
if (def == PermissionDefault.FALSE || (this.isOp && def == PermissionDefault.NOT_OP)) {
return PERMISSION_MAP_RESULT_FACTORY.result(Tristate.FALSE, "permission map (overriding wildcard): " + prev.cause());
}
}
}
return prev;
}
Tristate t = this.plugin.getDefaultPermissionMap().lookupDefaultPermission(permission, this.isOp); Tristate t = this.plugin.getDefaultPermissionMap().lookupDefaultPermission(permission, this.isOp);
if (t != Tristate.UNDEFINED) { if (t != Tristate.UNDEFINED) {
return DEFAULT_PERMISSION_MAP_RESULT_FACTORY.result(t); return DEFAULT_PERMISSION_MAP_RESULT_FACTORY.result(t);

View File

@ -44,7 +44,10 @@ public final class OpProcessor implements PermissionProcessor {
} }
@Override @Override
public TristateResult hasPermission(String permission) { public TristateResult hasPermission(TristateResult prev, String permission) {
if (prev != TristateResult.UNDEFINED) {
return prev;
}
return TRUE_RESULT; return TRUE_RESULT;
} }
} }

View File

@ -470,6 +470,17 @@ apply-wildcards: true
# and so on. # and so on.
apply-sponge-implicit-wildcards: false apply-sponge-implicit-wildcards: false
# If the plugin should apply negated Bukkit default permissions before it considers wildcard
# assignments.
#
# - Plugin authors can define permissions which explicitly should not be given automatically to OPs.
# This is usually used for so called "anti-permissions" - permissions which, when granted, apply
# something negative.
# - If this option is set to true, LuckPerms will consider any negated declarations made by
# plugins before it considers wildcards. (similar to the way the OP system works)
# - If this option is set to false, LuckPerms will consider any wildcard assignments first.
apply-default-negated-permissions-before-wildcards: true
# If the plugin should parse regex permissions. # If the plugin should parse regex permissions.
# #
# - If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the # - If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the

View File

@ -35,8 +35,6 @@ import me.lucko.luckperms.common.model.HolderType;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent; import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
import net.luckperms.api.util.Tristate;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List; import java.util.List;
@ -106,14 +104,11 @@ public class PermissionCalculator implements Function<String, TristateResult> {
// that this call is behind the cache. // that this call is behind the cache.
this.plugin.getPermissionRegistry().offer(permission); this.plugin.getPermissionRegistry().offer(permission);
TristateResult result = TristateResult.UNDEFINED;
for (PermissionProcessor processor : this.processors) { for (PermissionProcessor processor : this.processors) {
TristateResult result = processor.hasPermission(permission); result = processor.hasPermission(result, permission);
if (result.result() != Tristate.UNDEFINED) {
return result;
}
} }
return result;
return TristateResult.UNDEFINED;
} }
/** /**

View File

@ -25,6 +25,8 @@
package me.lucko.luckperms.common.calculator.processor; package me.lucko.luckperms.common.calculator.processor;
import me.lucko.luckperms.common.calculator.result.TristateResult;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
@ -35,4 +37,14 @@ public abstract class AbstractPermissionProcessor implements PermissionProcessor
public void setSource(Map<String, Boolean> sourceMap) { public void setSource(Map<String, Boolean> sourceMap) {
this.sourceMap = sourceMap; this.sourceMap = sourceMap;
} }
@Override
public TristateResult hasPermission(TristateResult prev, String permission) {
if (prev != TristateResult.UNDEFINED) {
return prev;
}
return hasPermission(permission);
}
public abstract TristateResult hasPermission(String permission);
} }

View File

@ -41,10 +41,11 @@ public interface PermissionProcessor {
/** /**
* Returns the permission value determined by this calculator. * Returns the permission value determined by this calculator.
* *
* @param prev the result of the previous calculator in the chain
* @param permission the permission * @param permission the permission
* @return a tristate * @return a tristate
*/ */
TristateResult hasPermission(String permission); TristateResult hasPermission(TristateResult prev, String permission);
/** /**
* Sets the source permissions which should be used by this processor * Sets the source permissions which should be used by this processor

View File

@ -237,6 +237,11 @@ public final class ConfigKeys {
return c.getBoolean("apply-sponge-implicit-wildcards", def); return c.getBoolean("apply-sponge-implicit-wildcards", def);
})); }));
/**
* If default negated permissions should be applied before wildcards.
*/
public static final ConfigKey<Boolean> APPLY_DEFAULT_NEGATIONS_BEFORE_WILDCARDS = notReloadable(booleanKey("apply-default-negated-permissions-before-wildcards", false));
/** /**
* If regex permissions are being applied * If regex permissions are being applied
*/ */

View File

@ -26,6 +26,8 @@
package me.lucko.luckperms.nukkit.calculator; package me.lucko.luckperms.nukkit.calculator;
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor; import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
import me.lucko.luckperms.common.calculator.processor.SpongeWildcardProcessor;
import me.lucko.luckperms.common.calculator.processor.WildcardProcessor;
import me.lucko.luckperms.common.calculator.result.TristateResult; import me.lucko.luckperms.common.calculator.result.TristateResult;
import me.lucko.luckperms.nukkit.LPNukkitPlugin; import me.lucko.luckperms.nukkit.LPNukkitPlugin;
import me.lucko.luckperms.nukkit.inject.PermissionDefault; import me.lucko.luckperms.nukkit.inject.PermissionDefault;
@ -40,15 +42,37 @@ public class DefaultsProcessor implements PermissionProcessor {
private static final TristateResult.Factory PERMISSION_MAP_RESULT_FACTORY = new TristateResult.Factory(DefaultsProcessor.class, "permission map"); private static final TristateResult.Factory PERMISSION_MAP_RESULT_FACTORY = new TristateResult.Factory(DefaultsProcessor.class, "permission map");
private final LPNukkitPlugin plugin; private final LPNukkitPlugin plugin;
private final boolean overrideWildcards;
private final boolean isOp; private final boolean isOp;
public DefaultsProcessor(LPNukkitPlugin plugin, boolean isOp) { public DefaultsProcessor(LPNukkitPlugin plugin, boolean overrideWildcards, boolean isOp) {
this.plugin = plugin; this.plugin = plugin;
this.overrideWildcards = overrideWildcards;
this.isOp = isOp; this.isOp = isOp;
} }
private boolean canOverrideWildcard(TristateResult prev) {
return this.overrideWildcards &&
(prev.processorClass() == WildcardProcessor.class || prev.processorClass() == SpongeWildcardProcessor.class) &&
prev.result() == Tristate.TRUE;
}
@Override @Override
public TristateResult hasPermission(String permission) { public TristateResult hasPermission(TristateResult prev, String permission) {
if (prev != TristateResult.UNDEFINED) {
// Check to see if the result should be overridden
if (canOverrideWildcard(prev)) {
PermissionDefault def = PermissionDefault.fromPermission(this.plugin.getPermissionMap().get(permission));
if (def != null) {
if (def == PermissionDefault.FALSE || (this.isOp && def == PermissionDefault.NOT_OP)) {
return PERMISSION_MAP_RESULT_FACTORY.result(Tristate.FALSE, "permission map (overriding wildcard): " + prev.cause());
}
}
}
return prev;
}
Tristate t = this.plugin.getDefaultPermissionMap().lookupDefaultPermission(permission, this.isOp); Tristate t = this.plugin.getDefaultPermissionMap().lookupDefaultPermission(permission, this.isOp);
if (t != Tristate.UNDEFINED) { if (t != Tristate.UNDEFINED) {
return DEFAULT_PERMISSION_MAP_RESULT_FACTORY.result(t); return DEFAULT_PERMISSION_MAP_RESULT_FACTORY.result(t);

View File

@ -45,14 +45,8 @@ import net.luckperms.api.query.QueryOptions;
public class NukkitCalculatorFactory implements CalculatorFactory { public class NukkitCalculatorFactory implements CalculatorFactory {
private final LPNukkitPlugin plugin; private final LPNukkitPlugin plugin;
private final DefaultsProcessor opDefaultsProcessor;
private final DefaultsProcessor nonOpDefaultsProcessor;
public NukkitCalculatorFactory(LPNukkitPlugin plugin) { public NukkitCalculatorFactory(LPNukkitPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
this.opDefaultsProcessor = new DefaultsProcessor(this.plugin, true);
this.nonOpDefaultsProcessor = new DefaultsProcessor(this.plugin, false);
} }
@Override @Override
@ -79,7 +73,8 @@ public class NukkitCalculatorFactory implements CalculatorFactory {
boolean op = queryOptions.option(NukkitContextManager.OP_OPTION).orElse(false); boolean op = queryOptions.option(NukkitContextManager.OP_OPTION).orElse(false);
if (metadata.getHolderType() == HolderType.USER && this.plugin.getConfiguration().get(ConfigKeys.APPLY_NUKKIT_DEFAULT_PERMISSIONS)) { if (metadata.getHolderType() == HolderType.USER && this.plugin.getConfiguration().get(ConfigKeys.APPLY_NUKKIT_DEFAULT_PERMISSIONS)) {
processors.add(op ? this.opDefaultsProcessor : this.nonOpDefaultsProcessor); boolean overrideWildcards = this.plugin.getConfiguration().get(ConfigKeys.APPLY_DEFAULT_NEGATIONS_BEFORE_WILDCARDS);
processors.add(new DefaultsProcessor(this.plugin, overrideWildcards, op));
} }
if (op) { if (op) {

View File

@ -44,7 +44,10 @@ public final class OpProcessor implements PermissionProcessor {
} }
@Override @Override
public TristateResult hasPermission(String permission) { public TristateResult hasPermission(TristateResult prev, String permission) {
if (prev != TristateResult.UNDEFINED) {
return prev;
}
return TRUE_RESULT; return TRUE_RESULT;
} }
} }

View File

@ -465,6 +465,17 @@ apply-wildcards: true
# and so on. # and so on.
apply-sponge-implicit-wildcards: false apply-sponge-implicit-wildcards: false
# If the plugin should apply negated Nukkit default permissions before it considers wildcard
# assignments.
#
# - Plugin authors can define permissions which explicitly should not be given automatically to OPs.
# This is usually used for so called "anti-permissions" - permissions which, when granted, apply
# something negative.
# - If this option is set to true, LuckPerms will consider any negated declarations made by
# plugins before it considers wildcards. (similar to the way the OP system works)
# - If this option is set to false, LuckPerms will consider any wildcard assignments first.
apply-default-negated-permissions-before-wildcards: true
# If the plugin should parse regex permissions. # If the plugin should parse regex permissions.
# #
# - If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the # - If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the

View File

@ -26,6 +26,8 @@
package me.lucko.luckperms.sponge.calculator; package me.lucko.luckperms.sponge.calculator;
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor; import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
import me.lucko.luckperms.common.calculator.processor.SpongeWildcardProcessor;
import me.lucko.luckperms.common.calculator.processor.WildcardProcessor;
import me.lucko.luckperms.common.calculator.result.TristateResult; import me.lucko.luckperms.common.calculator.result.TristateResult;
import me.lucko.luckperms.sponge.service.model.LPPermissionService; import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject; import me.lucko.luckperms.sponge.service.model.LPSubject;
@ -39,16 +41,41 @@ public abstract class DefaultsProcessor implements PermissionProcessor {
protected final LPPermissionService service; protected final LPPermissionService service;
private final QueryOptions queryOptions; private final QueryOptions queryOptions;
private final boolean overrideWildcards;
public DefaultsProcessor(LPPermissionService service, QueryOptions queryOptions) { public DefaultsProcessor(LPPermissionService service, QueryOptions queryOptions, boolean overrideWildcards) {
this.service = service; this.service = service;
this.queryOptions = queryOptions; this.queryOptions = queryOptions;
this.overrideWildcards = overrideWildcards;
} }
protected abstract LPSubject getTypeDefaults(); protected abstract LPSubject getTypeDefaults();
private boolean canOverrideWildcard(TristateResult prev) {
return this.overrideWildcards &&
(prev.processorClass() == WildcardProcessor.class || prev.processorClass() == SpongeWildcardProcessor.class) &&
prev.result() == Tristate.TRUE;
}
@Override @Override
public TristateResult hasPermission(String permission) { public TristateResult hasPermission(TristateResult prev, String permission) {
if (prev != TristateResult.UNDEFINED) {
// Check to see if the result should be overridden
if (canOverrideWildcard(prev)) {
Tristate t = getTypeDefaults().getPermissionValue(this.queryOptions, permission);
if (t == Tristate.FALSE) {
return TYPE_DEFAULTS_RESULT_FACTORY.result(Tristate.FALSE, "type defaults (overriding wildcard): " + prev.cause());
}
t = this.service.getRootDefaults().getPermissionValue(this.queryOptions, permission);
if (t == Tristate.FALSE) {
return ROOT_DEFAULTS_RESULT_FACTORY.result(Tristate.FALSE, "root defaults (overriding wildcard): " + prev.cause());
}
}
return prev;
}
Tristate t = getTypeDefaults().getPermissionValue(this.queryOptions, permission); Tristate t = getTypeDefaults().getPermissionValue(this.queryOptions, permission);
if (t != Tristate.UNDEFINED) { if (t != Tristate.UNDEFINED) {
return TYPE_DEFAULTS_RESULT_FACTORY.result(t); return TYPE_DEFAULTS_RESULT_FACTORY.result(t);

View File

@ -33,8 +33,8 @@ import net.luckperms.api.query.QueryOptions;
public class FixedDefaultsProcessor extends DefaultsProcessor { public class FixedDefaultsProcessor extends DefaultsProcessor {
private final LPSubject defaultsSubject; private final LPSubject defaultsSubject;
public FixedDefaultsProcessor(LPPermissionService service, QueryOptions queryOptions, LPSubject defaultsSubject) { public FixedDefaultsProcessor(LPPermissionService service, QueryOptions queryOptions, LPSubject defaultsSubject, boolean overrideWildcards) {
super(service, queryOptions); super(service, queryOptions, overrideWildcards);
this.defaultsSubject = defaultsSubject; this.defaultsSubject = defaultsSubject;
} }

View File

@ -32,8 +32,8 @@ import me.lucko.luckperms.sponge.service.model.LPSubject;
import net.luckperms.api.query.QueryOptions; import net.luckperms.api.query.QueryOptions;
public class GroupDefaultsProcessor extends DefaultsProcessor implements PermissionProcessor { public class GroupDefaultsProcessor extends DefaultsProcessor implements PermissionProcessor {
public GroupDefaultsProcessor(LPPermissionService service, QueryOptions queryOptions) { public GroupDefaultsProcessor(LPPermissionService service, QueryOptions queryOptions, boolean overrideWildcards) {
super(service, queryOptions); super(service, queryOptions, overrideWildcards);
} }
@Override @Override

View File

@ -67,10 +67,11 @@ public class SpongeCalculatorFactory implements CalculatorFactory {
} }
if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_SPONGE_DEFAULT_SUBJECTS)) { if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_SPONGE_DEFAULT_SUBJECTS)) {
boolean overrideWildcards = this.plugin.getConfiguration().get(ConfigKeys.APPLY_DEFAULT_NEGATIONS_BEFORE_WILDCARDS);
if (metadata.getHolderType() == HolderType.USER) { if (metadata.getHolderType() == HolderType.USER) {
processors.add(new UserDefaultsProcessor(this.plugin.getService(), queryOptions)); processors.add(new UserDefaultsProcessor(this.plugin.getService(), queryOptions, overrideWildcards));
} else if (metadata.getHolderType() == HolderType.GROUP) { } else if (metadata.getHolderType() == HolderType.GROUP) {
processors.add(new GroupDefaultsProcessor(this.plugin.getService(), queryOptions)); processors.add(new GroupDefaultsProcessor(this.plugin.getService(), queryOptions, overrideWildcards));
} }
} }

View File

@ -32,8 +32,8 @@ import me.lucko.luckperms.sponge.service.model.LPSubject;
import net.luckperms.api.query.QueryOptions; import net.luckperms.api.query.QueryOptions;
public class UserDefaultsProcessor extends DefaultsProcessor implements PermissionProcessor { public class UserDefaultsProcessor extends DefaultsProcessor implements PermissionProcessor {
public UserDefaultsProcessor(LPPermissionService service, QueryOptions queryOptions) { public UserDefaultsProcessor(LPPermissionService service, QueryOptions queryOptions, boolean overrideWildcards) {
super(service, queryOptions); super(service, queryOptions, overrideWildcards);
} }
@Override @Override

View File

@ -103,7 +103,7 @@ public class CalculatedSubjectCachedDataManager extends AbstractCachedDataManage
processors.add(new WildcardProcessor()); processors.add(new WildcardProcessor());
if (!this.subject.getParentCollection().isDefaultsCollection()) { if (!this.subject.getParentCollection().isDefaultsCollection()) {
processors.add(new FixedDefaultsProcessor(this.subject.getService(), queryOptions, this.subject.getDefaults())); processors.add(new FixedDefaultsProcessor(this.subject.getService(), queryOptions, this.subject.getDefaults(), true));
} }
return new PermissionCalculator(getPlugin(), metadata, processors.build()); return new PermissionCalculator(getPlugin(), metadata, processors.build());

View File

@ -481,6 +481,17 @@ apply-wildcards = true
# and so on. # and so on.
apply-sponge-implicit-wildcards=true apply-sponge-implicit-wildcards=true
# If the plugin should apply negated default permissions before it considers wildcard
# assignments.
#
# - Plugin authors can define permissions which explicitly should be false by default.
# This is usually used for so called "anti-permissions" - permissions which, when granted, apply
# something negative.
# - If this option is set to true, LuckPerms will consider any negated declarations made by
# plugins before it considers wildcards.
# - If this option is set to false, LuckPerms will consider any wildcard assignments first.
apply-default-negated-permissions-before-wildcards=true
# If the plugin should parse regex permissions. # If the plugin should parse regex permissions.
# #
# - If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the # - If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the