url-sanitizer 5.3.2 → 5.3.4

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
@@ -26,31 +26,32 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "dompurify": "^3.4.16",
29
- "jsdom": "^30.1.1"
29
+ "jsdom": "^30.1.2"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@braintree/sanitize-url": "^7.1.2",
33
33
  "@types/jsdom": "^30.0.0",
34
- "@types/node": "^26.6.3",
34
+ "@types/node": "^26.6.5",
35
35
  "c8": "^12.0.0",
36
- "chai": "^6.2.2",
36
+ "chai": "^6.3.0",
37
37
  "commander": "^15.0.0",
38
- "copyfiles-ng": "^2.4.7",
38
+ "copyfiles-ng": "^2.4.9",
39
39
  "esbuild": "^0.28.2",
40
- "eslint": "^10.11.0",
40
+ "eslint": "^10.12.0",
41
41
  "eslint-config-prettier": "^10.1.8",
42
- "eslint-plugin-jsdoc": "^64.5.4",
42
+ "eslint-plugin-jsdoc": "^65.2.2",
43
43
  "eslint-plugin-prettier": "^5.5.6",
44
44
  "eslint-plugin-regexp": "^3.3.1",
45
- "eslint-plugin-unicorn": "^76.0.0",
45
+ "eslint-plugin-unicorn": "^77.0.0",
46
46
  "fast-check": "^4.10.2",
47
- "globals": "^17.12.0",
47
+ "globals": "^17.13.0",
48
48
  "http-server": "^14.1.1",
49
49
  "mitata": "^1.0.34",
50
- "mocha": "^12.0.2",
51
- "neostandard": "^0.14.0-next.1",
50
+ "mocha": "^12.0.3",
51
+ "neostandard": "^0.14.0",
52
52
  "papaparse": "^5.7.0",
53
53
  "prettier": "^3.9.9",
54
+ "prettier-plugin-brace-style": "^0.10.3",
54
55
  "sinon": "^22.1.0",
55
56
  "strict-url-sanitise": "^0.0.1",
56
57
  "typescript": "^7.0.2",
@@ -80,5 +81,5 @@
80
81
  "engines": {
81
82
  "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
82
83
  },
83
- "version": "5.3.2"
84
+ "version": "5.3.4"
84
85
  }
package/src/index.js CHANGED
@@ -84,9 +84,11 @@ export const sanitizeURLSync = (url, opt) =>
84
84
  * Sanitizes the given URL and returns its parsed components.
85
85
  * NOTE: Blob URLs are not revoked after inspection.
86
86
  * @param {string} url - The URL string to inspect.
87
+ * @param {SanitizeOptions} [opt] - The sanitization options.
87
88
  * @returns {Promise<InspectedURLResult>} A promise resolving to the inspected URL result.
88
89
  */
89
- export const inspectURL = async url => sanitizer.inspectURL(url);
90
+ export const inspectURL = async (url, opt = {}) =>
91
+ sanitizer.inspectURL(url, opt);
90
92
 
