From 9cb65d72a3a46b5f9886d03777e7202e79b62034 Mon Sep 17 00:00:00 2001 From: md_5 Date: Tue, 10 Jul 2018 12:21:23 +1000 Subject: Be more strict about what constitutes a valid NamespacedKey * Brings us largely in line with what is supported by the implementation * Adds unit tests --- src/main/java/org/bukkit/NamespacedKey.java | 23 +++++++++--- src/test/java/org/bukkit/NamespacedKeyTest.java | 49 +++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 src/test/java/org/bukkit/NamespacedKeyTest.java diff --git a/src/main/java/org/bukkit/NamespacedKey.java b/src/main/java/org/bukkit/NamespacedKey.java index 19632d17..ea8738ad 100644 --- a/src/main/java/org/bukkit/NamespacedKey.java +++ b/src/main/java/org/bukkit/NamespacedKey.java @@ -3,11 +3,19 @@ package org.bukkit; import com.google.common.base.Preconditions; import java.util.Locale; import java.util.UUID; +import java.util.regex.Pattern; import org.bukkit.plugin.Plugin; /** * Represents a String based key which consists of two components - a namespace * and a key. + * + * Namespaces may only contain lowercase alphanumeric characters, periods, + * underscores, and hyphens. + *

+ * Keys may only contain lowercase alphanumeric characters, periods, + * underscores, hyphens, and forward slashes. + * */ public final class NamespacedKey { @@ -21,6 +29,9 @@ public final class NamespacedKey { */ public static final String BUKKIT = "bukkit"; // + private static final Pattern VALID_NAMESPACE = Pattern.compile("[a-z0-9._-]+"); + private static final Pattern VALID_KEY = Pattern.compile("[a-z0-9/._-]+"); + // private final String namespace; private final String key; @@ -33,14 +44,13 @@ public final class NamespacedKey { */ @Deprecated public NamespacedKey(String namespace, String key) { - Preconditions.checkArgument(namespace != null && !namespace.isEmpty(), "namespace"); - Preconditions.checkArgument(key != null, "key"); + Preconditions.checkArgument(namespace != null && VALID_NAMESPACE.matcher(namespace).matches(), "namespace"); + Preconditions.checkArgument(key != null && VALID_KEY.matcher(key).matches(), "key"); this.namespace = namespace; this.key = key; String string = toString(); - Preconditions.checkArgument(string.indexOf(' ') == -1, "NamespacedKey cannot contain spaces (%s)", string); Preconditions.checkArgument(string.length() < 256, "NamespacedKey must be less than 256 characters", string); } @@ -54,12 +64,13 @@ public final class NamespacedKey { Preconditions.checkArgument(plugin != null, "plugin"); Preconditions.checkArgument(key != null, "key"); - // Plugin names cannot have spaces anymore (SimplePluginManager) - Preconditions.checkArgument(key.indexOf(' ') == -1, "key cannot contain spaces (%s)", key); - this.namespace = plugin.getName().toLowerCase(Locale.ROOT); this.key = key.toLowerCase().toLowerCase(Locale.ROOT); + // Check validity after normalization + Preconditions.checkArgument(VALID_NAMESPACE.matcher(namespace).matches(), "namespace"); + Preconditions.checkArgument(VALID_KEY.matcher(key).matches(), "key"); + String string = toString(); Preconditions.checkArgument(string.length() < 256, "NamespacedKey must be less than 256 characters (%s)", string); } diff --git a/src/test/java/org/bukkit/NamespacedKeyTest.java b/src/test/java/org/bukkit/NamespacedKeyTest.java new file mode 100644 index 00000000..7c71aabf --- /dev/null +++ b/src/test/java/org/bukkit/NamespacedKeyTest.java @@ -0,0 +1,49 @@ +package org.bukkit; + +import org.junit.Assert; +import org.junit.Test; + +public class NamespacedKeyTest { + + @Test + public void testValid() { + Assert.assertEquals("minecraft:foo", new NamespacedKey("minecraft", "foo").toString()); + Assert.assertEquals("minecraft:foo/bar", new NamespacedKey("minecraft", "foo/bar").toString()); + Assert.assertEquals("minecraft:foo/bar_baz", new NamespacedKey("minecraft", "foo/bar_baz").toString()); + Assert.assertEquals("minecraft:foo/bar_baz-qux", new NamespacedKey("minecraft", "foo/bar_baz-qux").toString()); + Assert.assertEquals("minecraft:foo/bar_baz-qux.quux", new NamespacedKey("minecraft", "foo/bar_baz-qux.quux").toString()); + } + + @Test(expected = IllegalArgumentException.class) + public void testEmptyNamespace() { + new NamespacedKey("", "foo").toString(); + } + + @Test(expected = IllegalArgumentException.class) + public void testEmptyKey() { + new NamespacedKey("minecraft", "").toString(); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidNamespace() { + new NamespacedKey("minecraft/test", "foo").toString(); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidKey() { + new NamespacedKey("minecraft", "foo!").toString(); + } + + @Test + public void testBelowLength() { + new NamespacedKey("loremipsumdolorsitametconsecteturadipiscingelitduisvolutpatvelitsitametmaximusscelerisquemorbiullamcorperexacconsequategestas", + "loremipsumdolorsitametconsecteturadipiscingelitduisvolutpatvelitsitametmaximusscelerisquemorbiullamcorperexacconsequategestas").toString(); + } + + @Test(expected = IllegalArgumentException.class) + public void testAboveLength() { + new NamespacedKey("loremipsumdolorsitametconsecteturadipiscingelitduisvolutpatvelitsitametmaximusscelerisquemorbiullamcorperexacconsequategestas", + "loremipsumdolorsitametconsecteturadipiscingelitduisvolutpatvelitsitametmaximusscelerisquemorbiullamcorperexacconsequategestas/" + + "loremipsumdolorsitametconsecteturadipiscingelitduisvolutpatvelitsitametmaximusscelerisquemorbiullamcorperexacconsequategestas").toString(); + } +} -- cgit v1.2.3