url-sanitizer 0.5.5 → 0.6.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/README.md CHANGED
@@ -49,47 +49,65 @@ Sanitize the given URL.
49
49
  Returns **[Promise][5]<[string][1]?>** Sanitized URL, `null`able.
50
50
 
51
51
  ```javascript
52
- const res1 = await sanitizeURL('http://example.com/?<script>alert(1);</script>')
53
- .then(res => decodeURIComponent(res));
54
- // => 'http://example.com/?&lt;script&gt;alert(1);&lt;/script&gt;'
52
+ // Sanitize tags and quotes
53
+ const res1 = await sanitizeURL('http://example.com/"onmouseover="alert(1)"?<script>alert(\'XSS\');</script>');
54
+ // => 'http://example.com/%26quot;onmouseover=%26quot;alert(1)%26quot;?%26lt;script%26gt;alert(%26%2339;XSS%26%2339;);%26lt;/script%26gt;'
55
55
 
56
- const res2 = await sanitizeURL('data:text/html,<script>alert(1);</script>', {
56
+ console.log(decodeURIComponent(res1));
57
+ // => 'http://example.com/&quot;onmouseover=&quot;alert(1)&quot;?&lt;script&gt;alert(&#39;XSS&#39;);&lt;/script&gt;'
58
+
59
+ // Parse and purify data URL
60
+ const res2 = await sanitizeURL('data:text/html,<div><script>alert(1);</script></div><p onclick="alert(2)"></p>', {
57
61
  allow: ['data']
58
- }).then(res => decodeURIComponent(res));
59
- // => 'data:text/html,&lt;script&gt;alert(1);&lt;/script&gt;'
62
+ })
63
+ // -> 'data:text/html,%3Cdiv%3E%3C%2Fdiv%3E%3Cp%3E%3C%2Fp%3E'
64
+
65
+ console.log(decodeURIComponent(res2));
66
+ // => 'data:text/html,<div></div><p></p>'
60
67
 
61
- // Can parse and sanitize base64 encoded data
62
- const base64data3 = btoa('<script>alert(1);</script>');
68
+ // Can also parse and purify base64 encoded data
69
+ const base64data3 = btoa('<div><script>alert(1);</script></div>');
63
70
  const res3 = await sanitizeURL(`data:text/html;base64,${base64data3}`, {
64
71
  allow: ['data']
65
- }).then(res => decodeURIComponent(res));
66
- // => 'data:text/html,&lt;script&gt;alert(1);&lt;/script&gt;'
72
+ })
73
+ // => 'data:text/html,%3Cdiv%3E%3C%2Fdiv%3E'
74
+
75
+ console.log(decodeURIComponent(res3));
76
+ // => 'data:text/html,<div></div>'
77
+
78
+ const base64data4 = btoa('<div><iframe src="javascript:alert(1)"></iframe></div>');
79
+ const res4 = await sanitizeURL(`data:text/html;base64,${base64data4}`);
80
+ // => 'data:text/html,%3Cdiv%3E%3C%2Fdiv%3E'
81
+
82
+ console.log(decodeURIComponent(res4));
83
+ // => 'data:text/html,<div></div>'
67
84
 
68
- const res4 = await sanitizeURL('web+foo://example.com', {
85
+ const res5 = await sanitizeURL('web+foo://example.com', {
69
86
  deny: ['web+foo']
70
87
  });
71
88
  // => null
72
89
 
73
- const res5 = await sanitizeURL('http://example.com', {
90
+ const res6 = await sanitizeURL('http://example.com', {
74
91
  only: ['data', 'git', 'https']
75
92
  });
76
93
  // => null
77
94
 
78
- const res6 = await sanitizeURL('https://example.com/"onmouseover="alert(1)"', {
95
+ const res7 = await sanitizeURL('https://example.com/"onmouseover="alert(1)"', {
79
96
  only: ['data', 'git', 'https']
80
- }).then(res => decodeURIComponent(res));
81
- // => 'https://example.com/&quot;onmouseover=&quot;alert(1)&quot;'
97
+ });
98
+ // => 'https://example.com/%26quot;onmouseover=%26quot;alert(1)%26quot;'
82
99
 
83
- const res7 = await sanitizeURL('data:text/html,<script>alert(1);</script>', {
84
- only: ['data', 'git', 'https']
85
- }).then(res => decodeURIComponent(res));
86
- // => 'data:text/html,&lt;script&gt;alert(1);&lt;/script&gt;'
100
+ console.log(decodeURIComponent(res7));
101
+ // => 'https://example.com/&quot;onmouseover=&quot;alert(1)&quot;'
87
102
 
88
103
  // `only` option also allows combinations of the specified schemes
89
- const res8 = await sanitizeURL('git+https://example.com', {
104
+ const res8 = await sanitizeURL('git+https://example.com/foo.git?<script>alert(1)</script>', {
90
105
  only: ['data', 'git', 'https']
91
- }).then(res => decodeURIComponent(res));;
92
- // => 'git+https://example.com'
106
+ });
107
+ // => 'git+https://example.com/foo.git?%26lt;script%26gt;alert(1)%26lt;/script%26gt;'
108
+
109
+ console.log(decodeURIComponent(res8));
110
+ // => 'git+https://example.com/foo.git?&lt;script&gt;alert(1)&lt;/script&gt;'
93
111
  ```
