From a300e275d414ccb91179519953cb430558c0491e Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Sat, 3 Apr 2021 00:52:52 +0200 Subject: [PATCH] Valid FindArticles request with Konform --- build.gradle.kts | 6 ++- .../fr/dcproject/common/validation/Uuid.kt | 14 +++++++ .../component/article/routes/FindArticles.kt | 38 ++++++++++++++++++- src/main/resources/openapi.yaml | 2 + 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/fr/dcproject/common/validation/Uuid.kt diff --git a/build.gradle.kts b/build.gradle.kts index 6b07044..2757de5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -327,8 +327,9 @@ dependencyCheck { repositories { mavenLocal() jcenter() - maven { url = uri("https://kotlin.bintray.com/ktor") } - maven { url = uri("https://jitpack.io") } + maven("https://kotlin.bintray.com/ktor") + maven("https://jitpack.io") + maven("https://dl.bintray.com/konform-kt/konform") } dependencies { @@ -359,6 +360,7 @@ dependencies { implementation("org.elasticsearch.client:elasticsearch-rest-client:6.7.1") implementation("com.jayway.jsonpath:json-path:2.5.0") implementation("com.avast.gradle:gradle-docker-compose-plugin:0.14.0") + implementation("io.konform:konform-jvm:0.2.0") testImplementation("io.ktor:ktor-server-tests:$ktorVersion") testImplementation("io.ktor:ktor-client-mock:$ktorVersion") diff --git a/src/main/kotlin/fr/dcproject/common/validation/Uuid.kt b/src/main/kotlin/fr/dcproject/common/validation/Uuid.kt new file mode 100644 index 0000000..93708cd --- /dev/null +++ b/src/main/kotlin/fr/dcproject/common/validation/Uuid.kt @@ -0,0 +1,14 @@ +package fr.dcproject.common.validation + +import io.konform.validation.ValidationBuilder +import java.util.UUID + +fun ValidationBuilder.isUuid() = + addConstraint("must be UUID") { + try { + UUID.fromString(it) + true + } catch (exception: IllegalArgumentException) { + false + } + } diff --git a/src/main/kotlin/fr/dcproject/component/article/routes/FindArticles.kt b/src/main/kotlin/fr/dcproject/component/article/routes/FindArticles.kt index b0b5abd..b90f269 100644 --- a/src/main/kotlin/fr/dcproject/component/article/routes/FindArticles.kt +++ b/src/main/kotlin/fr/dcproject/component/article/routes/FindArticles.kt @@ -2,6 +2,7 @@ package fr.dcproject.component.article.routes import fr.dcproject.common.response.toOutput import fr.dcproject.common.security.assert +import fr.dcproject.common.validation.isUuid import fr.dcproject.component.article.ArticleAccessControl import fr.dcproject.component.article.database.ArticleForListing import fr.dcproject.component.article.database.ArticleRepository @@ -10,7 +11,12 @@ import fr.dcproject.routes.PaginatedRequest import fr.dcproject.routes.PaginatedRequestI import fr.postgresjson.connexion.Paginated import fr.postgresjson.repository.RepositoryI +import io.konform.validation.Validation +import io.konform.validation.jsonschema.enum +import io.konform.validation.jsonschema.maximum +import io.konform.validation.jsonschema.minimum import io.ktor.application.call +import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location import io.ktor.locations.get @@ -28,7 +34,32 @@ object FindArticles { val search: String? = null, val createdBy: String? = null, val workgroup: String? = null - ) : PaginatedRequestI by PaginatedRequest(page, limit) + ) : PaginatedRequestI by PaginatedRequest(page, limit) { + fun validate() = Validation { + ArticlesRequest::page { + minimum(1) + maximum(100) + } + ArticlesRequest::limit { + minimum(1) + maximum(50) + } + ArticlesRequest::sort ifPresent { + enum( + "title", + "createdAt", + "vote", + "popularity", + ) + } + ArticlesRequest::createdBy ifPresent { + isUuid() + } + ArticlesRequest::workgroup ifPresent { + isUuid() + } + }.validate(this) + } private fun ArticleRepository.findArticles(request: ArticlesRequest): Paginated { return find( @@ -43,6 +74,11 @@ object FindArticles { fun Route.findArticles(repo: ArticleRepository, ac: ArticleAccessControl) { get { + if (it.validate().errors.size > 0) { + call.respond(HttpStatusCode.BadRequest) + return@get + } + repo.findArticles(it) .apply { ac.assert { canView(result, citizenOrNull) } } .let { diff --git a/src/main/resources/openapi.yaml b/src/main/resources/openapi.yaml index b204c7e..386e9e7 100644 --- a/src/main/resources/openapi.yaml +++ b/src/main/resources/openapi.yaml @@ -41,6 +41,8 @@ paths: maxItems: 50 items: $ref: '#/components/schemas/ArticleListingResponse' + 400: + $ref: '#/components/responses/400' post: security: - JWTAuth: []