url-sanitizer 0.8.3 → 0.8.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/README.md CHANGED
@@ -21,9 +21,14 @@ npm i url-sanitizer
21
21
  For browsers and web sites, standalone ESM builds are available in `dist/` directory.
22
22
  * node_modules/url-sanitizer/dist/url-sanitizer.js
23
23
  * node_modules/url-sanitizer/dist/url-sanitizer.min.js
24
+ * node_modules/url-sanitizer/dist/url-sanitizer.wo.dompurify.js
25
+ * node_modules/url-sanitizer/dist/url-sanitizer.wo.dompurify.min.js
24
26
 
25
27
  Or, download them from [Releases](https://github.com/asamuzaK/urlSanitizer/releases).
26
28
 
29
+ NOTE: `url-sanitizer.wo.dompurify.js` and `url-sanitizer.wo.dompurify.min.js` are built without [DOMPurify](https://www.npmjs.com/package/dompurify).
30
+ Use them if DOMPurify is exposed as `window.DOMPurify`.
31
+
27
32
 
28
33
  ## Usage
29
34
 
@@ -94,7 +99,7 @@ const blob4 = new Blob(['<svg><g onload="alert(1)"/></svg>'], {
94
99
  type: 'image/svg+xml'
95
100
  });
96
101
  const url4 = URL.createObjectURL(blob4);
97
- const res4 = await func(url, {
102
+ const res4 = await func(url4, {
98
103
  allow: ['blob']
99
104
  });
100
105
  // => 'data:image/svg+xml,%3Csvg%3E%3Cg%3E%3C/g%3E%3C/svg%3E'
@@ -384,7 +389,7 @@ const res2 = urlSanitizer.remove('foo');
384
389
 
385
390
  The following resources have been of great help in the development of the URL Sanitizer.
386
391
 
387
- * [DOMPurify](https://www.npmjs.com/package/dompurify?activeTab=readme)
392
+ * [DOMPurify](https://www.npmjs.com/package/dompurify)
388
393
  * [Uniform Resource Identifier (URI) Schemes - IANA](https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml)
389
394
  * [Encoding -- determine the character encoding of a text file. - file/file](https://github.com/file/file/blob/master/src/encoding.c)
390
395
 
@@ -2184,6 +2184,7 @@ export {
2184
2184
  };
2185
2185
  /*!
2186
2186
  * URL Sanitizer
2187
+ *
2187
2188
  * @license MIT
2188
2189
  * @copyright asamuzaK (Kazz)
2189
2190
  * @see {@link https://github.com/asamuzaK/urlSanitizer/blob/main/LICENSE}
@@ -3,6 +3,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
3
3
  `+L),ce&&(L=U(L,je," "),L=U(L,We," "),L=U(L,Ye," ")),$&&Oe?$.createHTML(L):L},o.setConfig=function(l){rt(l),Ke=!0},o.clearConfig=function(){de=null,Ke=!1},o.isValidAttribute=function(l,e,t){de||rt({});var i=S(l),v=S(e);return zt(i,v,t)},o.addHook=function(l,e){typeof e=="function"&&(Y[l]=Y[l]||[],B(Y[l],e))},o.removeHook=function(l){if(Y[l])return se(Y[l])},o.removeHooks=function(l){Y[l]&&(Y[l]=[])},o.removeAllHooks=function(){Y={}},o}var fr=_t();return fr})});var{FileReader:ot}=window,va=new ot;var J=a=>Object.prototype.toString.call(a).slice(8,-1),P=a=>typeof a=="string"||a instanceof String;var ct=Gr(jt(),1);var pt=[7,8,9,10,11,12,13,27,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255];var Wt=["aaa","aaas","about","acap","acct","acd","acr","adiumxtra","adt","afp","afs","aim","amss","android","appdata","apt","ar","ark","attachment","aw","barion","beshare","bitcoin","bitcoincash","blob","bolo","browserext","cabal","calculator","callto","cap","cast","casts","chrome","chrome-extension","cid","coap","coaps","com-eventbrite-attendee","content","content-type","crid","cstr","cvs","dab","dat","data","dav","diaspora","dict","did","dis","dlna-playcontainer","dlna-playsingle","dns","dntp","doi","dpp","drm","dtmi","dtn","dvb","dvx","dweb","ed2k","eid","elsi","embedded","ens","ethereum","example","facetime","feed","feedready","fido","file","finger","first-run-pen-experience","fish","fm","ftp","fuchsia-pkg","geo","gg","git","gitoid","gizmoproject","go","gopher","graph","gtalk","h323","ham","hcap","hcp","http","https","hxxp","hxxps","hydrazone","hyper","iax","icap","icon","im","imap","info","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","lorawan","lpa","lvlt","magnet","mailto","maps","market","matrix","message","microsoft.windows.camera","microsoft.windows.camera.multipicker","microsoft.windows.camera.picker","mid","mms","mongodb","moz","moz-extension","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-lockscreencomponent-config","ms-media-stream-id","ms-meetnow","ms-mixedrealitycapture","ms-mobileplans","ms-newsandinterests","ms-officeapp","ms-people","ms-powerpoint","ms-project","ms-publisher","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-virtualtouchpad","ms-visio","ms-walk-to","ms-whiteboard","ms-whiteboard-cmd","ms-word","msnim","msrp","msrps","mss","mt","mtqp","mumble","mupdate","mvn","news","nfs","ni","nih","nntp","notes","num","ocf","oid","onenote","onenote-cmd","opaquelocktoken","openpgp4fpr","otpauth","palm","paparazzi","payment","payto","pkcs11","platform","pop","pres","proxy","psyc","pttp","pwid","qb","query","quic-transport","redis","rediss","reload","res","resource","rmi","rsync","rtmfp","rtmp","rtsp","rtsps","rtspu","sarif","secondlife","secret-token","service","session","sftp","sgn","shc","sieve","simpleledger","simplex","sip","sips","skype","smb","smp","sms","smtp","snmp","soap.beep","soap.beeps","soldat","spiffe","spotify","ssb","ssh","starknet","steam","stun","stuns","submit","svn","swh","swid","swidpath","tag","taler","teamspeak","tel","teliaeid","telnet","tftp","things","thismessage","tip","tn3270","tool","turn","turns","tv","udp","unreal","urn","ut2004","uuid-in-package","v-event","vemmi","ventrilo","ves","view-source","vnc","vscode","vscode-insiders","vsls","w3","wcr","web3","webcal","wifi","ws","wss","wtai","wyciwyg","xcon","xcon-userid","xfire","xmlrpc.beep","xmlrpc.beeps","xmpp","xri","ymsgr","z39.50r","z39.50s"];var he=16,jr=/^[\da-z+/\-_=]+$/i,ft=/data:[^,]*,/,Yt=/data:[^,]*;?base64,[\da-z+/\-_=]+/i,Wr=/data:[^,]*,[^"]+/g,Ie=/:$/,Yr=/(?:#|%23)$/,qr=/(?<!(?:#|%23).*)(?:\?|%3F)$/,Xr=/[<>"'\s]/g,Vr=/%(?:2(?:2|7)|3(?:C|E))/g,qt=/%(?:2(?:2|7)|3(?:C|E))+?/,Kr=/^(?:text\/(?:ht|x)ml|application\/(?:xhtml\+)?xml|image\/svg\+xml)/,Zr=/^\d+/,Qr=/#x?$/,Jr=/^#(?:x(?:00)?[2-7]|\d)/,ea=/^x[\dA-F]+/i,ta=/&#(x(?:00)?[\dA-F]{2}|0?\d{1,3});?/ig,ra=/^[a-z][\da-z+\-.]*$/,aa=/^(?:ext|web)\+[a-z]+$/,Xt=/(?:java|vb)script/,ut=/(?:java|vb)script|blob/,na=/^%[\dA-F]{2}$/i,ia=/%26/g,ht=a=>{if(!P(a))throw new TypeError(`Expected String but got ${J(a)}.`);let r=[];for(let s of a)r.push(`%${s.charCodeAt(0).toString(he).toUpperCase()}`);return r.join("")},Vt=a=>{P(a)&&na.test(a)&&(a=a.toUpperCase());let[r,s,u,c,y,g]=["&","#","<",">",'"',"'"].map(ht),d;return a===r?d=`${r}amp;`:a===u?d=`${r}lt;`:a===c?d=`${r}gt;`:a===y?d=`${r}quot;`:a===g?d=`${r}${s}39;`:d=a,d},oa=a=>{if(P(a)){if(!jr.test(a))throw new Error(`Invalid base64 data: ${a}`)}else throw new TypeError(`Expected String but got ${J(a)}.`);let r=atob(a),s=Uint8Array.from([...r].map(y=>y.charCodeAt(0))),u=new Set(pt),c;return s.every(y=>u.has(y))?c=r.replace(/\s/g,ht):c=a,c},Kt=(a,r=0)=>{if(!P(a))throw new TypeError(`Expected String but got ${J(a)}.`);if(Number.isInteger(r)){if(r>he)throw new Error("Character references nested too deeply.")}else throw new TypeError(`Expected Number but got ${J(r)}.`);let s=decodeURIComponent(a);if(/&#/.test(s)){let u=new Set(pt),c=[...s.matchAll(ta)].reverse();for(let y of c){let[g,d]=y,_;if(ea.test(d)?_=parseInt(`0${d}`,he):Zr.test(d)&&(_=parseInt(d)),Number.isInteger(_)){let{index:C}=y,[E,h]=[s.substring(0,C),s.substring(C+g.length)];u.has(_)?(s=`${E}${String.fromCharCode(_)}${h}`,(Qr.test(E)||Jr.test(h))&&(s=Kt(s,++r))):_<he*he&&(s=`${E}${h}`)}}}return s},sa=a=>new Promise((r,s)=>{let u=new ot;u.addEventListener("error",()=>s(u.error)),u.addEventListener("abort",()=>r(u.result)),u.addEventListener("load",()=>r(u.result)),u.readAsDataURL(a)}),mt=class{#e;constructor(){this.#e=new Set(Wt)}get(){return[...this.#e]}has(r){return this.#e.has(r)}add(r){if(P(r)){if(Xt.test(r)||!ra.test(r))throw new Error(`Invalid scheme: ${r}`)}else throw new TypeError(`Expected String but got ${J(r)}.`);return this.#e.add(r),[...this.#e]}remove(r){return this.#e.delete(r)}verify(r){let s;if(P(r))try{let{protocol:u}=new URL(r),c=u.replace(Ie,""),y=c.split("+");s=!Xt.test(c)&&aa.test(c)||y.every(g=>this.#e.has(g))}catch{s=!1}return!!s}},dt=class extends mt{#e;#t;constructor(){super(),this.#e=0,this.#t=new Set}replace(r){if(!P(r))throw new TypeError(`Expected String but got ${J(r)}.`);let s=r;if(ft.test(s)){let c=[...s.matchAll(Wr)].reverse();for(let y of c){let[g]=y;Yt.test(g)&&([g]=Yt.exec(g)),this.#e++,this.#t.add(g);let d=this.sanitize(g,{allow:["data"]}),{index:_}=y,[C,E]=[s.substring(0,_),s.substring(_+g.length)];d?s=`${C}${d}${E}`:s=`${C}${E}`}}return s}purify(r){if(!P(r))throw new TypeError(`Expected String but got ${J(r)}.`);let s=ct.default.sanitize(decodeURIComponent(r));return s&&ft.test(s)&&(s=this.replace(s)),s=s.replace(Yr,"").replace(qr,""),encodeURI(s)}sanitize(r,s={allow:[],deny:[],only:[]}){if(this.#e>he)throw this.#e=0,new Error("Data URLs nested too deeply.");let{allow:u,deny:c,only:y,remove:g}=s??{},d=new Map([["blob",!1],["data",!1],["file",!1],["javascrpt",!1],["vbscript",!1]]),_=!1;if(Array.isArray(y)&&y.length){let E=super.get();for(let b of E)d.set(b,!1);let h=Object.values(y);for(let b of h)if(P(b)&&(b=b.trim(),!ut.test(b))){if(super.has(b))d.set(b,!0);else{try{super.add(b)}catch{}super.has(b)&&d.set(b,!0)}!_&&d.has(b)&&(_=d.get(b))}}else{if(Array.isArray(u)&&u.length){let E=Object.values(u);for(let h of E)if(P(h)&&(h=h.trim(),!ut.test(h)))if(super.has(h))d.set(h,!0);else{try{super.add(h)}catch{}super.has(h)&&d.set(h,!0)}}if(Array.isArray(c)&&c.length){let E=Object.values(c);for(let h of E)P(h)&&(h=h.trim(),h&&d.set(h,!1))}}let C;if(super.verify(r)){let{hash:E,href:h,pathname:b,protocol:ie,search:ee}=new URL(r),T=ie.replace(Ie,""),I=T.split("+"),oe;if(_)oe=I.every(H=>d.get(H));else for(let[H,G]of d.entries())if(oe=G||T!==H&&I.every(x=>x!==H),!oe)break;if(oe){let H=I.includes("data"),G,x=h;if(H){let[te,...se]=b.split(","),B=`${se.join(",")}${ee}${E}`,X=te.split(";"),le=X[X.length-1]==="base64",F=B;le&&(F=oa(B));try{let Ae=Kt(F).trim(),{protocol:Ue}=new URL(Ae);Ue.replace(Ie,"").split("+").some(ve=>ut.test(ve))&&(x="")}catch{}let U=ft.test(F);F!==B||U?U?F=this.replace(F):this.#t.has(r)?this.#t.delete(r):G=!0:this.#t.has(r)?this.#t.delete(r):G=!0,(!te||Kr.test(te))&&(F=this.purify(F)),x&&F?(le&&F!==B&&X.pop(),x=`${T}:${X.join(";")},${F}`):x=""}else G=!0;if(!H&&g&&qt.test(x)){let te=qt.exec(x),{index:se}=te;x=x.substring(0,se)}x?(C=x.replace(Xr,ht).replace(ia,Vt),G&&(H||(C=C.replace(Vr,Vt)),this.#e=0)):(C=x,this.#e=0)}}return C||null}parse(r,s){if(!P(r))throw new TypeError(`Expected String but got ${J(r)}.`);let u=this.sanitize(r,s??{allow:["blob","data","file"]}),c=new Map([["input",r]]);if(u){let y=new URL(u),{pathname:g,protocol:d}=y,C=d.replace(Ie,"").split("+").includes("data");if(c.set("valid",!0),C){let E=new Map,[h,...b]=g.split(","),ie=`${b.join(",")}`,ee=h.split(";"),T=ee[ee.length-1]==="base64";T&&ee.pop(),E.set("mime",ee.join(";")),E.set("base64",T),E.set("data",ie),c.set("data",Object.fromEntries(E))}else c.set("data",null);for(let E in y){let h=y[E];P(h)&&c.set(E,h)}}else c.set("valid",!1);return Object.fromEntries(c)}},q=new dt,la=a=>q.verify(a),ca=async a=>q.verify(a),pa=a=>q.parse(a),fa=async a=>q.parse(a),ua=(a,r)=>{let s;if(q.verify(a)){let{protocol:u}=new URL(a);u==="blob:"?URL.revokeObjectURL(a):s=q.sanitize(a,r??{allow:[],deny:[],only:[]})}return s||null},ma=async(a,r={allow:[],deny:[],only:[]})=>{let s;if(q.verify(a)){let{protocol:u}=new URL(a);if(u==="blob:"){let{allow:c,deny:y,only:g}=r;if(Array.isArray(c)&&c.includes("blob")&&!(Array.isArray(y)&&y.includes("blob"))||Array.isArray(g)&&g.includes("blob")){let d;try{d=await fetch(a).then(_=>_.blob()).then(sa)}catch{}if(d){if(Array.isArray(g))g.includes("data")||g.push("data");else if(Array.isArray(c)&&(c.includes("data")||c.push("data"),Array.isArray(y)&&y.includes("data"))){let _=y.indexOf("data");y.splice(_,1)}s=q.sanitize(d,r)}}URL.revokeObjectURL(a)}else s=q.sanitize(a,r)}return s||null};export{q as default,ca as isURI,la as isURISync,fa as parseURL,pa as parseURLSync,ma as sanitizeURL,ua as sanitizeURLSync};
4
4
  /*!
5
5
  * URL Sanitizer
6
+ *
6
7
  * @license MIT
7
8
  * @copyright asamuzaK (Kazz)
8
9
  * @see {@link https://github.com/asamuzaK/urlSanitizer/blob/main/LICENSE}