Skip to content
Permalink
Browse files

fix(api-v2): Don't check file extensions of XSL files and Gravsearch …

…templates (DSP-1005) (#1749)
  • Loading branch information
benjamingeer committed Nov 5, 2020
1 parent 43ff213 commit 905766fe054ba25db6296d57915bf0cf330b521c
@@ -315,9 +315,9 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

# publish only on release
# publish on merge to main
publish:
name: Publish (on release only)
name: Publish (on merge to main)
needs: [
api-unit-tests,
api-e2e-tests,
@@ -326,7 +326,7 @@ jobs:
docs-build-test
]
runs-on: ubuntu-latest
if: github.event_name == 'release' && startsWith(github.ref, 'refs/tags')
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v1
with:
@@ -1336,20 +1336,20 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt
throw BadRequestException(s"Resource $gravsearchTemplateIri is not a Gravsearch template (text file expected)")
}

gravsearchFileValueContent: TextFileValueContentV2 = resource.values.get(OntologyConstants.KnoraBase.HasTextFileValue.toSmartIri) match {
(fileValueIri: IRI, gravsearchFileValueContent: TextFileValueContentV2) = resource.values.get(OntologyConstants.KnoraBase.HasTextFileValue.toSmartIri) match {
case Some(values: Seq[ReadValueV2]) if values.size == 1 => values.head match {
case value: ReadValueV2 => value.valueContent match {
case textRepr: TextFileValueContentV2 => textRepr
case textRepr: TextFileValueContentV2 => (value.valueIri, textRepr)
case _ => throw InconsistentTriplestoreDataException(s"Resource $gravsearchTemplateIri is supposed to have exactly one value of type ${OntologyConstants.KnoraBase.TextFileValue}")
}
}

case None => throw InconsistentTriplestoreDataException(s"Resource $gravsearchTemplateIri has no property ${OntologyConstants.KnoraBase.HasTextFileValue}")
}

// check if `xsltFileValue` represents an XSL transformation
_ = if (!(gravsearchFileValueContent.fileValue.internalMimeType == "text/plain" && gravsearchFileValueContent.fileValue.internalFilename.endsWith(".txt"))) {
throw BadRequestException(s"Resource $gravsearchTemplateIri does not have a file value referring to a Gravsearch template")
// check if gravsearchFileValueContent represents a text file
_ = if (gravsearchFileValueContent.fileValue.internalMimeType != "text/plain") {
throw BadRequestException(s"Expected $fileValueIri to be a text file referring to a Gravsearch template, but it has MIME type ${gravsearchFileValueContent.fileValue.internalMimeType}")
}

gravsearchUrl: String = s"${settings.internalSipiBaseUrl}/${resource.projectADM.shortcode}/${gravsearchFileValueContent.fileValue.internalFilename}/file"
@@ -173,20 +173,20 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon
throw BadRequestException(s"Resource $xslTransformationIri is not a ${OntologyConstants.KnoraBase.XSLTransformation}")
}

xsltFileValueContent: TextFileValueContentV2 = resource.values.get(OntologyConstants.KnoraBase.HasTextFileValue.toSmartIri) match {
(fileValueIri: IRI, xsltFileValueContent: TextFileValueContentV2) = resource.values.get(OntologyConstants.KnoraBase.HasTextFileValue.toSmartIri) match {
case Some(values: Seq[ReadValueV2]) if values.size == 1 => values.head match {
case value: ReadValueV2 => value.valueContent match {
case textRepr: TextFileValueContentV2 => textRepr
case textRepr: TextFileValueContentV2 => (value.valueIri, textRepr)
case _ => throw InconsistentTriplestoreDataException(s"${OntologyConstants.KnoraBase.XSLTransformation} $xslTransformationIri is supposed to have exactly one value of type ${OntologyConstants.KnoraBase.TextFileValue}")
}
}

case None => throw InconsistentTriplestoreDataException(s"${OntologyConstants.KnoraBase.XSLTransformation} has no property ${OntologyConstants.KnoraBase.HasTextFileValue}")
}

// check if xsltFileValue represents an XSL transformation
_ = if (!(xmlMimeTypes.contains(xsltFileValueContent.fileValue.internalMimeType) && xsltFileValueContent.fileValue.internalFilename.endsWith(".xsl"))) {
throw BadRequestException(s"$xslTransformationIri does not have a file value referring to an XSL transformation")
// check if xsltFileValueContent represents an XSL transformation
_ = if (!xmlMimeTypes.contains(xsltFileValueContent.fileValue.internalMimeType)) {
throw BadRequestException(s"Expected $fileValueIri to be an XML file referring to an XSL transformation, but it has MIME type ${xsltFileValueContent.fileValue.internalMimeType}")
}

xsltUrl: String = s"${settings.internalSipiBaseUrl}/${resource.projectADM.shortcode}/${xsltFileValueContent.fileValue.internalFilename}/file"
@@ -27,7 +27,7 @@ import org.knora.webapi.feature.FeatureFactoryConfig
import org.knora.webapi.messages.IriConversions._
import org.knora.webapi.messages.util.search.gravsearch.GravsearchParser
import org.knora.webapi.messages.v2.responder.searchmessages._
import org.knora.webapi.messages.{SmartIri, StringFormatter}
import org.knora.webapi.messages.{OntologyConstants, SmartIri, StringFormatter}
import org.knora.webapi.routing.{Authenticator, KnoraRoute, KnoraRouteData, RouteUtilV2}

import scala.concurrent.Future
@@ -152,13 +152,17 @@ class SearchRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
}

private def fullTextSearchCount(featureFactoryConfig: FeatureFactoryConfig): Route = path("v2" / "search" / "count" / Segment) { searchval => // TODO: if a space is encoded as a "+", this is not converted back to a space
private def fullTextSearchCount(featureFactoryConfig: FeatureFactoryConfig): Route = path("v2" / "search" / "count" / Segment) { searchStr => // TODO: if a space is encoded as a "+", this is not converted back to a space
get {
requestContext =>
val searchString = stringFormatter.toSparqlEncodedString(searchval, throw BadRequestException(s"Invalid search string: '$searchval'"))
if (searchStr.contains(OntologyConstants.KnoraApi.ApiOntologyHostname)) {
throw BadRequestException("It looks like you are submitting a Gravsearch request to a full-text search route")
}

if (searchString.length < settings.searchValueMinLength) {
throw BadRequestException(s"A search value is expected to have at least length of ${settings.searchValueMinLength}, but '$searchString' given of length ${searchString.length}.")
val escapedSearchStr = stringFormatter.toSparqlEncodedString(searchStr, throw BadRequestException(s"Invalid search string: '$searchStr'"))

if (escapedSearchStr.length < settings.searchValueMinLength) {
throw BadRequestException(s"A search value is expected to have at least length of ${settings.searchValueMinLength}, but '$escapedSearchStr' given of length ${escapedSearchStr.length}.")
}

val params: Map[String, String] = requestContext.request.uri.query().toMap
@@ -172,7 +176,7 @@ class SearchRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
val requestMessage: Future[FullTextSearchCountRequestV2] = for {
requestingUser <- getUserADM(requestContext)
} yield FullTextSearchCountRequestV2(
searchValue = searchString,
searchValue = escapedSearchStr,
limitToProject = limitToProject,
limitToResourceClass = limitToResourceClass,
limitToStandoffClass = limitToStandoffClass,
@@ -192,13 +196,17 @@ class SearchRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
}
}

private def fullTextSearch(featureFactoryConfig: FeatureFactoryConfig): Route = path("v2" / "search" / Segment) { searchval => // TODO: if a space is encoded as a "+", this is not converted back to a space
private def fullTextSearch(featureFactoryConfig: FeatureFactoryConfig): Route = path("v2" / "search" / Segment) { searchStr => // TODO: if a space is encoded as a "+", this is not converted back to a space
get {
requestContext => {
val searchString = stringFormatter.toSparqlEncodedString(searchval, throw BadRequestException(s"Invalid search string: '$searchval'"))
if (searchStr.contains(OntologyConstants.KnoraApi.ApiOntologyHostname)) {
throw BadRequestException("It looks like you are submitting a Gravsearch request to a full-text search route")
}

if (searchString.length < settings.searchValueMinLength) {
throw BadRequestException(s"A search value is expected to have at least length of ${settings.searchValueMinLength}, but '$searchString' given of length ${searchString.length}.")
val escapedSearchStr = stringFormatter.toSparqlEncodedString(searchStr, throw BadRequestException(s"Invalid search string: '$searchStr'"))

if (escapedSearchStr.length < settings.searchValueMinLength) {
throw BadRequestException(s"A search value is expected to have at least length of ${settings.searchValueMinLength}, but '$escapedSearchStr' given of length ${escapedSearchStr.length}.")
}

val params: Map[String, String] = requestContext.request.uri.query().toMap
@@ -217,7 +225,7 @@ class SearchRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit
val requestMessage: Future[FulltextSearchRequestV2] = for {
requestingUser <- getUserADM(requestContext)
} yield FulltextSearchRequestV2(
searchValue = searchString,
searchValue = escapedSearchStr,
offset = offset,
limitToProject = limitToProject,
limitToResourceClass = limitToResourceClass,
@@ -198,6 +198,16 @@ class SearchRouteV2R2RSpec extends R2RSpec {
}
}

"not accept a fulltext query containing http://api.knora.org" in {
val invalidSearchString: String = URLEncoder.encode("PREFIX knora-api: <http://api.knora.org/ontology/knora-api/v2#>", "UTF-8")

Get(s"/v2/search/$invalidSearchString") ~> searchPath ~> check {
val responseStr = responseAs[String]
assert(status == StatusCodes.BAD_REQUEST, responseStr)
assert(responseStr.contains("It looks like you are submitting a Gravsearch request to a full-text search route"))
}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Queries without type inference

0 comments on commit 905766f

Please sign in to comment.