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 +7 -2
- package/dist/url-sanitizer.js +1 -0
- package/dist/url-sanitizer.min.js +1 -0
- package/dist/url-sanitizer.wo.dompurify.js +1192 -0
- package/dist/url-sanitizer.wo.dompurify.js.map +7 -0
- package/dist/url-sanitizer.wo.dompurify.min.js +9 -0
- package/dist/url-sanitizer.wo.dompurify.min.js.map +7 -0
- package/package.json +5 -1
- package/src/index.js +1 -0
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(
|
|
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
|
|
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
|
|
package/dist/url-sanitizer.js
CHANGED
|
@@ -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}
|