repocairn 0.1.6 → 0.1.7

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.
Files changed (62) hide show
  1. package/node_modules/fast-uri/index.js +201 -48
  2. package/node_modules/fast-uri/lib/schemes.js +9 -4
  3. package/node_modules/fast-uri/lib/utils.js +388 -91
  4. package/node_modules/fast-uri/package.json +1 -1
  5. package/node_modules/fast-uri/test/component-safe-serialization.test.js +105 -0
  6. package/node_modules/fast-uri/test/equal.test.js +31 -3
  7. package/node_modules/fast-uri/test/fixtures/uri-js-parse.json +2 -0
  8. package/node_modules/fast-uri/test/ipv6-canonical.test.js +34 -0
  9. package/node_modules/fast-uri/test/ipv6-validation.test.js +90 -0
  10. package/node_modules/fast-uri/test/malformed-percent.test.js +77 -0
  11. package/node_modules/fast-uri/test/malformed-urn.test.js +61 -0
  12. package/node_modules/fast-uri/test/parse.test.js +7 -3
  13. package/node_modules/fast-uri/test/query-fragment-normalization.test.js +33 -0
  14. package/node_modules/fast-uri/test/reserved-path-normalization.test.js +109 -0
  15. package/node_modules/fast-uri/test/scheme-validation.test.js +124 -0
  16. package/node_modules/fast-uri/test/security-normalization.test.js +101 -0
  17. package/node_modules/fast-uri/test/security.test.js +75 -3
  18. package/node_modules/fast-uri/test/urn-full-input.test.js +29 -0
  19. package/node_modules/fast-uri/test/websocket-query-preservation.test.js +24 -0
  20. package/node_modules/jose/dist/types/jwks/remote.d.ts +4 -4
  21. package/node_modules/jose/dist/types/jws/general/verify.d.ts +3 -3
  22. package/node_modules/jose/dist/types/jwt/encrypt.d.ts +8 -14
  23. package/node_modules/jose/dist/types/jwt/sign.d.ts +8 -14
  24. package/node_modules/jose/dist/types/jwt/unsecured.d.ts +9 -15
  25. package/node_modules/jose/dist/webapi/jwe/compact/encrypt.js +30 -8
  26. package/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +8 -4
  27. package/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +6 -13
  28. package/node_modules/jose/dist/webapi/jwe/general/decrypt.js +19 -19
  29. package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +27 -20
  30. package/node_modules/jose/dist/webapi/jwk/embedded.js +15 -1
  31. package/node_modules/jose/dist/webapi/jwk/thumbprint.js +11 -5
  32. package/node_modules/jose/dist/webapi/jwks/local.js +45 -53
  33. package/node_modules/jose/dist/webapi/jwks/remote.js +82 -103
  34. package/node_modules/jose/dist/webapi/jws/compact/sign.js +10 -9
  35. package/node_modules/jose/dist/webapi/jws/flattened/sign.js +2 -1
  36. package/node_modules/jose/dist/webapi/jws/flattened/verify.js +8 -7
  37. package/node_modules/jose/dist/webapi/jws/general/sign.js +5 -3
  38. package/node_modules/jose/dist/webapi/jws/general/verify.js +51 -21
  39. package/node_modules/jose/dist/webapi/jwt/decrypt.js +7 -9
  40. package/node_modules/jose/dist/webapi/jwt/encrypt.js +21 -50
  41. package/node_modules/jose/dist/webapi/jwt/sign.js +8 -41
  42. package/node_modules/jose/dist/webapi/jwt/unsecured.js +21 -42
  43. package/node_modules/jose/dist/webapi/key/generate_key_pair.js +6 -2
  44. package/node_modules/jose/dist/webapi/key/generate_secret.js +7 -6
  45. package/node_modules/jose/dist/webapi/key/import.js +16 -12
  46. package/node_modules/jose/dist/webapi/lib/asn1.js +7 -2
  47. package/node_modules/jose/dist/webapi/lib/content_encryption.js +7 -15
  48. package/node_modules/jose/dist/webapi/lib/deflate.js +8 -0
  49. package/node_modules/jose/dist/webapi/lib/helpers.js +1 -1
  50. package/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +85 -28
  51. package/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +40 -12
  52. package/node_modules/jose/dist/webapi/lib/jwk_metadata.js +20 -0
  53. package/node_modules/jose/dist/webapi/lib/jws_sign.js +47 -36
  54. package/node_modules/jose/dist/webapi/lib/jws_verify.js +77 -45
  55. package/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +82 -47
  56. package/node_modules/jose/dist/webapi/lib/key.js +24 -9
  57. package/node_modules/jose/dist/webapi/lib/key_management.js +10 -4
  58. package/node_modules/jose/dist/webapi/lib/key_options.js +6 -0
  59. package/node_modules/jose/dist/webapi/lib/options.js +26 -0
  60. package/node_modules/jose/dist/webapi/lib/type_checks.js +11 -13
  61. package/node_modules/jose/package.json +1 -1
  62. package/package.json +1 -1