91
93
  /**
92
94
  * Checks if the given string is a valid URI and is registered.
@@ -1 +1 @@
1
- ["aaa","aaas","about","acap","acct","acd","ace","acr","adiumxtra","adt","aet","afp","afs","agtp","aim","amss","android","appdata","apt","ar","ari","ark","ars","at","attachment","aw","barion","beshare","bitcoin","bitcoincash","bl","blob","bluetooth","bolo","brid","browserext","cabal","caip","calculator","callto","cap","cast","casts","chrome","chrome-extension","cid","cm","coap","coaps","com-eventbrite-attendee","content","content-type","crid","cstr","cttps","cvs","dab","dat","data","dav","dhttp","diaspora","dict","did","dilithium3","dis","dlna-playcontainer","dlna-playsingle","dnp","dns","dntp","doi","donau","dpp","drm","dtmi","dtn","dvb","dvx","dweb","ed2k","eid","elsi","embedded","ens","esim","ethereum","example","ez","facetime","feed","feedready","fido","file","finger","first-run-pen-experience","fish","fm","ftp","fuchsia-pkg","gcx","gdsi","geo","gg","git","gitoid","gizmoproject","go","gopher","graph","gtalk","h323","ham","hcap","hcp","hs20","http","https","hxxp","hxxps","hydrazone","hyper","i0","iax","ibi","ibi-","icap","icon","ilstring","im","imap","info","interaction","iotdisco","ipfs","ipn","ipns","ipp","ipps","irc","irc6","ircs","iris","iris.beep","iris.lwz","iris.xpc","iris.xpcs","isostore","itms","jabber","jar","jms","keyparc","lastfm","lbry","ldap","ldaps","leaptofrogans","lid","linkid","lorawan","lpa","lvlt","machineProvisioningProgressReporter","magnet","mailto","maps","market","matrix","mdoc","mdoc-openid4vp","message","microsoft.windows.camera","microsoft.windows.camera.multipicker","microsoft.windows.camera.picker","mid","mms","mongodb","moz","moz-extension","mqtt","mqtts","ms-access","ms-appinstaller","ms-browser-extension","ms-calculator","ms-drive-to","ms-enrollment","ms-excel","ms-eyecontrolspeech","ms-gamebarservices","ms-gamingoverlay","ms-getoffice","ms-help","ms-infopath","ms-inputapp","ms-launchremotedesktop","ms-lockscreencomponent-config","ms-media-stream-id","ms-meetnow","ms-mixedrealitycapture","ms-mobileplans","ms-newsandinterests","ms-officeapp","ms-people","ms-personacard","ms-powerpoint","ms-project","ms-publisher","ms-recall","ms-remotedesktop","ms-remotedesktop-launch","ms-restoretabcompanion","ms-screenclip","ms-screensketch","ms-search","ms-search-repair","ms-secondary-screen-controller","ms-secondary-screen-setup","ms-settings","ms-settings-airplanemode","ms-settings-bluetooth","ms-settings-camera","ms-settings-cellular","ms-settings-cloudstorage","ms-settings-connectabledevices","ms-settings-displays-topology","ms-settings-emailandaccounts","ms-settings-language","ms-settings-location","ms-settings-lock","ms-settings-nfctransactions","ms-settings-notifications","ms-settings-power","ms-settings-privacy","ms-settings-proximity","ms-settings-screenrotation","ms-settings-wifi","ms-settings-workplace","ms-spd","ms-stickers","ms-sttoverlay","ms-transit-to","ms-useractivityset","ms-uup","ms-virtualtouchpad","ms-visio","ms-walk-to","ms-whiteboard","ms-whiteboard-cmd","ms-widgetboard","ms-widgets","ms-word","msnim","msrp","msrps","mss","mt","mtqp","mtrust","mumble","mupdate","musik","mvn","mvrp","mvrps","news","nfs","ni","nih","nntp","nostr","notes","npamp","num","ocf","oid","onenote","onenote-cmd","opaquelocktoken","openid","openpgp4fpr","otpauth","palm","paparazzi","payto","pkcs11","pkg","platform","pop","pres","proxy","psyc","pttp","pwid","qb","query","quic-transport","redis","rediss","reload","res","resource","rmi","rsync","rtmfp","rtmp","rtsp","rtsps","rtspu","rttp","sarif","secondlife","secret-token","seki","service","session","sftp","sgn","shc","shelter","sieve","simpleledger","simplex","sip","sips","skype","smb","smp","sms","smtp","snmp","soap.beep","soap.beeps","soldat","spacify","spiffe","spotify","ssb","ssh","sss","starknet","steam","stun","stuns","submit","svn","swh","swid","swidpath","tag","taler","teamspeak","teapot","teapots","tel","teliaeid","telnet","tftp","things","thismessage","tii","tip","tn3270","tool","tttps","turn","turns","tv","udp","unreal","upn","urn","ust","ut2004","uuaid","uuid-in-package","v-event","vemmi","ventrilo","ves","view-source","vnc","vscode","vscode-insiders","vsls","w3","wasm","wasm-js","wcr","web3","webcal","wifi","ws","wss","wtai","wyciwyg","xcompute","xcon","xcon-userid","xfire","xftp","xmlrpc.beep","xmlrpc.beeps","xmpp","xrcp","xri","ymsgr","z39.50r","z39.50s","ztdnaid"]
1
+ ["aaa","aaas","about","acap","acct","acd","ace","acr","adiumxtra","adt","aet","afp","afs","agtp","aim","alter","amss","android","appdata","apt","ar","ari","ark","ars","arv","at","attachment","aw","barion","beshare","bitcoin","bitcoincash","bl","blob","bluetooth","bolo","brid","browserext","cabal","caip","calculator","callto","canactid","cap","cast","casts","chrome","chrome-extension","cid","cm","coap","coaps","com-eventbrite-attendee","content","content-type","crid","cstr","cttps","cvs","dab","dat","data","dav","dhttp","diaspora","dict","did","dilithium3","dis","dlna-playcontainer","dlna-playsingle","dnp","dns","dntp","doi","donau","dpp","drm","dtmi","dtn","dvb","dvx","dweb","ed2k","eid","elsi","embedded","ens","esim","ethereum","example","ez","facetime","feed","feedready","fido","file","finger","first-run-pen-experience","fish","fm","ftp","fuchsia-pkg","gcx","gdsi","geo","gg","git","gitoid","gizmoproject","go","gopher","graph","gsos","gtalk","h323","ham","hcap","hcp","hs20","http","https","hxxp","hxxps","hydrazone","hyper","i0","iax","ibi","ibi-","icap","icon","ilstring","im","imap","info","interaction","iotdisco","ipfs","ipn","ipns","ipp","ipps","irc","irc6","ircs","iris","iris.beep","iris.lwz","iris.xpc","iris.xpcs","isostore","itms","jabber","jar","jms","keyparc","lastfm","lbry","ldap","ldaps","leaptofrogans","lid","linkid","locus","lorawan","lpa","lvlt","machineProvisioningProgressReporter","magnet","mailto","maps","market","matrix","mdoc","mdoc-openid4vp","message","microsoft.windows.camera","microsoft.windows.camera.multipicker","microsoft.windows.camera.picker","mid","mms","mongodb","moz","moz-extension","mqtt","mqtts","ms-access","ms-appinstaller","ms-browser-extension","ms-calculator","ms-drive-to","ms-enrollment","ms-excel","ms-eyecontrolspeech","ms-gamebarservices","ms-gamingoverlay","ms-getoffice","ms-help","ms-infopath","ms-inputapp","ms-launchremotedesktop","ms-lockscreencomponent-config","ms-media-stream-id","ms-meetnow","ms-mixedrealitycapture","ms-mobileplans","ms-newsandinterests","ms-officeapp","ms-people","ms-personacard","ms-powerpoint","ms-project","ms-publisher","ms-recall","ms-remotedesktop","ms-remotedesktop-launch","ms-restoretabcompanion","ms-screenclip","ms-screensketch","ms-search","ms-search-repair","ms-secondary-screen-controller","ms-secondary-screen-setup","ms-settings","ms-settings-airplanemode","ms-settings-bluetooth","ms-settings-camera","ms-settings-cellular","ms-settings-cloudstorage","ms-settings-connectabledevices","ms-settings-displays-topology","ms-settings-emailandaccounts","ms-settings-language","ms-settings-location","ms-settings-lock","ms-settings-nfctransactions","ms-settings-notifications","ms-settings-power","ms-settings-privacy","ms-settings-proximity","ms-settings-screenrotation","ms-settings-wifi","ms-settings-workplace","ms-spd","ms-stickers","ms-sttoverlay","ms-transit-to","ms-useractivityset","ms-uup","ms-virtualtouchpad","ms-visio","ms-walk-to","ms-whiteboard","ms-whiteboard-cmd","ms-widgetboard","ms-widgets","ms-word","msnim","msrp","msrps","mss","mt","mtqp","mtrust","mumble","mupdate","musik","mvn","mvrp","mvrps","news","nfs","ni","nih","nntp","nostr","notes","npamp","num","ocf","oid","onenote","onenote-cmd","opaquelocktoken","openid","openpgp4fpr","otpauth","palm","paparazzi","payto","pkcs11","pkg","platform","pop","pres","proxy","psyc","pttp","pwid","qb","query","quic-transport","redis","rediss","reload","res","resource","rmi","rsync","rtmfp","rtmp","rtsp","rtsps","rtspu","rttp","sarif","secondlife","secret-token","seki","service","session","sftp","sgn","shc","shelter","sieve","simpleledger","simplex","sip","sips","skype","smb","smp","sms","smtp","snmp","soap.beep","soap.beeps","soldat","spacify","spiffe","spotify","ssb","ssh","sss","starknet","steam","stun","stuns","submit","svn","swh","swid","swidpath","tag","taler","tcxp","teamspeak","teapot","teapots","tel","teliaeid","telnet","tftp","things","thismessage","tii","tip","tn3270","tool","tttps","turn","turns","tv","udp","unreal","upn","urn","ust","ut2004","uuaid","uuid-in-package","v-event","vemmi","ventrilo","ves","view-source","vnc","vscode","vscode-insiders","vsls","w3","wasm","wasm-js","wcr","web3","webcal","wifi","ws","wss","wtai","wyciwyg","xcompute","xcon","xcon-userid","xfire","xftp","xmlrpc.beep","xmlrpc.beeps","xmpp","xrcp","xri","ymsgr","z39.50r","z39.50s","ztdnaid"]
@@ -118,9 +118,10 @@ export class URLSanitizer extends URISchemes {
118
118
  * Inspects, parses, and sanitizes the given URL.
119
119
  * @private
120
120
  * @param {string} url - The URL string to parse.
121
+ * @param {InternalSanitizeOptions} options - Sanitization options.
121
122
  * @returns {InspectedURLResult} The result of an inspected URL.
122
123
  */
