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 +112 -86
- package/dist/url-sanitizer.js +1112 -29
- package/dist/url-sanitizer.js.map +4 -4
- package/dist/url-sanitizer.min.js +8 -1
- package/dist/url-sanitizer.min.js.map +4 -4
- package/index.js +2 -1
- package/package.json +13 -6
- package/src/mjs/dompurify.esm.js +5 -0
- package/src/mjs/dompurify.js +13 -0
- package/src/mjs/uri-util.js +109 -25
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
|
-
|
|
53
|
-
|
|
54
|
-
// => 'http://example.com
|
|
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
|
-
|
|
56
|
+
console.log(decodeURIComponent(res1));
|
|
57
|
+
// => 'http://example.com/"onmouseover="alert(1)"?<script>alert('XSS');</script>'
|
|
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
|
-
})
|
|
59
|
-
//
|
|
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
|
|
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
|
-
})
|
|
66
|
-
// => 'data:text/html
|
|
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
|
|
85
|
+
const res5 = await sanitizeURL('web+foo://example.com', {
|
|
69
86
|
deny: ['web+foo']
|
|
70
87
|
});
|
|
71
88
|
// => null
|
|
72
89
|
|
|
73
|
-
const
|
|
90
|
+
const res6 = await sanitizeURL('http://example.com', {
|
|
74
91
|
only: ['data', 'git', 'https']
|
|
75
92
|
});
|
|
76
93
|
// => null
|
|
77
94
|
|
|
78
|
-
const
|
|
95
|
+
const res7 = await sanitizeURL('https://example.com/"onmouseover="alert(1)"', {
|
|
79
96
|
only: ['data', 'git', 'https']
|
|
80
|
-
})
|
|
81
|
-
// => 'https://example.com
|
|
97
|
+
});
|
|
98
|
+
// => 'https://example.com/%26quot;onmouseover=%26quot;alert(1)%26quot;'
|
|
82
99
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}).then(res => decodeURIComponent(res));
|
|
86
|
-
// => 'data:text/html,<script>alert(1);</script>'
|
|
100
|
+
console.log(decodeURIComponent(res7));
|
|
101
|
+
// => 'https://example.com/"onmouseover="alert(1)"'
|
|
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
|
-
})
|
|
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?<script>alert(1)</script>'
|
|
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]**
|
|
126
|
-
* `origin` **[string][1]**
|
|
127
|
-
* `protocol` **[string][1]**
|
|
128
|
-
* `username` **[string][1]**
|
|
129
|
-
* `password` **[string][1]**
|
|
130
|
-
* `host` **[string][1]**
|
|
131
|
-
* `hostname` **[string][1]**
|
|
132
|
-
* `port` **[string][1]**
|
|
133
|
-
* `pathname` **[string][1]**
|
|
134
|
-
* `search` **[string][1]**
|
|
135
|
-
* `searchParams` **[object][3]**
|
|
136
|
-
* `hash` **[string][1]**
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
} */
|
|
159
|
-
|
|
160
|
-
// base64 encoded
|
|
161
|
-
const res3 = await parseURL('data:image/svg+xml;base64,
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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('
|
|
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
|
|
240
|
+
const res4 = await isURI('foo:bar');
|
|
218
241
|
// => false
|
|
219
242
|
|
|
220
|
-
const
|
|
243
|
+
const res5 = await isURI('web+foo:bar');
|
|
221
244
|
// => true
|
|
222
245
|
|
|
223
|
-
const
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|