diff --git a/src/main/java/io/stargate/sgv2/jsonapi/StargateJsonApi.java b/src/main/java/io/stargate/sgv2/jsonapi/StargateJsonApi.java index a0a99289c9..74a2022359 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/StargateJsonApi.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/StargateJsonApi.java @@ -45,14 +45,22 @@ in = ParameterIn.PATH, name = "namespace", required = true, - schema = @Schema(implementation = String.class, pattern = "\\w+"), + schema = + @Schema( + implementation = String.class, + pattern = "[a-zA-Z][a-zA-Z0-9_]*", + maxLength = 48), description = "The namespace where the collection is located.", example = "cycling"), @Parameter( in = ParameterIn.PATH, name = "collection", required = true, - schema = @Schema(implementation = String.class, pattern = "\\w+"), + schema = + @Schema( + implementation = String.class, + pattern = "[a-zA-Z][a-zA-Z0-9_]*", + maxLength = 48), description = "The name of the collection.", example = "events") }, diff --git a/src/main/java/io/stargate/sgv2/jsonapi/api/v1/CollectionResource.java b/src/main/java/io/stargate/sgv2/jsonapi/api/v1/CollectionResource.java index efb988e525..afbbf71a04 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/api/v1/CollectionResource.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/api/v1/CollectionResource.java @@ -21,6 +21,8 @@ import javax.inject.Inject; import javax.validation.Valid; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -127,8 +129,16 @@ public CollectionResource(CommandProcessor commandProcessor) { @POST public Uni> postCommand( @NotNull @Valid CollectionCommand command, - @PathParam("namespace") String namespace, - @PathParam("collection") String collection) { + @PathParam("namespace") + @NotNull + @Pattern(regexp = "[a-zA-Z][a-zA-Z0-9_]*") + @Size(min = 1, max = 48) + String namespace, + @PathParam("collection") + @NotNull + @Pattern(regexp = "[a-zA-Z][a-zA-Z0-9_]*") + @Size(min = 1, max = 48) + String collection) { // create context CommandContext commandContext = new CommandContext(namespace, collection); diff --git a/src/main/java/io/stargate/sgv2/jsonapi/api/v1/NamespaceResource.java b/src/main/java/io/stargate/sgv2/jsonapi/api/v1/NamespaceResource.java index 26f2a933f6..d56574c57c 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/api/v1/NamespaceResource.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/api/v1/NamespaceResource.java @@ -10,6 +10,8 @@ import javax.inject.Inject; import javax.validation.Valid; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -75,7 +77,12 @@ public NamespaceResource(CommandProcessor commandProcessor) { }))) @POST public Uni> postCommand( - @NotNull @Valid NamespaceCommand command, @PathParam("namespace") String namespace) { + @NotNull @Valid NamespaceCommand command, + @PathParam("namespace") + @NotNull + @Pattern(regexp = "[a-zA-Z][a-zA-Z0-9_]*") + @Size(min = 1, max = 48) + String namespace) { // create context CommandContext commandContext = new CommandContext(namespace, null); diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CollectionResourceIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CollectionResourceIntegrationTest.java index 176c74d2ce..6e0f9215ed 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CollectionResourceIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CollectionResourceIntegrationTest.java @@ -65,11 +65,11 @@ public void malformedBody() { public void unknownCommand() { String json = """ - { - "unknownCommand": { - } - } - """; + { + "unknownCommand": { + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) @@ -83,6 +83,56 @@ public void unknownCommand() { .body("errors[0].exceptionClass", is("InvalidTypeIdException")); } + @Test + public void invalidNamespaceName() { + String json = + """ + { + "insertOne": { + "document": {} + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, "7_no_leading_number", collectionName) + .then() + .statusCode(200) + .body( + "errors[0].message", + startsWith("Request invalid, the field postCommand.namespace not valid")) + .body("errors[0].exceptionClass", is("ConstraintViolationException")); + } + + @Test + public void invalidCollectionName() { + String json = + """ + { + "insertOne": { + "document": {} + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), "7_no_leading_number") + .then() + .statusCode(200) + .body( + "errors[0].message", + startsWith("Request invalid, the field postCommand.collection not valid")) + .body("errors[0].exceptionClass", is("ConstraintViolationException")); + } + @Test public void emptyBody() { given() diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/NamespaceResourceIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/NamespaceResourceIntegrationTest.java index 2fe1db0201..7ce575a1f8 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/NamespaceResourceIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/NamespaceResourceIntegrationTest.java @@ -81,6 +81,31 @@ public void unknownCommand() { .body("errors[0].exceptionClass", is("InvalidTypeIdException")); } + @Test + public void invalidNamespaceName() { + String json = + """ + { + "createCollection": { + "name": "ignore_me" + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(NamespaceResource.BASE_PATH, "7_no_leading_number") + .then() + .statusCode(200) + .body( + "errors[0].message", + startsWith("Request invalid, the field postCommand.namespace not valid")) + .body("errors[0].exceptionClass", is("ConstraintViolationException")); + } + @Test public void emptyBody() { given()