Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(api-v2, api-admin): ontology name and project name should be URL …
…safe (DSP-1749) (#1889)

* fix: ontology name and project name should be URL safe

* docs (ontologProjectName): add docs
  • Loading branch information
SepidehAlassi committed Jul 14, 2021
1 parent b3c2d5f commit 17601a7
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 4 deletions.
2 changes: 1 addition & 1 deletion docs/03-apis/api-admin/projects.md
Expand Up @@ -61,7 +61,7 @@ License along with DSP. If not, see <http://www.gnu.org/licenses/>.
- Required information:
- shortcode (unique, 4-digits)
- shortname (unique; it should be in the form of a
[xsd:NCNAME](https://www.w3.org/TR/xmlschema11-2/#NCName))
[xsd:NCNAME](https://www.w3.org/TR/xmlschema11-2/#NCName) and it should be URL safe.)
- description (collection of descriptions as strings with language tag.)
- keywords (collection of keywords)
- status (true, if project is active. false, if project is inactive)
Expand Down
2 changes: 1 addition & 1 deletion docs/03-apis/api-v2/knora-iris.md
Expand Up @@ -68,7 +68,7 @@ http://www.knora.org/ontology/0001/example
```

An ontology name must be a valid XML
[NCName](https://www.w3.org/TR/xml-names/#NT-NCName).
[NCName](https://www.w3.org/TR/xml-names/#NT-NCName) and must be URL safe.
The following names are reserved for built-in internal DSP ontologies:

- `knora-base`
Expand Down
Expand Up @@ -852,6 +852,8 @@ class StringFormatter private (val maybeSettings: Option[KnoraSettingsImpl] = No
// RFC 4648.
private val Base64UrlPattern = "[A-Za-z0-9_-]+"

private val Base64UrlPatternRegex: Regex = ("^" + Base64UrlPattern + "$").r

// Calculates check digits for resource IDs in ARK URLs.
private val base64UrlCheckDigit = new Base64UrlCheckDigit

Expand Down Expand Up @@ -2176,11 +2178,18 @@ class StringFormatter private (val maybeSettings: Option[KnoraSettingsImpl] = No
* @return the same ontology name.
*/
def validateProjectSpecificOntologyName(ontologyName: String, errorFun: => Nothing): String = {
// Check that ontology name matched NCName regex pattern
ontologyName match {
case NCNameRegex(_*) => ()
case _ => errorFun
}

// Check that ontology name is URL safe
ontologyName match {
case Base64UrlPatternRegex(_*) => ()
case _ => errorFun
}

val lowerCaseOntologyName = ontologyName.toLowerCase

lowerCaseOntologyName match {
Expand Down Expand Up @@ -2481,8 +2490,14 @@ class StringFormatter private (val maybeSettings: Option[KnoraSettingsImpl] = No
* project shortname.
* @return the same string.
*/
def validateAndEscapeProjectShortname(value: String, errorFun: => Nothing): String = {
NCNameRegex.findFirstIn(value) match {
def validateAndEscapeProjectShortname(shortname: String, errorFun: => Nothing): String = {
// Check that shortname matches NCName pattern
val ncNameMatch = NCNameRegex.findFirstIn(shortname) match {
case Some(value) => value
case None => errorFun
}
// Check that shortname is URL safe
Base64UrlPatternRegex.findFirstIn(ncNameMatch) match {
case Some(shortname) => toSparqlEncodedString(shortname, errorFun)
case None => errorFun
}
Expand Down
Expand Up @@ -108,6 +108,40 @@ class ProjectsMessagesADMSpec extends CoreSpec(ProjectsMessagesADMSpec.config) {
)
assert(caught.getMessage === "Project shortcode must be supplied.")
}

"return 'BadRequestException' if project 'shortname' is not NCName valid" in {
val invalidShortName = "abd%2"
val caught = intercept[BadRequestException](
CreateProjectApiRequestADM(
shortname = invalidShortName,
shortcode = "1114",
longname = Some("project longname"),
description = Seq(StringLiteralV2(value = "project description", language = Some("en"))),
keywords = Seq("keywords"),
logo = Some("/fu/bar/baz.jpg"),
status = true,
selfjoin = false
).validateAndEscape
)
assert(caught.getMessage === s"The supplied short name: '$invalidShortName' is not valid.")
}

"return 'BadRequestException' if project 'shortname' is not URL safe" in {
val invalidShortName = "äbd2"
val caught = intercept[BadRequestException](
CreateProjectApiRequestADM(
shortname = invalidShortName,
shortcode = "1114",
longname = Some("project longname"),
description = Seq(StringLiteralV2(value = "project description", language = Some("en"))),
keywords = Seq("keywords"),
logo = Some("/fu/bar/baz.jpg"),
status = true,
selfjoin = false
).validateAndEscape
)
assert(caught.getMessage === s"The supplied short name: '$invalidShortName' is not valid.")
}
}

"The ChangeProjectApiRequestADM case class" should {
Expand Down
Expand Up @@ -245,6 +245,23 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender {
fooLastModDate = newFooLastModDate
}

"not create an ontology if the given name matches NCName pattern but is not URL safe" in {
responderManager ! CreateOntologyRequestV2(
ontologyName = "bär",
projectIri = imagesProjectIri,
label = "The bär ontology",
comment = Some("some comment"),
apiRequestID = UUID.randomUUID,
featureFactoryConfig = defaultFeatureFactoryConfig,
requestingUser = imagesUser
)

expectMsgPF(timeout) {
case msg: akka.actor.Status.Failure =>
msg.cause.isInstanceOf[BadRequestException] should ===(true)
}
}

"create an empty ontology called 'bar' with a comment" in {
responderManager ! CreateOntologyRequestV2(
ontologyName = "bar",
Expand Down

0 comments on commit 17601a7

Please sign in to comment.