Skip to content

Commit

Permalink
fix: Fix escaping issues in labels, add fuzz testing to make sure (DE…
Browse files Browse the repository at this point in the history
  • Loading branch information
siers authored Aug 20, 2024
1 parent fe6dae1 commit ae8f44a
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 26 deletions.
2 changes: 2 additions & 0 deletions integration/src/test/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ app {
}

reload-on-start = false

is-test-env = true
}

features {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
package org.knora.webapi.e2e.v2

import org.apache.pekko
import spray.json.JsString

import java.net.URLEncoder
import java.time.Instant
import scala.concurrent.ExecutionContextExecutor
import scala.util.Random

import dsp.constants.SalsahGui
import dsp.errors.BadRequestException
Expand Down Expand Up @@ -2790,6 +2792,13 @@ class OntologyV2R2RSpec extends R2RSpec {

// Create a resource of #BlueTestClass using only #hasBlueTestIntProp

val resourceLabel: String = {
val fuzz1 = Random.nextString(1000)
val fuzz2 = List.fill(1000)(()).map(_ => Random.nextInt(128).toChar).mkString
val fuzz3 = List.fill(1000)(()).map(_ => Random.nextPrintableChar()).mkString
fuzz1 ++ fuzz2 ++ fuzz3
}

val createResourceWithValues: String =
s"""{
| "@type" : "freetest:BlueFreeTestClass",
Expand All @@ -2802,7 +2811,7 @@ class OntologyV2R2RSpec extends R2RSpec {
| "knora-api:attachedToProject" : {
| "@id" : "http://rdfh.ch/projects/0001"
| },
| "rdfs:label" : "my blue test class thing instance",
| "rdfs:label" : ${JsString(resourceLabel).toString},
| "@context" : {
| "rdf" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
| "knora-api" : "http://api.knora.org/ontology/knora-api/v2#",
Expand All @@ -2818,10 +2827,15 @@ class OntologyV2R2RSpec extends R2RSpec {
) ~> addCredentials(BasicHttpCredentials(anythingUsername, password)) ~> resourcesPath ~> check {
val responseStr = responseAs[String]
assert(status == StatusCodes.OK, responseStr)

val responseJsonDoc = JsonLDUtil.parseJsonLD(responseStr)
val validationFun: (String, => Nothing) => String = (s, e) => Iri.validateAndEscapeIri(s).getOrElse(e)
val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, validationFun)
assert(resourceIri.toSmartIri.isKnoraDataIri)

val responseJsonDoc2 = JsonLDUtil.parseJsonLD(responseStr)
val label = responseJsonDoc2.body.value.get(OntologyConstants.Rdfs.Label).get
assert(label == JsonLDString(resourceLabel))
}

// payload to test cardinality can't be deleted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ final case class Triplestore(
autoInit: Boolean,
fuseki: Fuseki,
profileQueries: Boolean,
isTestEnv: Boolean = false,
)

final case class Fuseki(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ object CreateResourceRequestV2 {

// Get the resource's rdfs:label.
label <-
ZIO.attempt(jsonLDDocument.body.requireStringWithValidation(Rdfs.Label, validationFun))
ZIO.attempt(jsonLDDocument.body.requireStringWithValidation(Rdfs.Label, (s, _) => s))

// Get information about the project that the resource should be created in.
projectIri <- ZIO.attempt(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ final case class CreateResourceV2Handler(
private def makeTask(
createResourceRequestV2: CreateResourceRequestV2,
resourceIri: IRI,
): Task[ReadResourcesSequenceV2] = {
): Task[ReadResourcesSequenceV2] =
for {
_ <- // check if resourceIri already exists holding a lock on the IRI
ZIO
Expand Down Expand Up @@ -219,44 +219,35 @@ final case class CreateResourceV2Handler(
)

// Get the default permissions of the resource class.

defaultResourcePermissionsMap <- getResourceClassDefaultPermissions(
projectIri = createResourceRequestV2.createResource.projectADM.id,
resourceClassIris = Set(internalCreateResource.resourceClassIri),
requestingUser = createResourceRequestV2.requestingUser,
)

defaultResourcePermissions: String = defaultResourcePermissionsMap(internalCreateResource.resourceClassIri)

// Get the default permissions of each property used.

defaultPropertyPermissionsMap <- getDefaultPropertyPermissions(
projectIri = createResourceRequestV2.createResource.projectADM.id,
resourceClassProperties = Map(
internalCreateResource.resourceClassIri -> internalCreateResource.values.keySet,
),
requestingUser = createResourceRequestV2.requestingUser,
)
defaultPropertyPermissions: Map[SmartIri, String] = defaultPropertyPermissionsMap(
internalCreateResource.resourceClassIri,
)

// Make a versionDate for the resource and its values.
creationDate: Instant = internalCreateResource.creationDate.getOrElse(Instant.now)

// Do the remaining pre-update checks and make a ResourceReadyToCreate describing the SPARQL
// for creating the resource.
resourceReadyToCreate <- generateResourceReadyToCreate(
resourceIri = resourceIri,
internalCreateResource = internalCreateResource,
linkTargetClasses = linkTargetClasses,
entityInfo = allEntityInfo,
clientResourceIDs = Map.empty[IRI, String],
defaultResourcePermissions = defaultResourcePermissions,
defaultPropertyPermissions = defaultPropertyPermissions,
creationDate = creationDate,
requestingUser = createResourceRequestV2.requestingUser,
)
resourceReadyToCreate <-
generateResourceReadyToCreate(
resourceIri = resourceIri,
internalCreateResource = internalCreateResource,
linkTargetClasses = linkTargetClasses,
entityInfo = allEntityInfo,
clientResourceIDs = Map.empty[IRI, String],
defaultResourcePermissions = defaultResourcePermissionsMap(internalCreateResource.resourceClassIri),
defaultPropertyPermissions = defaultPropertyPermissionsMap(internalCreateResource.resourceClassIri),
creationDate = internalCreateResource.creationDate.getOrElse(Instant.now),
requestingUser = createResourceRequestV2.requestingUser,
)

dataNamedGraph = ProjectService.projectDataNamedGraphV2(createResourceRequestV2.createResource.projectADM)

Expand All @@ -273,7 +264,6 @@ final case class CreateResourceV2Handler(
requestingUser = createResourceRequestV2.requestingUser,
)
} yield previewOfCreatedResource
}

/**
* Generates a [[ResourceReadyToCreate]] describing SPARQL for creating a resource and its values.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ case class TriplestoreServiceLive(
_ <- {
val endTime = java.lang.System.nanoTime()
val duration = Duration.fromNanos(endTime - startTime)
ZIO.when(duration >= trackingThreshold) {
ZIO.when(!triplestoreConfig.isTestEnv && duration >= trackingThreshold) {
ZIO.logInfo(
s"Fuseki request took $duration, which is longer than $trackingThreshold, timeout=${query.timeout}\n ${query.sparql}",
)
Expand Down

0 comments on commit ae8f44a

Please sign in to comment.