diff --git a/hivemq-edge/src/main/java/com/hivemq/edge/HiveMQEdgeConstants.java b/hivemq-edge/src/main/java/com/hivemq/edge/HiveMQEdgeConstants.java index 15a105f342..d0f08f9c25 100644 --- a/hivemq-edge/src/main/java/com/hivemq/edge/HiveMQEdgeConstants.java +++ b/hivemq-edge/src/main/java/com/hivemq/edge/HiveMQEdgeConstants.java @@ -31,8 +31,8 @@ public interface HiveMQEdgeConstants { int MAX_ID_LEN = 500; int MAX_NAME_LEN = 256; - String ID_REGEX = "([a-zA-Z_0-9\\-])*"; - String NAME_REGEX = "^([a-zA-Z_0-9\\- ])*$"; + String ID_REGEX = "^([a-zA-Z_0-9-_])*$"; + String NAME_REGEX = "^[A-Za-z0-9-_](?:[A-Za-z0-9_ -]*[A-Za-z0-9_-])$"; //-- alpha-num with spaces, underscore and hyphen (but NOT starting or ending with spaces) int MAX_UINT16 = 65535; String MAX_UINT16_String = "65535"; String DEVELOPMENT_MODE = "hivemq.edge.workspace.modules"; diff --git a/hivemq-edge/src/test/java/com/hivemq/adapter/AdapterConfigFormatTest.java b/hivemq-edge/src/test/java/com/hivemq/adapter/AdapterConfigFormatTest.java new file mode 100644 index 0000000000..bd5cc6ddf3 --- /dev/null +++ b/hivemq-edge/src/test/java/com/hivemq/adapter/AdapterConfigFormatTest.java @@ -0,0 +1,97 @@ +package com.hivemq.adapter; + +import com.hivemq.edge.HiveMQEdgeConstants; +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Pattern; + +/** + * @author Simon L Johnson + */ +public class AdapterConfigFormatTest { + + @Test + void testIdentifierRegex() { + Pattern pattern = Pattern.compile(HiveMQEdgeConstants.ID_REGEX); + + //-- Test for leading and trailing whitespace + Assert.assertFalse("Leading whitespace is invalid for identifiers", pattern.matcher(" invalid-leading-ws").find()); + Assert.assertFalse("Trailing whitespace is invalid for identifiers", pattern.matcher("invalid-trailing-ws ").find()); + + //-- Test the allowed cases + Assert.assertTrue("Should be valid identifier", pattern.matcher("this-is-valid").find()); + Assert.assertTrue("Should be valid identifier", pattern.matcher("this_is_valid").find()); + Assert.assertTrue("Should be valid identifier", pattern.matcher("this_is-valid").find()); + Assert.assertTrue("Should be valid identifier", pattern.matcher("this-is_valid").find()); + Assert.assertTrue("Should be valid identifier", pattern.matcher("-thisisvalid-").find()); + Assert.assertTrue("Should be valid identifier", pattern.matcher("_thisisvalid_").find()); + + //-- Test the not allowed cases + testPatternDoesNotAllowSpecialCharsOtherThanSpecified("test_-", pattern, '_','-'); + } + + @Test + void testNameRegex() { + Pattern pattern = Pattern.compile(HiveMQEdgeConstants.NAME_REGEX); + + //-- Test for leading and trailing whitespace + Assert.assertFalse("Leading whitespace is invalid for name", pattern.matcher(" invalid-leading-ws").find()); + Assert.assertFalse("Trailing whitespace is invalid for name", pattern.matcher("invalid-trailing-ws ").find()); + + //-- Test the allowed cases + Assert.assertTrue("Should be valid name", pattern.matcher("A Valid Name").find()); + Assert.assertTrue("Should be valid name", pattern.matcher("this-is-valid").find()); + Assert.assertTrue("Should be valid name", pattern.matcher("this_is_valid").find()); + Assert.assertTrue("Should be valid name", pattern.matcher("this_is-valid").find()); + Assert.assertTrue("Should be valid name", pattern.matcher("this-is_valid").find()); + Assert.assertTrue("Should be valid name", pattern.matcher("-thisisvalid-").find()); + Assert.assertTrue("Should be valid name", pattern.matcher("_thisisvalid_").find()); + + //-- Test the not allowed cases + testPatternDoesNotAllowSpecialCharsOtherThanSpecified("test_-", pattern, '_','-'); + } + + void testPatternDoesNotAllowSpecialCharsOtherThanSpecified(final String validPrefix, final Pattern pattern, final char... exceptions) { + char[] cs = generateSomeNotAllowedChars(exceptions); + for (int i = 0; i < cs.length; i++){ + String value = validPrefix + cs[i]; + Assert.assertFalse(String.format("pattern should not be allow special char [%s]", + String.format("\\u%04x", (int) cs[i])), + pattern.matcher(value).find()); + } + } + + static char[] generateSomeNotAllowedChars(char... allowedChars){ + List asciiSpecial = new ArrayList<>(); + asciiSpecial.addAll(List.of('+','-','_','@','#','^','*','{','}','[',']','|','\\','/','<','>','?','~','`')); + for (int i = 0; i < 128; i++){ + char c = (char) i; + if((i >= 0 && i <= 47) || + (i >= 58 && i <= 64) || + (i >= 91 && i <= 96) || + (i >= 123 && i <= 127)){ + + //CR & LF + if(i == 10 || i == 13) continue; + if(!asciiSpecial.contains(c)){ + asciiSpecial.add(c); + } + } + } + if(allowedChars != null && allowedChars.length > 0){ + //b-search the allow list to remove those the pattern will allow + Arrays.sort(allowedChars); + asciiSpecial.removeIf(character -> Arrays.binarySearch(allowedChars, character) > -1); + } + Iterator itr = asciiSpecial.iterator(); + char[] chars = new char[asciiSpecial.size()]; + int i = 0; + while(itr.hasNext()) chars[i++] = itr.next(); + return chars; + } +}