diff --git a/src/main/kotlin/org/opensearch/commons/alerting/model/DocLevelQuery.kt b/src/main/kotlin/org/opensearch/commons/alerting/model/DocLevelQuery.kt index 7c72b0ca..ebba6bf9 100644 --- a/src/main/kotlin/org/opensearch/commons/alerting/model/DocLevelQuery.kt +++ b/src/main/kotlin/org/opensearch/commons/alerting/model/DocLevelQuery.kt @@ -22,9 +22,9 @@ data class DocLevelQuery( init { // Ensure the name and tags have valid characters - validateQuery(name) + validateQueryName(name) for (tag in tags) { - validateQuery(tag) + validateQueryTag(tag) } } @@ -80,6 +80,7 @@ data class DocLevelQuery( const val QUERY_FIELD_NAMES_FIELD = "query_field_names" const val NO_ID = "" val INVALID_CHARACTERS: List = listOf(" ", "[", "]", "{", "}", "(", ")") + val QUERY_NAME_REGEX = "^.{1,256}$".toRegex() // regex to restrict string length between 1 - 256 chars @JvmStatic @Throws(IOException::class) @@ -100,7 +101,7 @@ data class DocLevelQuery( QUERY_ID_FIELD -> id = xcp.text() NAME_FIELD -> { name = xcp.text() - validateQuery(name) + validateQueryName(name) } QUERY_FIELD -> query = xcp.text() @@ -112,7 +113,7 @@ data class DocLevelQuery( ) while (xcp.nextToken() != XContentParser.Token.END_ARRAY) { val tag = xcp.text() - validateQuery(tag) + validateQueryTag(tag) tags.add(tag) } } @@ -159,16 +160,20 @@ data class DocLevelQuery( return DocLevelQuery(sin) } - // TODO: add test for this - private fun validateQuery(stringVal: String) { + private fun validateQueryTag(stringVal: String) { for (inValidChar in INVALID_CHARACTERS) { if (stringVal.contains(inValidChar)) { throw IllegalArgumentException( - "They query name or tag, $stringVal, contains an invalid character: [' ','[',']','{','}','(',')']" + "The query tag, $stringVal, contains an invalid character: [' ','[',']','{','}','(',')']" ) } } } + private fun validateQueryName(stringVal: String) { + if (!stringVal.matches(QUERY_NAME_REGEX)) { + throw IllegalArgumentException("The query name, $stringVal, should be between 1 - 256 characters.") + } + } } // constructor for java plugins' convenience to optionally avoid passing empty list for 'fieldsBeingQueried' field diff --git a/src/main/kotlin/org/opensearch/commons/utils/ValidationHelpers.kt b/src/main/kotlin/org/opensearch/commons/utils/ValidationHelpers.kt index c34a7850..3bca2f9b 100644 --- a/src/main/kotlin/org/opensearch/commons/utils/ValidationHelpers.kt +++ b/src/main/kotlin/org/opensearch/commons/utils/ValidationHelpers.kt @@ -29,6 +29,9 @@ val CLUSTER_PATTERN_REGEX = Regex("^(?=.{1,255}$)[a-z0-9*]([a-zA-Z0-9_*-]*:?[a-z // Valid ID characters = (All Base64 chars + "_-") to support UUID format and Base64 encoded IDs private val VALID_ID_CHARS: Set = (('a'..'z') + ('A'..'Z') + ('0'..'9') + '+' + '/' + '_' + '-').toSet() +// Invalid characters in a new name field: [* ? < > | #] +private val INVALID_NAME_CHARS = "^\\*\\?<>|#" + fun validateUrl(urlString: String) { require(isValidUrl(urlString)) { "Invalid URL or unsupported" } } @@ -71,3 +74,15 @@ fun validateIamRoleArn(roleArn: String) { val roleArnRegex = Pattern.compile("^arn:aws(-[^:]+)?:iam::([0-9]{12}):([a-zA-Z_0-9+=,.@\\-_/]+)$") require(roleArnRegex.matcher(roleArn).find()) { "Invalid AWS role ARN: $roleArn " } } + +fun isValidName(name: String): Boolean { + // Regex to restrict string so that it cannot start with [_, -, +], + // contain two consecutive periods or contain invalid chars + val regex = Regex("""^(?![_\-\+])(?!.*\.\.)[^$INVALID_NAME_CHARS]+$""") + + return name.matches(regex) +} + +fun getInvalidNameChars(): String { + return INVALID_NAME_CHARS +} diff --git a/src/test/kotlin/org/opensearch/commons/alerting/model/DocLevelMonitorInputTests.kt b/src/test/kotlin/org/opensearch/commons/alerting/model/DocLevelMonitorInputTests.kt index 8a3d3bde..b102b28e 100644 --- a/src/test/kotlin/org/opensearch/commons/alerting/model/DocLevelMonitorInputTests.kt +++ b/src/test/kotlin/org/opensearch/commons/alerting/model/DocLevelMonitorInputTests.kt @@ -42,14 +42,33 @@ class DocLevelMonitorInputTests { } @Test - fun `test create Doc Level Query with invalid characters for name`() { - val badString = "query with space" + fun `test create Doc Level Query with invalid name length`() { + val stringBuilder = StringBuilder() + + // test empty string + val emptyString = stringBuilder.toString() + try { + randomDocLevelQuery(name = emptyString) + Assertions.fail("Expecting an illegal argument exception") + } catch (e: IllegalArgumentException) { + Assertions.assertEquals( + "The query name, $emptyString, should be between 1 - 256 characters.", + e.message + ) + } + + // test string with 257 chars + repeat(257) { + stringBuilder.append("a") + } + val badString = stringBuilder.toString() + try { randomDocLevelQuery(name = badString) Assertions.fail("Expecting an illegal argument exception") } catch (e: IllegalArgumentException) { Assertions.assertEquals( - "They query name or tag, $badString, contains an invalid character: [' ','[',']','{','}','(',')']", + "The query name, $badString, should be between 1 - 256 characters.", e.message ) } @@ -64,7 +83,7 @@ class DocLevelMonitorInputTests { Assertions.fail("Expecting an illegal argument exception") } catch (e: IllegalArgumentException) { Assertions.assertEquals( - "They query name or tag, $badString, contains an invalid character: [' ','[',']','{','}','(',')']", + "The query tag, $badString, contains an invalid character: [' ','[',']','{','}','(',')']", e.message ) }