94
112
 
95
113
 
@@ -122,18 +140,18 @@ Type: [object][3]
122
140
  * `data.mime` **[string][1]** MIME type.
123
141
  * `data.base64` **[boolean][2]** `true` if base64 encoded.
124
142
  * `data.data` **[string][1]** Data part of the data URL.
125
- * `href` **[string][1]** Same as URL API.
126
- * `origin` **[string][1]** Same as URL API.
127
- * `protocol` **[string][1]** Same as URL API.
128
- * `username` **[string][1]** Same as URL API.
129
- * `password` **[string][1]** Same as URL API.
130
- * `host` **[string][1]** Same as URL API.
131
- * `hostname` **[string][1]** Same as URL API.
132
- * `port` **[string][1]** Same as URL API.
133
- * `pathname` **[string][1]** Same as URL API.
134
- * `search` **[string][1]** Same as URL API.
135
- * `searchParams` **[object][3]** Same as URL API.
136
- * `hash` **[string][1]** Same as URL API.
143
+ * `href` **[string][1]** Sanitized URL input.
144
+ * `origin` **[string][1]** Scheme, domain and port of the sanitized URL.
145
+ * `protocol` **[string][1]** Protocol scheme of the sanitized URL.
146
+ * `username` **[string][1]** Username specified before the domain name.
147
+ * `password` **[string][1]** Password specified before the domain name.
148
+ * `host` **[string][1]** Domain and port of the sanitized URL.
149
+ * `hostname` **[string][1]** Domain of the sanitized URL.
150
+ * `port` **[string][1]** Port number of the sanitized URL.
151
+ * `pathname` **[string][1]** Path of the sanitized URL.
152
+ * `search` **[string][1]** Query string of the sanitized URL.
153
+ * `searchParams` **[object][3]** [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) object.
154
+ * `hash` **[string][1]** Fragment identifier of the sanitized URL.
137
155
 