@@ -1,8 +1,23 @@
1
1
  'use strict'
2
2
 
3
- const { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require('./lib/utils')
3
+ const { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require('./lib/utils')
4
4
  const { SCHEMES, getSchemeHandler } = require('./lib/schemes')
5
5
 
6
+ const VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u
7
+ const MALFORMED_SCHEME_ERROR = 'URI scheme is malformed.'
8
+
9
+ /**
10
+ * @param {string} scheme
11
+ * @returns {string}
12
+ */
13
+ function decodeValidScheme (scheme) {
14
+ const decodedScheme = unescape(String(scheme))
15
+ if (!VALID_SCHEME.test(decodedScheme)) {
16
+ throw new TypeError(MALFORMED_SCHEME_ERROR)
17
+ }
18
+ return decodedScheme
19
+ }
20
+
6
21
  /**
7
22
  * @template {import('./types/index').URIComponent|string} T
8
23
  * @param {T} uri
@@ -26,12 +41,50 @@ function normalize (uri, options) {
26
41
  */
27
42
  function resolve (baseURI, relativeURI, options) {
28
43
  const schemelessOptions = options ? Object.assign({ scheme: 'null' }, options) : { scheme: 'null' }
29
- const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions)
30
- const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions)
31
- if (baseMalformed || relativeMalformed) {
44
+ const {
45
+ parsed: baseParsed,
46
+ malformedAuthorityOrPort: baseMalformed,
47
+ malformedPercentEncoding: baseMalformedPercentEncoding,
48
+ malformedSchemeSpecific: baseMalformedSchemeSpecific,
49
+ malformedHost: baseMalformedHost,
50
+ malformedScheme: baseMalformedScheme
51
+ } = parseWithStatus(baseURI, schemelessOptions)
52
+ const {
53
+ parsed: relativeParsed,
54
+ malformedAuthorityOrPort: relativeMalformed,
55
+ malformedPercentEncoding: relativeMalformedPercentEncoding,
56
+ malformedSchemeSpecific: relativeMalformedSchemeSpecific,
57
+ malformedHost: relativeMalformedHost,
58
+ malformedScheme: relativeMalformedScheme
59
+ } = parseWithStatus(relativeURI, schemelessOptions)
60
+ if (
61
+ baseMalformed ||
62
+ relativeMalformed ||
63
+ baseMalformedPercentEncoding ||
64
+ relativeMalformedPercentEncoding ||
65
+ baseMalformedSchemeSpecific ||
66
+ relativeMalformedSchemeSpecific ||
67
+ baseMalformedHost ||
68
+ relativeMalformedHost ||
69
+ baseMalformedScheme ||
70
+ relativeMalformedScheme
71
+ ) {
32
72
  throw new Error(baseParsed.error || relativeParsed.error || 'URI is malformed.')
33
73
  }
34
74
  const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true)
75
+ const resolvedSchemeHandler = getSchemeHandler((options && options.scheme) || resolved.scheme)
76
+ const resolvedHost = resolved.host
77
+ const resolvedHostIsIP = resolvedHost !== undefined && resolvedHost !== '' &&
78
+ (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6)
79
+ canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP)
80
+ // Percent escapes in an ASCII reg-name are encoded data. The WHATWG hostname
81
+ // parser can reject them even though fast-uri preserves them safely as RFC
82
+ // 3986 data. A raw non-ASCII host must still fail closed if conversion fails.
83
+ const encodedASCIIHost = resolvedHost && resolvedHost.indexOf('%') !== -1 &&
84
+ !/\P{ASCII}/u.test(resolvedHost)
85
+ if (resolved.error && !encodedASCIIHost) {
86
+ throw new Error(resolved.error)
87
+ }
35
88
  schemelessOptions.skipEscape = true
