@cyclonedx/cyclonedx-library 6.1.3 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyclonedx/cyclonedx-library",
3
- "version": "6.1.3",
3
+ "version": "6.2.0",
4
4
  "description": "Core functionality of CycloneDX for JavaScript (Node.js or WebBrowser).",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -0,0 +1,51 @@
1
+ /*!
2
+ This file is part of CycloneDX JavaScript Library.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+
16
+ SPDX-License-Identifier: Apache-2.0
17
+ Copyright (c) OWASP Foundation. All Rights Reserved.
18
+ */
19
+
20
+ const escapeMap: Readonly<Record<string, string>> = Object.freeze({
21
+ ' ': '%20',
22
+ '[': '%5B',
23
+ ']': '%5D',
24
+ '<': '%3C',
25
+ '>': '%3E',
26
+ '{': '%7B',
27
+ '}': '%7D'
28
+ })
29
+
30
+ /**
31
+ * Make a string valid to
32
+ * - XML::anyURI spec.
33
+ * - JSON::iri-reference spec.
34
+ *
35
+ * BEST EFFORT IMPLEMENTATION
36
+ *
37
+ * @see http://www.w3.org/TR/xmlschema-2/#anyURI
38
+ * @see http://www.datypic.com/sc/xsd/t-xsd_anyURI.html
39
+ * @see https://datatracker.ietf.org/doc/html/rfc2396
40
+ * @see https://datatracker.ietf.org/doc/html/rfc3987
41
+ */
42
+ export function escapeUri<T extends (string | undefined)> (value: T): T {
43
+ if (value === undefined) {
44
+ return value
45
+ }
46
+ for (const [s, r] of Object.entries(escapeMap)) {
47
+ /* @ts-expect-error -- TS does not properly detect that value is to be forced as string, here */
48
+ value = value.replace(s, r)
49
+ }
50
+ return value
51
+ }
@@ -21,6 +21,7 @@ import { isNotUndefined } from '../../_helpers/notUndefined'
21
21
  import type { SortableIterable } from '../../_helpers/sortable'
22
22
  import type { Stringable } from '../../_helpers/stringable'
23
23
  import { treeIteratorSymbol } from '../../_helpers/tree'
24
+ import { escapeUri } from '../../_helpers/uri'
24
25
  import * as Models from '../../models'
25
26
  import { isSupportedSpdxId } from '../../spdx'
26
27
  import { Version as SpecVersion } from '../../spec'
@@ -311,8 +312,10 @@ export class OrganizationalContactNormalizer extends BaseJsonNormalizer<Models.O
311
312
 