138
156
  ```javascript
139
157
  const res1 = await parseURL('javascript:alert(1)');
@@ -144,50 +162,52 @@ const res1 = await parseURL('javascript:alert(1)');
144
162
 
145
163
  const res2 = await parseURL('https://example.com/?foo=bar#baz');
146
164
  /* => {
147
- input: 'https://www.example.com/?foo=bar#baz',
148
- valid: true,
149
- data: null,
150
- href: 'https://www.example.com/?foo=bar#baz',
151
- origin: 'https://www.example.com',
152
- protocol: 'https:',
153
- hostname: 'www.example.com',
154
- pathname: '/',
155
- search: '?foo=bar',
156
- hash: '#baz',
157
- ...
158
- } */
159
-
160
- // base64 encoded svg '<svg><g onload="alert(1)"/></svg>'
161
- const res3 = await parseURL('data:image/svg+xml;base64,PHN2Zz48ZyBvbmxvYWQ9ImFsZXJ0KDEpIi8+PC9zdmc+');
165
+ input: 'https://www.example.com/?foo=bar#baz',
166
+ valid: true,
167
+ data: null,
168
+ href: 'https://www.example.com/?foo=bar#baz',
169
+ origin: 'https://www.example.com',
170
+ protocol: 'https:',
171
+ hostname: 'www.example.com',
172
+ pathname: '/',
173
+ search: '?foo=bar',
174
+ hash: '#baz',
175
+ ...
176
+ } */
177
+
178
+ // base64 encoded SVG '<svg><g onclick="alert(1)"/></svg>'
179
+ const res3 = await parseURL('data:image/svg+xml;base64,PHN2Zz48ZyBvbmNsaWNrPSJhbGVydCgxKSIvPjwvc3ZnPg==');
162
180
  /* => {
163
- input: 'data:image/svg+xml;base64,PHN2Zz48ZyBvbmxvYWQ9ImFsZXJ0KDEpIi8+PC9zdmc+',
164
- valid: true,
165
- data: {
166
- mime: 'image/svg+xml',
167
- base64: false,
168
- data: '%26lt;svg%26gt;%26lt;g%20onload=%26quot;alert(1)%26quot;/%26gt;%26lt;/svg%26gt;'
169
- },
170
- href: 'data:image/svg+xml,%26lt;svg%26gt;%26lt;g%20onload=%26quot;alert(1)%26quot;/%26gt;%26lt;/svg%26gt;',
171
- protocol: 'data:',
172
- pathname: 'image/svg+xml,%26lt;svg%26gt;%26lt;g%20onload=%26quot;alert(1)%26quot;/%26gt;%26lt;/svg%26gt;',
173
- ...
174
- } */
181
+ input: 'data:image/svg+xml;base64,PHN2Zz48ZyBvbmNsaWNrPSJhbGVydCgxKSIvPjwvc3ZnPg==',
182
+ valid: true,
183
+ data: {
184
+ mime: 'image/svg+xml',
185
+ base64: false,
186
+ data: '%3Csvg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
187
+ },
188
+ href: 'data:image/svg+xml,%3Csvg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E',
189
+ origin: 'null',
190
+ protocol: 'data:',
191
+ pathname: 'image/svg+xml,%3Csvg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E',
192
+ ...
193
+ } */
175
194
 
176
195
  // base64 encoded png
177
196
  const res4 = await parseURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==');
178
197
  /* => {
179
- input: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==',
180
- valid: true,
181
- data: {
182
- mime: 'image/png',
183
- base64: true,
184
- data: 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='
185
- },
186
- href: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==',
187
- protocol: 'data:',
188
- pathname: 'image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==',
189
- ...
190
- } */
198
+ input: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==',
199
+ valid: true,
200
+ data: {
201
+ mime: 'image/png',
202
+ base64: true,
203
+ data: 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='
204
+ },
205
+ href: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==',
206
+ origin: 'null',
207
+ protocol: 'data:',
208
+ pathname: 'image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==',
209
+ ...
210
+ } */
191
211
  ```
192
212
 
193
213
 
@@ -211,16 +231,19 @@ Returns **[Promise][5]<[boolean][2]>** Result.
211
231
  const res1 = await isURI('https://example.com/foo');
212
232
  // => true
213
233
 
214
- const res2 = await isURI('mailto:foo@example.com');
234
+ const res2 = await isURI('javascript:alert(1)');
235
+ // => false
236
+
237
+ const res3 = await isURI('mailto:foo@example.com');
215
238
  // => true