123
- #inspect(url) {
124
+ #inspect(url, options) {
124
125
  const inspectedURL = {
125
126
  input: url,
126
127
  href: null,
@@ -137,12 +138,7 @@ export class URLSanitizer extends URISchemes {
137
138
  let sanitizedURL;
138
139
  let invalidReason = null;
139
140
  try {
140
- sanitizedURL = this.#filter.sanitize(url, {
141
- ...this.#defaultOpts,
142
- allow: ['data'],
143
- allowRelative: true,
144
- schemes: this.#allowedSchemes
145
- });
141
+ sanitizedURL = this.#filter.sanitize(url, options);
146
142
  if (!sanitizedURL) {
147
143
  invalidReason =
148
144
  'Sanitization failed (blocked by allowed schemes or rules).';
@@ -227,6 +223,23 @@ export class URLSanitizer extends URISchemes {
227
223
  }
228
224
  }
229
225
 
226
+ /**
227
+ * Re-throws errors or operation aborts.
228
+ * @private
229
+ * @param {Error} e - The error object to evaluate.
230
+ * @param {InternalSanitizeOptions} options - The internal sanitization options.
231
+ * @throws {Error} Re-throws the given error if it is a TypeError, AbortError, or aborted signal.
232
+ */
233
+ #shouldThrow(e, options) {
234
+ if (
235
+ e instanceof TypeError ||
236
+ e.name === 'AbortError' ||
237
+ options.signal?.aborted
238
+ ) {
239
+ throw e;
240
+ }
241
+ }
242
+
230
243
  /**
231
244
  * Gets the list of registered URI schemes.
232
245
  * @returns {string[]} An array of registered schemes.
@@ -349,16 +362,31 @@ export class URLSanitizer extends URISchemes {
349
362
  );
350
363
  }
351
364
  }
365
+ } catch (e) {
366
+ this.#shouldThrow(e, options);
367
+ if (options.debug) {
368
+ logDebug(`Failed to sanitize URL: ${truncateURL(url)}`, e);
369
+ }
370
+ return null;
352
371
  } finally {
353
372
  if (options.revokeObjectURL) {
354
373
  URL.revokeObjectURL(url);
355
374
  }
356
375
  }
357
376
  return sanitizedData;
358
- } else if (scheme === 'data') {
359
- return this.#filter.sanitizeDataURL(url, options);
360
377
  }
361
- return this.#filter.sanitize(url, options);
378
+ try {
379
+ if (scheme === 'data') {
380
+ return this.#filter.sanitizeDataURL(url, options);
381
+ }
382
+ return this.#filter.sanitize(url, options);
383
+ } catch (e) {
384
+ this.#shouldThrow(e, options);
385
+ if (options.debug) {
386
+ logDebug(`Failed to sanitize URL: ${truncateURL(url)}`, e);
387
+ }
388
+ return null;
389
+ }
362
390
  }
363
391
 
364
392
  /**
@@ -380,7 +408,15 @@ export class URLSanitizer extends URISchemes {
380
408
  }
381
409
  return null;
382
410
  }
383
- return this.#filter.sanitize(url, options);
411
+ try {
412
+ return this.#filter.sanitize(url, options);
413
+ } catch (e) {
414
+ this.#shouldThrow(e, options);
415
+ if (options.debug) {
416
+ logDebug(`Failed to sanitize URL: ${truncateURL(url)}`, e);
417
+ }
418
+ return null;
419
+ }
384
420
  }
385
421
 
386
422
  /**
@@ -389,7 +425,7 @@ export class URLSanitizer extends URISchemes {
389
425
  * @param {SanitizeOptions} [opt] - The sanitization options.
390
426
  * @returns {Promise<InspectedURLResult>} A promise resolving to the inspected URL result.
391
427
  */