312
313
  export class OrganizationalEntityNormalizer extends BaseJsonNormalizer<Models.OrganizationalEntity> {
313
314
  normalize (data: Models.OrganizationalEntity, options: NormalizerOptions): Normalized.OrganizationalEntity {
314
- const urls = normalizeStringableIter(data.url, options)
315
- .filter(JsonSchema.isIriReference)
315
+ const urls = normalizeStringableIter(
316
+ Array.from(data.url, (s) => escapeUri(s.toString())),
317
+ options
318
+ ).filter(JsonSchema.isIriReference)
316
319
  return {
317
320
  name: data.name || undefined,
318
321
  url: urls.length > 0
@@ -438,7 +441,7 @@ export class LicenseNormalizer extends BaseJsonNormalizer<Models.License> {
438
441
  }
439
442
 
440
443
  #normalizeNamedLicense (data: Models.NamedLicense, options: NormalizerOptions): Normalized.NamedLicense {
441
- const url = data.url?.toString()
444
+ const url = escapeUri(data.url?.toString())
442
445
  return {
443
446
  license: {
444
447
  name: data.name,
@@ -453,13 +456,16 @@ export class LicenseNormalizer extends BaseJsonNormalizer<Models.License> {
453
456
  }
454
457
 
455
458
  #normalizeSpdxLicense (data: Models.SpdxLicense, options: NormalizerOptions): Normalized.SpdxLicense {
459
+ const url = escapeUri(data.url?.toString())
456
460
  return {
457
461
  license: {
458
462
  id: data.id,
459
463
  text: data.text === undefined
460
464
  ? undefined
461
465
  : this._factory.makeForAttachment().normalize(data.text, options),
462
- url: data.url?.toString()
466
+ url: JsonSchema.isIriReference(url)
467
+ ? url
468
+ : undefined
463
469
  }
464
470
  }
465
471
  }
@@ -493,7 +499,7 @@ export class LicenseNormalizer extends BaseJsonNormalizer<Models.License> {
493
499
 
494
500
  export class SWIDNormalizer extends BaseJsonNormalizer<Models.SWID> {
495
501
  normalize (data: Models.SWID, options: NormalizerOptions): Normalized.SWID {
496
- const url = data.url?.toString()
502
+ const url = escapeUri(data.url?.toString())
497
503
  return {
498
504
  tagId: data.tagId,
499
505
  name: data.name,
@@ -514,7 +520,7 @@ export class ExternalReferenceNormalizer extends BaseJsonNormalizer<Models.Exter
514
520
  normalize (data: Models.ExternalReference, options: NormalizerOptions): Normalized.ExternalReference | undefined {
515
521
  return this._factory.spec.supportsExternalReferenceType(data.type)
516
522
  ? {
517
- url: data.url.toString(),
523
+ url: escapeUri(data.url.toString()),
518
524
  type: data.type,
519
525
  hashes: this._factory.spec.supportsExternalReferenceHashes && data.hashes.size > 0
520
526
  ? this._factory.makeForHash().normalizeIterable(data.hashes, options)
@@ -726,7 +732,7 @@ export class VulnerabilityRatingNormalizer extends BaseJsonNormalizer<Models.Vul
726
732
 
727
733
  export class VulnerabilityAdvisoryNormalizer extends BaseJsonNormalizer<Models.Vulnerability.Advisory> {
728
734
  normalize (data: Models.Vulnerability.Advisory, options: NormalizerOptions): Normalized.Vulnerability.Advisory | undefined {
729
- const url = data.url.toString()
735
+ const url = escapeUri(data.url.toString())
730
736
  if (!JsonSchema.isIriReference(url)) {
731
737
  // invalid value -> cannot render
732
738
  return undefined
@@ -21,6 +21,7 @@ import { isNotUndefined } from '../../_helpers/notUndefined'
21
21
  import type { SortableIterable } from '../../_helpers/sortable'
22
22
  import type { Stringable } from '../../_helpers/stringable'
23
23
  import { treeIteratorSymbol } from '../../_helpers/tree'
24
+ import { escapeUri } from '../../_helpers/uri'
24
25
  import * as Models from '../../models'
25
26
  import { isSupportedSpdxId } from '../../spdx'
26
27
  import { Version as SpecVersion } from '../../spec'
@@ -388,8 +389,10 @@ export class OrganizationalEntityNormalizer extends BaseXmlNormalizer<Models.Org
388
389
  name: elementName,
389
390
  children: [
390
391
  makeOptionalTextElement(data.name, 'name'),
391
- ...makeTextElementIter(data.url, options, 'url')
392
- .filter(({ children: u }) => XmlSchema.isAnyURI(u)),
392
+ ...makeTextElementIter(Array.from(
393
+ data.url, (s): string => escapeUri(s.toString())
394
+ ), options, 'url'
395
+ ).filter(({ children: u }) => XmlSchema.isAnyURI(u)),
393
396
  ...this._factory.makeForOrganizationalContact().normalizeIterable(data.contact, options, 'contact')
394
397
  ].filter(isNotUndefined)
395
398
  }
@@ -554,7 +557,7 @@ export class LicenseNormalizer extends BaseXmlNormalizer<Models.License> {
554
557
  }
555
558
 
556
559
  #normalizeNamedLicense (data: Models.NamedLicense, options: NormalizerOptions): SimpleXml.Element {
557
- const url = data.url?.toString()
560
+ const url = escapeUri(data.url?.toString())
558
561
  return {
559
562
  type: 'element',
560
563
  name: 'license',
@@ -571,7 +574,7 @@ export class LicenseNormalizer extends BaseXmlNormalizer<Models.License> {
571
574
  }
572
575
 
573
576
  #normalizeSpdxLicense (data: Models.SpdxLicense, options: NormalizerOptions): SimpleXml.Element {
574
- const url = data.url?.toString()
577
+ const url = escapeUri(data.url?.toString())
575
578
  return {
576
579
  type: 'element',
577
580
  name: 'license',
@@ -614,7 +617,7 @@ export class LicenseNormalizer extends BaseXmlNormalizer<Models.License> {
614
617
 
615
618
  export class SWIDNormalizer extends BaseXmlNormalizer<Models.SWID> {
616
619
  normalize (data: Models.SWID, options: NormalizerOptions, elementName: string): SimpleXml.Element {
617
- const url = data.url?.toString()
620
+ const url = escapeUri(data.url?.toString())
618
621
  return {
619
622
  type: 'element',
620
623
  name: elementName,
@@ -641,7 +644,7 @@ export class SWIDNormalizer extends BaseXmlNormalizer<Models.SWID> {
641
644
 
642
645
  export class ExternalReferenceNormalizer extends BaseXmlNormalizer<Models.ExternalReference> {
643
646
  normalize (data: Models.ExternalReference, options: NormalizerOptions, elementName: string): SimpleXml.Element | undefined {
644
- const url = data.url.toString()
647
+ const url = escapeUri(data.url.toString())
645
648
  const hashes: SimpleXml.Element | undefined = this._factory.spec.supportsExternalReferenceHashes && data.hashes.size > 0
646
649
  ? {
647
650
  type: 'element',
@@ -874,7 +877,7 @@ export class VulnerabilityNormalizer extends BaseXmlNormalizer<Models.Vulnerabil
874
877
 
875
878
  export class VulnerabilitySourceNormalizer extends BaseXmlNormalizer<Models.Vulnerability.Source> {
876
879
  normalize (data: Models.Vulnerability.Source, options: NormalizerOptions, elementName: string): SimpleXml.Element {
877
- const url = data.url?.toString()
880
+ const url = escapeUri(data.url?.toString())
878
881
  return {
879
882
  type: 'element',
880
883
  name: elementName,
@@ -940,7 +943,7 @@ export class VulnerabilityRatingNormalizer extends BaseXmlNormalizer<Models.Vuln
940
943
 
941
944
  export class VulnerabilityAdvisoryNormalizer extends BaseXmlNormalizer<Models.Vulnerability.Advisory> {
942
945
  normalize (data: Models.Vulnerability.Advisory, options: NormalizerOptions, elementName: string): SimpleXml.Element | undefined {
943
- const url = data.url.toString()
946
+ const url = escapeUri(data.url.toString())
944
947
  if (!XmlSchema.isAnyURI(url)) {
945
948
  // invalid value -> cannot render
946
949
  return undefined