216
239
 
217
- const res3 = await isURI('foo:bar');
240
+ const res4 = await isURI('foo:bar');
218
241
  // => false
219
242
 
220
- const res4 = await isURI('web+foo:bar');
243
+ const res5 = await isURI('web+foo:bar');
221
244
  // => true
222
245
 
223
- const res5 = await isURI('web+javascript:alert(1)');
246
+ const res6 = await isURI('web+javascript:alert(1)');
224
247
  // => false
225
248
  ```
226
249
 
@@ -237,11 +260,13 @@ Instance of the sanitizer.
237
260
 
238
261
  ### urlSanitizer.get()
239
262
 
240
- Get an array of URI schemes registered at [iana.org](https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml "Uniform Resource Identifier (URI) Schemes").
241
- * Historical schemes omitted.
242
- * `moz-extension` scheme added.
263
+ Get a list of registered URI schemes.
243
264
 
244
265
  Returns **[Array][4]<[string][1]>** Array of registered URI schemes.
266
+ * Includes schemes registered at [iana.org](https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml "Uniform Resource Identifier (URI) Schemes") by default.
267
+ * Historical schemes omitted.
268
+ * `moz-extension` scheme added.
269
+ * Also includes custom schemes added via [urlSanitizer.add()](#urlsanitizeraddscheme).
245
270
 
246
271
  ```javascript
247
272
  const schemes = urlSanitizer.get();
@@ -268,7 +293,7 @@ const res2 = urlSanitizer.has('foo');
268
293
 
269
294
  ### urlSanitizer.add(scheme)
270
295
 
271
- Add a scheme to the list of URI schemes.
296
+ Add a scheme to the list of registered URI schemes.
272
297
  * `javascript` and `vbscript` schemes can not be registered. It throws.
273
298
 
274
299
  #### Parameters
@@ -278,19 +303,19 @@ Add a scheme to the list of URI schemes.
278
303
  Returns **[Array][4]<[string][1]>** Array of registered URI schemes.
279
304
 
280
305
  ```javascript
281
- console.log(isURISync('foo'));
306
+ console.log(urlSanitizer.has('foo'));
282
307
  // => false
283
308
 
284
309
  const res = urlSanitizer.add('foo');
285
310
  // => ['aaa', 'aaas', 'about', 'acap', ... 'foo', ...]
286
311
 
287
- console.log(isURISync('foo'));
312
+ console.log(urlSanitizer.has('foo'));
288
313
  // => true
289
314
  ```
290
315
 
291
316
  ### urlSanitizer.remove(scheme)
292
317
 
293
- Remove a scheme from the list of URI schemes.
318
+ Remove a scheme from the list of registered URI schemes.
294
319
 
295
320
  #### Parameters
296
321
 
@@ -300,13 +325,13 @@ Returns **[boolean][2]** Result.
300
325
  * `true` if the scheme is successfully removed, `false` otherwise.
301
326
 
302
327
  ```javascript
303
- console.log(isURISync('aaa'));
328
+ console.log(urlSanitizer.has('aaa'));
304
329
  // => true
305
330
 
306
331
  const res1 = urlSanitizer.remove('aaa');
307
332
  // => true
308
333
 
309
- console.log(isURISync('aaa'));
334
+ console.log(urlSanitizer.has('aaa'));
310
335
  // => false
311
336
 
312
337
  const res2 = urlSanitizer.remove('foo');
@@ -319,6 +344,7 @@ const res2 = urlSanitizer.remove('foo');
319
344
 
320
345
  The following resources have been of great help in the development of the URL Sanitizer.
321
346
 
347
+ * [DOMPurify](https://www.npmjs.com/package/dompurify?activeTab=readme)
322
348
  * [Uniform Resource Identifier (URI) Schemes - IANA](https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml)
323
349
  * [Encoding -- determine the character encoding of a text file. - file/file](https://github.com/file/file/blob/master/src/encoding.c)
324
350