36
89
  return serialize(resolved, schemelessOptions)
37
90
  }
@@ -114,7 +167,7 @@ function equal (uriA, uriB, options) {
114
167
  const normalizedA = normalizeComparableURI(uriA, options)
115
168
  const normalizedB = normalizeComparableURI(uriB, options)
116
169
 
117
- return normalizedA !== undefined && normalizedB !== undefined && normalizedA.toLowerCase() === normalizedB.toLowerCase()
170
+ return normalizedA !== undefined && normalizedB !== undefined && normalizedA === normalizedB
118
171
  }
119
172
 
120
173
  /**
@@ -142,25 +195,30 @@ function serialize (cmpts, opts) {
142
195
  const options = Object.assign({}, opts)
143
196
  const uriTokens = []
144
197
 
198
+ if (component.scheme) {
199
+ component.scheme = decodeValidScheme(component.scheme)
200
+ }
201
+
145
202
  // find scheme handler
146
203
  const schemeHandler = getSchemeHandler(options.scheme || component.scheme)
147
204
 
148
205
  // perform scheme specific serialization
149
206
  if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options)
150
207
 
208
+ const hasAuthority = component.userinfo !== undefined || component.host !== undefined || component.port !== undefined
209
+ const pathNoScheme = !options.skipEscape && component.scheme === undefined && !hasAuthority
210
+
151
211
  if (component.path !== undefined) {
152
212
  if (!options.skipEscape) {
153
- component.path = escapePreservingEscapes(component.path)
154
-
155
- if (component.scheme !== undefined) {
156
- component.path = component.path.split('%3A').join(':')
157
- }
213
+ component.path = serializePathEncoding(component.path, pathNoScheme)
158
214
  } else {
159
215
  component.path = normalizePercentEncoding(component.path)
160
216
  }
161
217
  }
162
218
 
163
219
  if (options.reference !== 'suffix' && component.scheme) {
220
+ // Scheme handlers may replace the scheme during serialization.
221
+ component.scheme = decodeValidScheme(component.scheme)
164
222
  uriTokens.push(component.scheme, ':')
165
223
  }
166
224
 
@@ -183,6 +241,13 @@ function serialize (cmpts, opts) {
183
241
  s = removeDotSegments(s)
184
242
  }
185
243
 
244
+ // Dot-segment removal can expose a colon that was not originally in the
245
+ // first segment (for example, "./a:b"). Reapply path-noscheme encoding so
246
+ // the serialized relative reference cannot be reparsed as a URI scheme.
247
+ if (pathNoScheme) {
248
+ s = serializePathEncoding(s, true)
249
+ }
250
+
186
251
  if (
187
252
  authority === undefined &&
188
253
  s[0] === '/' &&
@@ -196,11 +261,11 @@ function serialize (cmpts, opts) {
196
261
  }
197
262
 
198
263
  if (component.query !== undefined) {
199
- uriTokens.push('?', component.query)
264
+ uriTokens.push('?', encodeQuery(component.query))
200
265
  }
201
266
 
202
267
  if (component.fragment !== undefined) {
203
- uriTokens.push('#', component.fragment)
268
+ uriTokens.push('#', encodeFragment(component.fragment))
204
269
  }
205
270
  return uriTokens.join('')
206
271
  }
@@ -237,10 +302,74 @@ function getParseError (parsed, matches) {
237
302
  return undefined
238
303
  }
239
304
 
305
+ /**
306
+ * Checks percent syntax without decoding the represented octets. RFC 3986
307
+ * percent-encoding is byte-oriented, so sequences such as `%FF` are valid even
308
+ * though they are not independently valid UTF-8.
309
+ *
310
+ * @param {string|undefined} component
311
+ * @returns {boolean}
312
+ */
313
+ function hasMalformedPercentEncoding (component) {
314
+ if (component === undefined) return false
315
+
316
+ let percent = component.indexOf('%')
317
+ while (percent !== -1) {
318
+ if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) {
319
+ return true
320
+ }
321
+ percent = component.indexOf('%', percent + 3)
322
+ }
323
+
324
+ return false
325
+ }
326
+
327
+ /**
328
+ * @param {RegExpMatchArray} matches
329
+ * @returns {boolean}
330
+ */
331
+ function hasMalformedComponentPercentEncoding (matches) {
332
+ // Bracketed IP literals use a raw "%" as the zone separator for historical
333
+ // compatibility. Their parsing is intentionally left to normalizeIPv6.
334
+ const host = matches[4]
335
+ return hasMalformedPercentEncoding(matches[3]) ||
336
+ (host !== undefined && !(host[0] === '[' && host[host.length - 1] === ']') && hasMalformedPercentEncoding(host)) ||
337
+ hasMalformedPercentEncoding(matches[6]) ||
338
+ hasMalformedPercentEncoding(matches[7]) ||
339
+ hasMalformedPercentEncoding(matches[8])
340
+ }
341
+
342
+ /**
343
+ * @param {import('./types/index').URIComponent} parsed
344
+ * @param {import('./types/index').Options} options
345
+ * @param {{ domainHost?: boolean, unicodeSupport?: boolean }|undefined} schemeHandler
346
+ * @param {boolean} isIP
347
+ * @returns {boolean} whether host conversion failed
348
+ */
349
+ function canonicalizeHost (parsed, options, schemeHandler, isIP) {
350
+ if (
351
+ !options.unicodeSupport &&
352
+ (!schemeHandler || !schemeHandler.unicodeSupport) &&
353
+ parsed.host &&
354
+ parsed.host[0] !== '[' &&
355
+ (options.domainHost || (schemeHandler && schemeHandler.domainHost)) &&
356
+ isIP === false &&
357
+ nonSimpleDomain(parsed.host)
358
+ ) {
359
+ try {
360
+ parsed.host = new URL('http://' + parsed.host).hostname
361
+ } catch (e) {
362
+ parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e
363
+ return true
364
+ }
365
+ }
366
+ return false
367
+ }
368
+
240
369
  /**
241
370
  * @param {string} uri
242
371
  * @param {import('./types/index').Options} [opts]
243
- * @returns {{ parsed: import('./types/index').URIComponent, malformedAuthorityOrPort: boolean }}
372
+ * @returns {{ parsed: import('./types/index').URIComponent, malformedAuthorityOrPort: boolean, malformedPercentEncoding: boolean, malformedSchemeSpecific: boolean, malformedHost: boolean, malformedScheme: boolean }}
244
373
  */