392
- async inspectURL(url, opt) {
428
+ async inspectURL(url, opt = {}) {
393
429
  const { options, scheme } = this.#normalizeOptions(url, opt);
394
430
  if (scheme === 'blob') {
395
431
  return this.#inspectBlob(url, options);
@@ -356,6 +356,8 @@ export const encodeBufferToBase64 = buffer => {
356
356
  * @param {AbortSignal} [signal] - The abort signal.
357
357
  * @returns {Promise<ArrayBuffer>} A promise resolving to the generated ArrayBuffer.
358
358
  */
359
+ // Stream reading requires sequential async execution.
360
+ /* eslint-disable no-await-in-loop */
359
361
  export const readStreamInChunksAsArrayBuffer = async (
360
362
  response,
361
363
  maxSize,
@@ -409,6 +411,7 @@ export const readStreamInChunksAsArrayBuffer = async (
409
411
  reader.releaseLock();
410
412
  }
411
413
  };
414
+ /* eslint-enable no-await-in-loop */
412
415
 
413
416
  /**
414
417
  * Fetches a Blob URL and extracts its ArrayBuffer and MIME type.
package/types/index.d.ts CHANGED
@@ -44,7 +44,7 @@ export { URLSanitizer };
44
44
  declare const sanitizer: URLSanitizer;
45
45
  export declare const sanitizeURL: (url: string, opt?: SanitizeOptions) => Promise<string | null>;
46
46
  export declare const sanitizeURLSync: (url: string, opt?: SanitizeOptions) => string | null;
47
- export declare const inspectURL: (url: string) => Promise<InspectedURLResult>;
47
+ export declare const inspectURL: (url: string, opt?: SanitizeOptions) => Promise<InspectedURLResult>;
48
48
  export declare const isValidURI: (uri: string) => boolean;
49
49
  export declare const isURISync: (uri: string) => boolean;
50
50
  export default sanitizer;
@@ -12,6 +12,7 @@ export declare class SanitizeContext {
12
12
  schemeMap: Map<string, boolean>;
13
13
  allowRelative: boolean | undefined;
14
14
  debug: boolean | undefined;
15
+ schemes: Set<string> | undefined;
15
16
  constructor(domPurifyInstance: DOMPurify, opt?: InternalSanitizeOptions);
16
17
  private #compileRules;
17
18
  private #registerScheme;
@@ -12,6 +12,7 @@ export declare class URLSanitizer extends URISchemes {
12
12
  private #normalizeOptions;
13
13
  private #inspect;
14
14
  private #inspectBlob;
15
+ private #shouldThrow;
15
16
  get(): string[];
16
17
  has(scheme: string): boolean;
17
18
  add(scheme: string): string[];