Ignore empty string world names in Bukkit WorldCalculator (#2119)

This commit is contained in:
Luck 2020-03-30 14:32:27 +01:00
parent 42e9f43443
commit b65639cd76
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
5 changed files with 63 additions and 22 deletions

View File

@ -26,12 +26,62 @@
package net.luckperms.api.context; package net.luckperms.api.context;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Represents an individual context pair. * Represents an individual context pair.
*
* <p>Context keys and values may not be null or empty. A key/value will be
* deemed empty if it's length is zero, or if it consists of only space
* characters.</p>
*/ */
public interface Context { public interface Context {
/**
* Tests whether {@code key} is valid.
*
* <p>Context keys and values may not be null or empty. A key/value will be
* deemed empty if it's length is zero, or if it consists of only space
* characters.</p>
*
* <p>An exception is thrown when an invalid key is added to a {@link ContextSet}.</p>
*
* @param key the key to test
* @return true if valid, false otherwise.
* @since 5.1
*/
static boolean isValidKey(@Nullable String key) {
if (key == null || key.isEmpty()) {
return false;
}
// look for a non-whitespace character
for (int i = 0, n = key.length(); i < n; i++) {
if (key.charAt(i) != ' ') {
return true;
}
}
return false;
}
/**
* Tests whether {@code value} is valid.
*
* <p>Context keys and values may not be null or empty. A key/value will be
* deemed empty if it's length is zero, or if it consists of only space
* characters.</p>
*
* <p>An exception is thrown when an invalid value is added to a {@link ContextSet}.</p>
*
* @param value the value to test
* @return true if valid, false otherwise.
* @since 5.1
*/
static boolean isValidValue(@Nullable String value) {
return isValidKey(value); // the same for now...
}
/** /**
* Gets the context key. * Gets the context key.
* *

View File

@ -29,6 +29,7 @@ import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl; import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl;
import net.luckperms.api.context.Context;
import net.luckperms.api.context.ContextCalculator; import net.luckperms.api.context.ContextCalculator;
import net.luckperms.api.context.ContextConsumer; import net.luckperms.api.context.ContextConsumer;
import net.luckperms.api.context.ContextSet; import net.luckperms.api.context.ContextSet;
@ -54,7 +55,9 @@ public class WorldCalculator implements ContextCalculator<Player> {
public void calculate(@NonNull Player subject, @NonNull ContextConsumer consumer) { public void calculate(@NonNull Player subject, @NonNull ContextConsumer consumer) {
Set<String> seen = new HashSet<>(); Set<String> seen = new HashSet<>();
String world = subject.getWorld().getName().toLowerCase(); String world = subject.getWorld().getName().toLowerCase();
while (seen.add(world)) { // seems like world names can sometimes be the empty string
// see: https://github.com/lucko/LuckPerms/issues/2119
while (Context.isValidValue(world) && seen.add(world)) {
consumer.accept(DefaultContextKeys.WORLD_KEY, world); consumer.accept(DefaultContextKeys.WORLD_KEY, world);
world = this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(world, world).toLowerCase(); world = this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(world, world).toLowerCase();
} }
@ -66,7 +69,7 @@ public class WorldCalculator implements ContextCalculator<Player> {
ImmutableContextSet.Builder builder = new ImmutableContextSetImpl.BuilderImpl(); ImmutableContextSet.Builder builder = new ImmutableContextSetImpl.BuilderImpl();
for (World world : worlds) { for (World world : worlds) {
String name = world.getName().toLowerCase(); String name = world.getName().toLowerCase();
if (!name.trim().isEmpty()) { if (Context.isValidValue(name)) {
builder.add(DefaultContextKeys.WORLD_KEY, name); builder.add(DefaultContextKeys.WORLD_KEY, name);
} }
} }

View File

@ -39,6 +39,7 @@ import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.storage.misc.DataConstraints; import me.lucko.luckperms.common.storage.misc.DataConstraints;
import me.lucko.luckperms.common.util.DurationParser; import me.lucko.luckperms.common.util.DurationParser;
import net.luckperms.api.context.Context;
import net.luckperms.api.context.DefaultContextKeys; import net.luckperms.api.context.DefaultContextKeys;
import net.luckperms.api.context.ImmutableContextSet; import net.luckperms.api.context.ImmutableContextSet;
import net.luckperms.api.context.MutableContextSet; import net.luckperms.api.context.MutableContextSet;
@ -192,10 +193,8 @@ public class ArgumentParser {
value = entry; value = entry;
} }
if (AbstractContextSet.stringIsEmpty(key) ||
AbstractContextSet.stringIsEmpty(value) ||
// TODO reconsider a better place to insert / avoid this special case // TODO reconsider a better place to insert / avoid this special case
AbstractContextSet.shouldIgnoreEntry(key, value)) { if (!Context.isValidKey(key) || !Context.isValidValue(value) || AbstractContextSet.isGlobalServerWorldEntry(key, value)) {
continue; continue;
} }

View File

@ -28,6 +28,7 @@ package me.lucko.luckperms.common.context.contextset;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.SetMultimap; import com.google.common.collect.SetMultimap;
import net.luckperms.api.context.Context;
import net.luckperms.api.context.ContextSet; import net.luckperms.api.context.ContextSet;
import net.luckperms.api.context.DefaultContextKeys; import net.luckperms.api.context.DefaultContextKeys;
@ -76,7 +77,7 @@ public abstract class AbstractContextSet implements ContextSet {
static String sanitizeKey(String key) { static String sanitizeKey(String key) {
Objects.requireNonNull(key, "key is null"); Objects.requireNonNull(key, "key is null");
if (stringIsEmpty(key)) { if (!Context.isValidKey(key)) {
throw new IllegalArgumentException("key is (effectively) empty"); throw new IllegalArgumentException("key is (effectively) empty");
} }
return key.toLowerCase(); return key.toLowerCase();
@ -84,25 +85,13 @@ public abstract class AbstractContextSet implements ContextSet {
static String sanitizeValue(String value) { static String sanitizeValue(String value) {
Objects.requireNonNull(value, "value is null"); Objects.requireNonNull(value, "value is null");
if (stringIsEmpty(value)) { if (!Context.isValidValue(value)) {
throw new IllegalArgumentException("value is (effectively) empty"); throw new IllegalArgumentException("value is (effectively) empty");
} }
return value.toLowerCase(); return value.toLowerCase();
} }
public static boolean stringIsEmpty(String s) { public static boolean isGlobalServerWorldEntry(String key, String value) {
if (s.isEmpty()) {
return true;
}
for (char c : s.toCharArray()) {
if (c != ' ') {
return false;
}
}
return true;
}
public static boolean shouldIgnoreEntry(String key, String value) {
return (key.equalsIgnoreCase(DefaultContextKeys.SERVER_KEY) || key.equalsIgnoreCase(DefaultContextKeys.WORLD_KEY)) && value.equalsIgnoreCase("global"); return (key.equalsIgnoreCase(DefaultContextKeys.SERVER_KEY) || key.equalsIgnoreCase(DefaultContextKeys.WORLD_KEY)) && value.equalsIgnoreCase("global");
} }

View File

@ -119,7 +119,7 @@ public abstract class AbstractNodeBuilder<N extends ScopedNode<N, B>, B extends
@Override @Override
public @NonNull B withContext(@NonNull String key, @NonNull String value) { public @NonNull B withContext(@NonNull String key, @NonNull String value) {
// TODO reconsider a better place to insert / avoid this special case // TODO reconsider a better place to insert / avoid this special case
if (AbstractContextSet.shouldIgnoreEntry(key, value)) { if (AbstractContextSet.isGlobalServerWorldEntry(key, value)) {
return (B) this; return (B) this;
} }
this.context.add(key, value); this.context.add(key, value);