245
374
  function parseWithStatus (uri, opts) {
246
375
  const options = Object.assign({}, opts)
@@ -256,6 +385,11 @@ function parseWithStatus (uri, opts) {
256
385
  }
257
386
 
258
387
  let malformedAuthorityOrPort = false
388
+ let malformedPercentEncoding = false
389
+ let malformedSchemeSpecific = false
390
+ let malformedHost = false
391
+ let malformedIPLiteral = false
392
+ let malformedScheme = false
259
393
 
260
394
  let isIP = false
261
395
  if (options.reference === 'suffix') {
@@ -313,6 +447,21 @@ function parseWithStatus (uri, opts) {
313
447
  parsed.query = matches[7]
314
448
  parsed.fragment = matches[8]
315
449
 
450
+ if (parsed.scheme !== undefined) {
451
+ const decodedScheme = unescape(parsed.scheme)
452
+ if (VALID_SCHEME.test(decodedScheme)) {
453
+ parsed.scheme = decodedScheme.toLowerCase()
454
+ } else {
455
+ parsed.error = parsed.error || MALFORMED_SCHEME_ERROR
456
+ malformedScheme = true
457
+ }
458
+ }
459
+
460
+ malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches)
461
+ if (malformedPercentEncoding) {
462
+ parsed.error = parsed.error || 'URI contains malformed percent-encoding.'
463
+ }
464
+
316
465
  // fix port number
317
466
  if (isNaN(parsed.port)) {
318
467
  parsed.port = matches[5]
@@ -327,9 +476,16 @@ function parseWithStatus (uri, opts) {
327
476
  if (parsed.host) {
328
477
  const ipv4result = isIPv4(parsed.host)
329
478
  if (ipv4result === false) {
479
+ const bracketedIPLiteral = parsed.host[0] === '[' && parsed.host[parsed.host.length - 1] === ']'
330
480
  const ipv6result = normalizeIPv6(parsed.host)
331
- parsed.host = ipv6result.host.toLowerCase()
332
- isIP = ipv6result.isIPV6
481
+ isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true
482
+ malformedIPLiteral = bracketedIPLiteral && ipv6result.error === true
483
+ parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase()
484
+
485
+ if (malformedIPLiteral) {
486
+ parsed.error = parsed.error || 'URI host is malformed.'
487
+ malformedAuthorityOrPort = true
488
+ }
333
489
  } else {
334
490
  isIP = true
335
491
  }
@@ -352,49 +508,38 @@ function parseWithStatus (uri, opts) {
352
508
  // find scheme handler
353
509
  const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme)
354
510
 
355
- // check if scheme can't handle IRIs
356
- if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
357
- // if host component is a domain name
358
- if (parsed.host && (options.domainHost || (schemeHandler && schemeHandler.domainHost)) && isIP === false && nonSimpleDomain(parsed.host)) {
359
- // convert Unicode IDN -> ASCII IDN
360
- try {
361
- parsed.host = new URL('http://' + parsed.host).hostname
362
- } catch (e) {
363
- parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e
364
- }
365
- }
366
- // convert IRI -> URI
367
- }
511
+ // convert Unicode IDN -> ASCII IDN when the effective scheme uses domain hosts
512
+ malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP)
368
513
 
369
514
  if (!schemeHandler || (schemeHandler && !schemeHandler.skipNormalize)) {
370
515
  if (uri.indexOf('%') !== -1) {
371
- if (parsed.scheme !== undefined) {
372
- parsed.scheme = unescape(parsed.scheme)
373
- }
374
- if (parsed.host !== undefined) {
375
- parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP)
516
+ if (parsed.host !== undefined && !malformedIPLiteral) {
517
+ const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true)
518
+ parsed.host = reescapeHostDelimiters(host, isIP)
376
519
  }
377
520
  }
378
521
  if (parsed.path) {
379
522
  parsed.path = normalizePathEncoding(parsed.path)
380
523
  }
524
+ if (parsed.query) {
525
+ parsed.query = normalizeQueryFragmentEncoding(parsed.query)
526
+ }
381
527
  if (parsed.fragment) {
382
- try {
383
- parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment))
384
- } catch {
385
- parsed.error = parsed.error || 'URI malformed'
386
- }
528
+ parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment)
387
529
  }
