Skip to content

Commit 17601a7

Browse files
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
1 parent b3c2d5f commit 17601a7

5 files changed

Lines changed: 70 additions & 4 deletions

File tree

‎docs/03-apis/api-admin/projects.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ License along with DSP. If not, see <http://www.gnu.org/licenses/>.
6161
- Required information:
6262
- shortcode (unique, 4-digits)
6363
- shortname (unique; it should be in the form of a
64-
[xsd:NCNAME](https://www.w3.org/TR/xmlschema11-2/#NCName))
64+
[xsd:NCNAME](https://www.w3.org/TR/xmlschema11-2/#NCName) and it should be URL safe.)
6565
- description (collection of descriptions as strings with language tag.)
6666
- keywords (collection of keywords)
6767
- status (true, if project is active. false, if project is inactive)

‎docs/03-apis/api-v2/knora-iris.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ http://www.knora.org/ontology/0001/example
6868
```
6969

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

7474
- `knora-base`

‎webapi/src/main/scala/org/knora/webapi/messages/StringFormatter.scala‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,8 @@ class StringFormatter private (val maybeSettings: Option[KnoraSettingsImpl] = No
852852
// RFC 4648.
853853
private val Base64UrlPattern = "[A-Za-z0-9_-]+"
854854

855+
private val Base64UrlPatternRegex: Regex = ("^" + Base64UrlPattern + "$").r
856+
855857
// Calculates check digits for resource IDs in ARK URLs.
856858
private val base64UrlCheckDigit = new Base64UrlCheckDigit
857859

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

2187+
// Check that ontology name is URL safe
2188+
ontologyName match {
2189+
case Base64UrlPatternRegex(_*) => ()
2190+
case _ => errorFun
2191+
}
2192+
21842193
val lowerCaseOntologyName = ontologyName.toLowerCase
21852194

21862195
lowerCaseOntologyName match {
@@ -2481,8 +2490,14 @@ class StringFormatter private (val maybeSettings: Option[KnoraSettingsImpl] = No
24812490
* project shortname.
24822491
* @return the same string.
24832492
*/
2484-
def validateAndEscapeProjectShortname(value: String, errorFun: => Nothing): String = {
2485-
NCNameRegex.findFirstIn(value) match {
2493+
def validateAndEscapeProjectShortname(shortname: String, errorFun: => Nothing): String = {
2494+
// Check that shortname matches NCName pattern
2495+
val ncNameMatch = NCNameRegex.findFirstIn(shortname) match {
2496+
case Some(value) => value
2497+
case None => errorFun
2498+
}
2499+
// Check that shortname is URL safe
2500+
Base64UrlPatternRegex.findFirstIn(ncNameMatch) match {
24862501
case Some(shortname) => toSparqlEncodedString(shortname, errorFun)
24872502
case None => errorFun
24882503
}

‎webapi/src/test/scala/org/knora/webapi/messages/admin/responder/projectsmessages/ProjectsMessagesADMSpec.scala‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,40 @@ class ProjectsMessagesADMSpec extends CoreSpec(ProjectsMessagesADMSpec.config) {
108108
)
109109
assert(caught.getMessage === "Project shortcode must be supplied.")
110110
}
111+
112+
"return 'BadRequestException' if project 'shortname' is not NCName valid" in {
113+
val invalidShortName = "abd%2"
114+
val caught = intercept[BadRequestException](
115+
CreateProjectApiRequestADM(
116+
shortname = invalidShortName,
117+
shortcode = "1114",
118+
longname = Some("project longname"),
119+
description = Seq(StringLiteralV2(value = "project description", language = Some("en"))),
120+
keywords = Seq("keywords"),
121+
logo = Some("/fu/bar/baz.jpg"),
122+
status = true,
123+
selfjoin = false
124+
).validateAndEscape
125+
)
126+
assert(caught.getMessage === s"The supplied short name: '$invalidShortName' is not valid.")
127+
}
128+
129+
"return 'BadRequestException' if project 'shortname' is not URL safe" in {
130+
val invalidShortName = "äbd2"
131+
val caught = intercept[BadRequestException](
132+
CreateProjectApiRequestADM(
133+
shortname = invalidShortName,
134+
shortcode = "1114",
135+
longname = Some("project longname"),
136+
description = Seq(StringLiteralV2(value = "project description", language = Some("en"))),
137+
keywords = Seq("keywords"),
138+
logo = Some("/fu/bar/baz.jpg"),
139+
status = true,
140+
selfjoin = false
141+
).validateAndEscape
142+
)
143+
assert(caught.getMessage === s"The supplied short name: '$invalidShortName' is not valid.")
144+
}
111145
}
112146

113147
"The ChangeProjectApiRequestADM case class" should {

‎webapi/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,23 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender {
245245
fooLastModDate = newFooLastModDate
246246
}
247247

248+
"not create an ontology if the given name matches NCName pattern but is not URL safe" in {
249+
responderManager ! CreateOntologyRequestV2(
250+
ontologyName = "bär",
251+
projectIri = imagesProjectIri,
252+
label = "The bär ontology",
253+
comment = Some("some comment"),
254+
apiRequestID = UUID.randomUUID,
255+
featureFactoryConfig = defaultFeatureFactoryConfig,
256+
requestingUser = imagesUser
257+
)
258+
259+
expectMsgPF(timeout) {
260+
case msg: akka.actor.Status.Failure =>
261+
msg.cause.isInstanceOf[BadRequestException] should ===(true)
262+
}
263+
}
264+
248265
"create an empty ontology called 'bar' with a comment" in {
249266
responderManager ! CreateOntologyRequestV2(
250267
ontologyName = "bar",

0 commit comments

Comments
 (0)