388
530
  }
389
531
 
390
532
  // perform scheme specific parsing
391
533
  if (schemeHandler && schemeHandler.parse) {
392
534
  schemeHandler.parse(parsed, options)
535
+ if (schemeHandler === SCHEMES.urn && parsed.nid === undefined) {
536
+ malformedSchemeSpecific = true
537
+ }
393
538
  }
394
539
  } else {
395
540
  parsed.error = parsed.error || 'URI can not be parsed.'
396
541
  }
397
- return { parsed, malformedAuthorityOrPort }
542
+ return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme }
398
543
  }
399
544
 
400
545
  /**
@@ -418,13 +563,17 @@ function normalizeString (uri, opts) {
418
563
  /**
419
564
  * @param {string} uri
420
565
  * @param {import('./types/index').Options} [opts]
421
- * @returns {{ normalized: string, malformedAuthorityOrPort: boolean }}
566
+ * @returns {{ normalized: string, malformedAuthorityOrPort: boolean, malformedPercentEncoding: boolean, malformedSchemeSpecific: boolean, malformedHost: boolean, malformedScheme: boolean }}
422
567
  */
423
568
  function normalizeStringWithStatus (uri, opts) {
424
- const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts)
569
+ const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts)
425
570
  return {
426
- normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
427
- malformedAuthorityOrPort
571
+ normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
572
+ malformedAuthorityOrPort,
573
+ malformedPercentEncoding,
574
+ malformedSchemeSpecific,
575
+ malformedHost,
576
+ malformedScheme
428
577
  }
429
578
  }
430
579
 
@@ -434,14 +583,18 @@ function normalizeStringWithStatus (uri, opts) {
434
583
  * @returns {string|undefined}
435
584
  */
436
585
  function normalizeComparableURI (uri, opts) {
437
- if (typeof uri === 'string') {
438
- const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts)
439
- return malformedAuthorityOrPort ? undefined : normalized
586
+ if (typeof uri !== 'string' && typeof uri !== 'object') {
587
+ return undefined
440
588
  }
441
589
 
442
- if (typeof uri === 'object') {
443
- return serialize(uri, opts)
590
+ let value
591
+ try {
592
+ value = typeof uri === 'string' ? uri : serialize(uri, opts)
593
+ } catch {
594
+ return undefined
444
595
  }
596
+ const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts)
597
+ return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? undefined : normalized
445
598
  }
446
599
 
447
600
  const fastUri = {
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { isUUID } = require('./utils')
4
- const URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu
4
+ const URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu
5
5
 
6
6
  const supportedSchemeNames = /** @type {const} */ (['http', 'https', 'ws',
7
7
  'wss', 'urn', 'urn:uuid'])
@@ -113,9 +113,14 @@ function wsSerialize (wsComponent) {
113
113
 
114
114
  // reconstruct path from resource name
115
115
  if (wsComponent.resourceName) {
116
- const [path, query] = wsComponent.resourceName.split('?')
116
+ const queryIndex = wsComponent.resourceName.indexOf('?')
117
+ const path = queryIndex === -1
118
+ ? wsComponent.resourceName
119
+ : wsComponent.resourceName.slice(0, queryIndex)
117
120
  wsComponent.path = (path && path !== '/' ? path : undefined)
118
- wsComponent.query = query
121
+ wsComponent.query = queryIndex === -1
122
+ ? undefined
123
+ : wsComponent.resourceName.slice(queryIndex + 1)
119
124
  wsComponent.resourceName = undefined
120
125
  }
121
126
 
@@ -132,7 +137,7 @@ function urnParse (urnComponent, options) {
132
137
  return urnComponent
133
138
  }
134
139
  const matches = urnComponent.path.match(URN_REG)
135
- if (matches) {
140
+ if (matches && matches[0] === urnComponent.path) {
136
141
  const scheme = options.scheme || urnComponent.scheme || 'urn'
137
142
  urnComponent.nid = matches[1].toLowerCase()
138
143
  urnComponent.nss = matches[2]