sanitize-html 1.19.0 → 1.20.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/test/test.js DELETED
@@ -1,801 +0,0 @@
1
- var assert = require("assert");
2
- describe('sanitizeHtml', function() {
3
- var sanitizeHtml;
4
- it('should be successfully initialized', function() {
5
- sanitizeHtml = require('../dist/index.js');
6
- });
7
- it('should pass through simple well-formed whitelisted markup', function() {
8
- assert.equal(sanitizeHtml('<div><p>Hello <b>there</b></p></div>'), '<div><p>Hello <b>there</b></p></div>');
9
- });
10
- it('should pass through all markup if allowedTags and allowedAttributes are set to false', function() {
11
- assert.equal(sanitizeHtml('<div><wiggly worms="ewww">hello</wiggly></div>', {
12
- allowedTags: false,
13
- allowedAttributes: false
14
- }), '<div><wiggly worms="ewww">hello</wiggly></div>');
15
- });
16
- it('should respect text nodes at top level', function() {
17
- assert.equal(sanitizeHtml('Blah blah blah<p>Whee!</p>'), 'Blah blah blah<p>Whee!</p>');
18
- });
19
- it('should reject markup not whitelisted without destroying its text', function() {
20
- assert.equal(sanitizeHtml('<div><wiggly>Hello</wiggly></div>'), '<div>Hello</div>');
21
- });
22
- it('should accept a custom list of allowed tags', function() {
23
- assert.equal(sanitizeHtml('<blue><red><green>Cheese</green></red></blue>', { allowedTags: [ 'blue', 'green' ] }), '<blue><green>Cheese</green></blue>');
24
- });
25
- it('should reject attributes not whitelisted', function() {
26
- assert.equal(sanitizeHtml('<a href="foo.html" whizbang="whangle">foo</a>'), '<a href="foo.html">foo</a>');
27
- });
28
- it('should accept a custom list of allowed attributes per element', function() {
29
- assert.equal(sanitizeHtml('<a href="foo.html" whizbang="whangle">foo</a>', { allowedAttributes: { a: [ 'href', 'whizbang' ] } } ), '<a href="foo.html" whizbang="whangle">foo</a>');
30
- });
31
- it('should clean up unclosed img tags and p tags', function() {
32
- assert.equal(sanitizeHtml('<img src="foo.jpg"><p>Whee<p>Again<p>Wow<b>cool</b>', { allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'img' ])}), '<img src="foo.jpg" /><p>Whee</p><p>Again</p><p>Wow<b>cool</b></p>');
33
- });
34
- it('should reject hrefs that are not relative, ftp, http, https or mailto', function() {
35
- assert.equal(sanitizeHtml('<a href="http://google.com">google</a><a href="https://google.com">https google</a><a href="ftp://example.com">ftp</a><a href="mailto:test@test.com">mailto</a><a href="/relative.html">relative</a><a href="javascript:alert(0)">javascript</a>'), '<a href="http://google.com">google</a><a href="https://google.com">https google</a><a href="ftp://example.com">ftp</a><a href="mailto:test@test.com">mailto</a><a href="/relative.html">relative</a><a>javascript</a>');
36
- });
37
- it('should cope identically with capitalized attributes and tags and should tolerate capitalized schemes', function() {
38
- assert.equal(sanitizeHtml('<A HREF="http://google.com">google</a><a href="HTTPS://google.com">https google</a><a href="ftp://example.com">ftp</a><a href="mailto:test@test.com">mailto</a><a href="/relative.html">relative</a><a href="javascript:alert(0)">javascript</a>'), '<a href="http://google.com">google</a><a href="HTTPS://google.com">https google</a><a href="ftp://example.com">ftp</a><a href="mailto:test@test.com">mailto</a><a href="/relative.html">relative</a><a>javascript</a>');
39
- });
40
- it('should drop the content of script elements', function() {
41
- assert.equal(sanitizeHtml('<script>alert("ruhroh!");</script><p>Paragraph</p>'), '<p>Paragraph</p>');
42
- });
43
- it('should drop the content of style elements', function() {
44
- assert.equal(sanitizeHtml('<style>.foo { color: blue; }</style><p>Paragraph</p>'), '<p>Paragraph</p>');
45
- });
46
- it('should drop the content of textarea elements', function() {
47
- assert.equal(sanitizeHtml('<textarea>Nifty</textarea><p>Paragraph</p>'), '<p>Paragraph</p>');
48
- });
49
- it('should drop the content of textarea elements but keep the closing parent tag, when nested', function() {
50
- assert.equal(sanitizeHtml('<p>Paragraph<textarea>Nifty</textarea></p>'), '<p>Paragraph</p>');
51
- });
52
- it('should retain the content of fibble elements by default', function() {
53
- assert.equal(sanitizeHtml('<fibble>Nifty</fibble><p>Paragraph</p>'), 'Nifty<p>Paragraph</p>');
54
- });
55
- it('should discard the content of fibble elements if specified for nonTextTags', function() {
56
- assert.equal(sanitizeHtml('<fibble>Nifty</fibble><p>Paragraph</p>', { nonTextTags: [ 'fibble' ] }), '<p>Paragraph</p>');
57
- });
58
- it('should retain allowed tags within a fibble element if fibble is not specified for nonTextTags', function() {
59
- assert.equal(sanitizeHtml('<fibble>Ni<em>f</em>ty</fibble><p>Paragraph</p>', {}), 'Ni<em>f</em>ty<p>Paragraph</p>');
60
- });
61
- it('should discard allowed tags within a fibble element if fibble is specified for nonTextTags', function() {
62
- assert.equal(sanitizeHtml('<fibble>Ni<em>f</em>ty</fibble><p>Paragraph</p>', { nonTextTags: [ 'fibble' ] }), '<p>Paragraph</p>');
63
- });
64
- it('should preserve textarea content if textareas are allowed', function() {
65
- assert.equal(sanitizeHtml('<textarea>Nifty</textarea><p>Paragraph</p>', {
66
- allowedTags: [ 'textarea', 'p' ]
67
- }), '<textarea>Nifty</textarea><p>Paragraph</p>');
68
- });
69
- it('should preserve entities as such', function() {
70
- assert.equal(sanitizeHtml('<a name="&lt;silly&gt;">&lt;Kapow!&gt;</a>'), '<a name="&lt;silly&gt;">&lt;Kapow!&gt;</a>');
71
- });
72
- it('should dump comments', function() {
73
- assert.equal(sanitizeHtml('<p><!-- Blah blah -->Whee</p>'), '<p>Whee</p>');
74
- });
75
- it('should dump a sneaky encoded javascript url', function() {
76
- assert.equal(sanitizeHtml('<a href="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;">Hax</a>'), '<a>Hax</a>');
77
- });
78
- it('should dump an uppercase javascript url', function() {
79
- assert.equal(sanitizeHtml('<a href="JAVASCRIPT:alert(\'foo\')">Hax</a>'), '<a>Hax</a>');
80
- });
81
- it('should dump a javascript URL with a comment in the middle (probably only respected by browsers in XML data islands, but just in case someone enables those)', function() {
82
- assert.equal(sanitizeHtml('<a href="java<!-- -->script:alert(\'foo\')">Hax</a>'), '<a>Hax</a>');
83
- });
84
- it('should not mess up a hashcode with a : in it', function() {
85
- assert.equal(sanitizeHtml('<a href="awesome.html#this:stuff">Hi</a>'), '<a href="awesome.html#this:stuff">Hi</a>');
86
- });
87
- it('should dump character codes 1-32 before testing scheme', function() {
88
- assert.equal(sanitizeHtml('<a href="java\0&#14;\t\r\n script:alert(\'foo\')">Hax</a>'), '<a>Hax</a>');
89
- });
90
- it('should dump character codes 1-32 even when escaped with padding rather than trailing ;', function() {
91
- assert.equal(sanitizeHtml('<a href="java&#0000001script:alert(\'foo\')">Hax</a>'), '<a>Hax</a>');
92
- // This one is weird, but the browser does not interpret it
93
- // as a scheme, so we're OK. That character is 65535, not null. I
94
- // think it's a limitation of the entities module
95
- assert.equal(sanitizeHtml('<a href="java&#0000000script:alert(\'foo\')">Hax</a>'), '<a href="java�script:alert(\'foo\')">Hax</a>');
96
- });
97
- it('should still like nice schemes', function() {
98
- assert.equal(sanitizeHtml('<a href="http://google.com/">Hi</a>'), '<a href="http://google.com/">Hi</a>');
99
- });
100
- it('should still like nice relative URLs', function() {
101
- assert.equal(sanitizeHtml('<a href="hello.html">Hi</a>'), '<a href="hello.html">Hi</a>');
102
- });
103
- it('should replace ol to ul', function() {
104
- assert.equal(sanitizeHtml('<ol><li>Hello world</li></ol>', { transformTags: {ol: 'ul'} }), '<ul><li>Hello world</li></ul>');
105
- });
106
- it('should replace ol to ul and add class attribute with foo value', function() {
107
- assert.equal(sanitizeHtml('<ol><li>Hello world</li></ol>', { transformTags: {ol: sanitizeHtml.simpleTransform('ul', {class: 'foo'})}, allowedAttributes: { ul: ['class'] } }), '<ul class="foo"><li>Hello world</li></ul>');
108
- });
109
- it('should replace ol to ul, left attributes foo and bar untouched, remove baz attribute and add class attributte with foo value', function() {
110
- assert.equal(sanitizeHtml('<ol foo="foo" bar="bar" baz="baz"><li>Hello world</li></ol>', { transformTags: {ol: sanitizeHtml.simpleTransform('ul', {class: 'foo'})}, allowedAttributes: { ul: ['foo', 'bar', 'class'] } }), '<ul foo="foo" bar="bar" class="foo"><li>Hello world</li></ul>');
111
- });
112
- it('should replace ol to ul and replace all attributes to class attribute with foo value', function() {
113
- assert.equal(sanitizeHtml('<ol foo="foo" bar="bar" baz="baz"><li>Hello world</li></ol>', { transformTags: {ol: sanitizeHtml.simpleTransform('ul', {class: 'foo'}, false)}, allowedAttributes: { ul: ['foo', 'bar', 'class'] } }), '<ul class="foo"><li>Hello world</li></ul>');
114
- });
115
- it('should replace ol to ul and add attribute class with foo value and attribute bar with bar value', function() {
116
- assert.equal(sanitizeHtml('<ol><li>Hello world</li></ol>', { transformTags: {ol: function(tagName, attribs){
117
- attribs.class = 'foo';
118
- attribs.bar = 'bar';
119
- return {
120
- tagName: 'ul',
121
- attribs: attribs
122
- }
123
- }}, allowedAttributes: { ul: ['bar', 'class'] } }), '<ul class="foo" bar="bar"><li>Hello world</li></ul>');
124
- });
125
-
126
- it('should replace text and attributes when they are changed by transforming function', function () {
127
- assert.equal(sanitizeHtml('<a href="http://somelink">some text</a>', { transformTags: {a: function (tagName, attribs) {
128
- return {
129
- tagName: tagName,
130
- attribs: attribs,
131
- text: ''
132
- }
133
- }}}), '<a href="http://somelink"></a>');
134
- });
135
- it('should replace text and attributes when they are changed by transforming function and textFilter is set', function () {
136
- assert.equal(sanitizeHtml('<a href="http://somelink">some text</a>', { transformTags: {a: function (tagName, attribs) {
137
- return {
138
- tagName: tagName,
139
- attribs: attribs,
140
- text: 'some text need"to<be>filtered'
141
- }
142
- }}, textFilter: function (text) {
143
- return text.replace(/\s/g, '_');
144
- }}), '<a href="http://somelink">some_text_need&quot;to&lt;be&gt;filtered</a>');
145
- });
146
-
147
- it('should add new text when not initially set and replace attributes when they are changed by transforming function', function () {
148
- assert.equal(sanitizeHtml('<a href="http://somelink"></a>', { transformTags: {a: function (tagName, attribs) {
149
- return {
150
- tagName: tagName,
151
- attribs: attribs,
152
- text: 'some new text'
153
- }
154
- }}}), '<a href="http://somelink">some new text</a>');
155
- });
156
-
157
- it('should preserve text when initially set and replace attributes when they are changed by transforming function', function () {
158
- assert.equal(sanitizeHtml('<a href="http://somelink">some initial text</a>', { transformTags: {a: function (tagName, attribs) {
159
- return {
160
- tagName: tagName,
161
- attribs: attribs
162
- }
163
- }}}), '<a href="http://somelink">some initial text</a>');
164
- });
165
-
166
- it('should skip an empty link', function() {
167
- assert.strictEqual(
168
- sanitizeHtml('<p>This is <a href="http://www.linux.org"></a><br/>Linux</p>', {
169
- exclusiveFilter: function (frame) {
170
- return frame.tag === 'a' && !frame.text.trim();
171
- }
172
- }),
173
- '<p>This is <br />Linux</p>'
174
- );
175
- });
176
-
177
- it("Should expose a node's inner text and inner HTML to the filter", function() {
178
- assert.strictEqual(
179
- sanitizeHtml('<p>12<a href="http://www.linux.org"><br/>3<br></a><span>4</span></p>', {
180
- exclusiveFilter : function(frame) {
181
- if (frame.tag === 'p') {
182
- assert.strictEqual(frame.text, '124');
183
- } else if (frame.tag === 'a') {
184
- assert.strictEqual(frame.text, '3');
185
- return true;
186
- } else if (frame.tag === 'br') {
187
- assert.strictEqual(frame.text, '');
188
- } else {
189
- assert.fail('p, a, br', frame.tag);
190
- }
191
- return false;
192
- }
193
- }),
194
- '<p>124</p>'
195
- );
196
- });
197
-
198
- it('Should collapse nested empty elements', function() {
199
- assert.strictEqual(
200
- sanitizeHtml('<p><a href="http://www.linux.org"><br/></a></p>', {
201
- exclusiveFilter : function(frame) {
202
- return (frame.tag === 'a' || frame.tag === 'p' ) && !frame.text.trim();
203
- }
204
- }),
205
- ''
206
- );
207
- });
208
- it('Exclusive filter should not affect elements which do not match the filter condition', function () {
209
- assert.strictEqual(
210
- sanitizeHtml('I love <a href="www.linux.org" target="_hplink">Linux</a> OS',
211
- {
212
- exclusiveFilter: function (frame) {
213
- return (frame.tag === 'a') && !frame.text.trim();
214
- }
215
- }),
216
- 'I love <a href="www.linux.org" target="_hplink">Linux</a> OS'
217
- );
218
- });
219
- it('should disallow data URLs with default allowedSchemes', function() {
220
- assert.equal(
221
- sanitizeHtml(
222
- // teeny-tiny valid transparent GIF in a data URL
223
- '<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />',
224
- {
225
- allowedTags: [ 'img' ]
226
- }
227
- ),
228
- '<img />'
229
- );
230
- });
231
- it('should allow data URLs with custom allowedSchemes', function() {
232
- assert.equal(
233
- sanitizeHtml(
234
- // teeny-tiny valid transparent GIF in a data URL
235
- '<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />',
236
- {
237
- allowedTags: [ 'img', 'p' ],
238
- allowedSchemes: [ 'data', 'http' ]
239
- }
240
- ),
241
- '<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />'
242
- );
243
- });
244
- it('should allow specific classes when whitelisted with allowedClasses', function() {
245
- assert.equal(
246
- sanitizeHtml(
247
- '<p class="nifty simple dippy">whee</p>',
248
- {
249
- allowedTags: [ 'p' ],
250
- allowedClasses: {
251
- p: [ 'nifty' ]
252
- }
253
- }
254
- ),
255
- '<p class="nifty">whee</p>'
256
- );
257
- });
258
- it('should allow defining schemes on a per-tag basis', function() {
259
- assert.equal(
260
- sanitizeHtml(
261
- // teeny-tiny valid transparent GIF in a data URL
262
- '<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" /><a href="https://www.example.com"></a>',
263
- {
264
- allowedTags: ['img', 'a'],
265
- allowedSchemes: ['http'],
266
- allowedSchemesByTag: {
267
- img: ['data'],
268
- a: ['https']
269
- }
270
- }
271
- ),
272
- '<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" /><a href="https://www.example.com"></a>'
273
- );
274
- assert.equal(
275
- sanitizeHtml(
276
- // teeny-tiny valid transparent GIF in a data URL
277
- '<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" /><a href="https://www.example.com"></a>',
278
- {
279
- allowedTags: ['img', 'a'],
280
- allowedSchemes: ['http'],
281
- allowedSchemesByTag: {
282
- img: [],
283
- a: ['https']
284
- }
285
- }
286
- ),
287
- '<img /><a href="https://www.example.com"></a>'
288
- );
289
- });
290
- it('should not act weird when the class attribute is empty', function() {
291
- assert.equal(
292
- sanitizeHtml(
293
- '<p class="">whee</p>',
294
- {
295
- allowedTags: [ 'p' ],
296
- allowedClasses: {
297
- p: [ 'nifty' ]
298
- }
299
- }
300
- ),
301
- '<p>whee</p>'
302
- );
303
- });
304
- it('should not crash on bad markup', function() {
305
- assert.equal(
306
- sanitizeHtml(
307
- "<p a"
308
- ),
309
- ''
310
- );
311
- });
312
- it('should not allow a naked = sign followed by an unrelated attribute to result in one merged attribute with unescaped double quote marks', function() {
313
- assert.equal(
314
- sanitizeHtml(
315
- '<IMG SRC= onmouseover="alert(\'XSS\');">',
316
- {
317
- allowedTags: [ 'img' ],
318
- allowedAttributes: {
319
- img: [ 'src' ]
320
- }
321
- }
322
- ),
323
- // This is weird but not dangerous. Without the &quot there
324
- // would probably be some way to make it come out as a
325
- // separate attribute
326
- '<img src="onmouseover=&quot;alert(\'XSS\');&quot;" />'
327
- );
328
- });
329
- it('should allow only whitelisted attributes, but to any tags, if tag is declared as "*"', function() {
330
- assert.equal(
331
- sanitizeHtml(
332
- '<table bgcolor="1" align="left" notlisted="0"><img src="1.gif" align="center" alt="not listed too"/></table>',
333
- {
334
- allowedTags: [ 'table', 'img' ],
335
- allowedAttributes: {
336
- '*': [ 'bgcolor', 'align', 'src' ]
337
- }
338
- }
339
- ),
340
- '<table bgcolor="1" align="left"><img src="1.gif" align="center" /></table>'
341
- );
342
- });
343
- it('should not filter if exclusive filter does not match after transforming tags', function() {
344
- assert.equal(
345
- sanitizeHtml(
346
- '<a href="test.html">test</a>',
347
- {
348
- allowedTags: [ 'a' ],
349
- allowedAttributes: { a: ['href', 'target']},
350
- transformTags: {
351
- 'a': function (tagName, attribs) {
352
- if (!attribs.href)
353
- return false;
354
- return {
355
- tagName: tagName,
356
- attribs: {
357
- target: '_blank',
358
- href: attribs.href
359
- }
360
- };
361
- }
362
- },
363
- exclusiveFilter: function(frame) {
364
- return frame.tag === 'a' && frame.text.trim() == 'blah';
365
- }
366
- }
367
- ),
368
- '<a target="_blank" href="test.html">test</a>'
369
- )
370
- });
371
- it('should filter if exclusive filter does match after transforming tags', function() {
372
- assert.equal(
373
- sanitizeHtml(
374
- '<a href="test.html">blah</a>',
375
- {
376
- allowedTags: [ 'a' ],
377
- allowedAttributes: {a: ['href', 'target']},
378
- transformTags: {
379
- 'a': function (tagName, attribs) {
380
- if (!attribs.href)
381
- return false;
382
- return {
383
- tagName: tagName,
384
- attribs: {
385
- target: '_blank',
386
- href: attribs.href
387
- }
388
- };
389
- }
390
- },
391
- exclusiveFilter: function(frame) {
392
- return frame.tag === 'a' && frame.text.trim() == 'blah';
393
- }
394
- }
395
- ),
396
- ''
397
- );
398
- });
399
- it('should allow transform on all tags using \'*\'', function () {
400
- assert.equal(
401
- sanitizeHtml(
402
- '<p>Text</p>',
403
- {
404
- allowedTags: [ 'p' ],
405
- allowedAttributes: {p: ['style']},
406
- transformTags: {
407
- '*': function (tagName, attribs) {
408
- return {
409
- tagName: tagName,
410
- attribs: {
411
- style: 'text-align: center;'
412
- }
413
- };
414
- }
415
- }
416
- }
417
- ),
418
- '<p style="text-align:center;">Text</p>'
419
- );
420
- });
421
- it('should not be faked out by double <', function() {
422
- assert.equal(
423
- sanitizeHtml('<<img src="javascript:evil"/>img src="javascript:evil"/>'
424
- ),
425
- '&lt;img src=&quot;javascript:evil&quot;/&gt;'
426
- );
427
- assert.equal(
428
- sanitizeHtml('<<a href="javascript:evil"/>a href="javascript:evil"/>'
429
- ),
430
- '&lt;<a>a href=&quot;javascript:evil&quot;/&gt;</a>'
431
- );
432
- });
433
- it('should allow attributes to be specified as globs', function() {
434
- assert.equal(
435
- sanitizeHtml('<a data-target="#test" data-foo="hello">click me</a>', {
436
- allowedTags: [ 'a' ],
437
- allowedAttributes: { a: ['data-*'] }
438
- }), '<a data-target="#test" data-foo="hello">click me</a>'
439
- );
440
- assert.equal(
441
- sanitizeHtml('<a data-target="#test" data-my-foo="hello">click me</a>', {
442
- allowedTags: [ 'a' ],
443
- allowedAttributes: { a: ['data-*-foo'] }
444
- }), '<a data-my-foo="hello">click me</a>'
445
- );
446
- });
447
- it('should quote regex chars in attributes specified as globs', function() {
448
- assert.equal(
449
- sanitizeHtml('<a data-b.c="#test" data-bcc="remove this">click me</a>', {
450
- allowedTags: [ 'a' ],
451
- allowedAttributes: { a: ['data-b.*'] }
452
- }), '<a data-b.c="#test">click me</a>'
453
- );
454
- });
455
- it('should not escape inner content of script and style tags (when allowed)', function() {
456
- assert.equal(
457
- sanitizeHtml('<div>"normal text"</div><script>"this is code"</script>', {
458
- allowedTags: [ 'script' ]
459
- }), '&quot;normal text&quot;<script>"this is code"</script>'
460
- );
461
- assert.equal(
462
- sanitizeHtml('<div>"normal text"</div><style>body { background-image: url("image.test"); }</style>', {
463
- allowedTags: [ 'style' ]
464
- }), '&quot;normal text&quot;<style>body { background-image: url("image.test"); }</style>'
465
- );
466
- });
467
- it('should not unescape escapes found inside script tags', function() {
468
- assert.equal(
469
- sanitizeHtml('<script>alert("&quot;This is cool but just ironically so I quoted it&quot;")</script>',
470
- {
471
- allowedTags: [ 'script' ]
472
- }
473
- ),
474
- '<script>alert("&quot;This is cool but just ironically so I quoted it&quot;")</script>'
475
- )
476
- });
477
- it('should process text nodes with provided function', function() {
478
- assert.equal(
479
- sanitizeHtml('"normal text this should be removed"', {
480
- textFilter: function(text) {
481
- return text.replace(' this should be removed', '');
482
- }
483
- }), '&quot;normal text&quot;'
484
- );
485
- });
486
- it('should respect htmlparser2 options when passed in', function() {
487
- assert.equal(
488
- sanitizeHtml("<Archer><Sterling>I am</Sterling></Archer>", {
489
- allowedTags: false,
490
- allowedAttributes: false,
491
- }),
492
- "<archer><sterling>I am</sterling></archer>"
493
- );
494
- assert.equal(
495
- sanitizeHtml("<Archer><Sterling>I am</Sterling></Archer>", {
496
- allowedTags: false,
497
- allowedAttributes: false,
498
- parser: {
499
- lowerCaseTags: false
500
- }
501
- }),
502
- "<Archer><Sterling>I am</Sterling></Archer>"
503
- );
504
- });
505
- it('should not crash due to tag names that are properties of the universal Object prototype', function() {
506
- assert.equal(
507
- sanitizeHtml("!<__proto__>!"),
508
- "!!");
509
- });
510
- it('should correctly maintain escaping when allowing a nonTextTags tag other than script or style', function() {
511
- assert.equal(
512
- sanitizeHtml('!<textarea>&lt;/textarea&gt;&lt;svg/onload=prompt`xs`&gt;</textarea>!',
513
- { allowedTags: [ 'textarea' ] }
514
- ), '!<textarea>&lt;/textarea&gt;&lt;svg/onload=prompt`xs`&gt;</textarea>!'
515
- );
516
- });
517
- it('should allow protocol relative links by default', function() {
518
- assert.equal(
519
- sanitizeHtml('<a href="//cnn.com/example">test</a>'),
520
- '<a href="//cnn.com/example">test</a>'
521
- );
522
- });
523
- it('should not allow protocol relative links when allowProtocolRelative is false', function() {
524
- assert.equal(
525
- sanitizeHtml('<a href="//cnn.com/example">test</a>', { allowProtocolRelative: false }),
526
- '<a>test</a>'
527
- );
528
- assert.equal(
529
- sanitizeHtml('<a href="/\\cnn.com/example">test</a>', { allowProtocolRelative: false }),
530
- '<a>test</a>'
531
- );
532
- assert.equal(
533
- sanitizeHtml('<a href="\\\\cnn.com/example">test</a>', { allowProtocolRelative: false }),
534
- '<a>test</a>'
535
- );
536
- assert.equal(
537
- sanitizeHtml('<a href="\\/cnn.com/example">test</a>', { allowProtocolRelative: false }),
538
- '<a>test</a>'
539
- );
540
- });
541
- it('should still allow regular relative URLs when allowProtocolRelative is false', function() {
542
- assert.equal(
543
- sanitizeHtml('<a href="/welcome">test</a>', { allowProtocolRelative: false }),
544
- '<a href="/welcome">test</a>'
545
- );
546
- });
547
- it('should discard srcset by default', function() {
548
- assert.equal(
549
- sanitizeHtml('<img src="fallback.jpg" srcset="foo.jpg 100w 2x, bar.jpg 200w 1x" />', {
550
- allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'img' ])
551
- }),
552
- '<img src="fallback.jpg" />'
553
- );
554
- });
555
- it('should accept srcset if allowed', function() {
556
- assert.equal(
557
- sanitizeHtml('<img src="fallback.jpg" srcset="foo.jpg 100w 2x, bar.jpg 200w 1x" />', {
558
- allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'img' ]),
559
- allowedAttributes: { img: [ 'src', 'srcset' ] }
560
- }),
561
- '<img src="fallback.jpg" srcset="foo.jpg 100w 2x, bar.jpg 200w 1x" />'
562
- );
563
- });
564
- it('should drop bogus srcset', function() {
565
- assert.equal(
566
- sanitizeHtml('<img src="fallback.jpg" srcset="foo.jpg 100w 2x, bar.jpg 200w 1x, javascript:alert(1) 100w 2x" />', {
567
- allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'img' ]),
568
- allowedAttributes: { img: [ 'src', 'srcset' ] }
569
- }),
570
- '<img src="fallback.jpg" srcset="foo.jpg 100w 2x, bar.jpg 200w 1x" />'
571
- );
572
- });
573
- it('drop attribute names with meta-characters', function() {
574
- assert.equal(
575
- sanitizeHtml('<span data-<script>alert(1)//>', {
576
- allowedTags: ['span'],
577
- allowedAttributes: { 'span': ['data-*'] }
578
- }),
579
- '<span>alert(1)//&gt;</span>'
580
- );
581
- });
582
- it('should sanitize styles correctly', function() {
583
- var sanitizeString = '<p dir="ltr"><strong>beste</strong><em>testestes</em><s>testestset</s><u>testestest</u></p><ul dir="ltr"> <li><u>test</u></li></ul><blockquote dir="ltr"> <ol> <li><u>​test</u></li><li><u>test</u></li><li style="text-align: right;"><u>test</u></li><li style="text-align: justify;"><u>test</u></li></ol> <p><u><span style="color:#00FF00;">test</span></u></p><p><span style="color:#00FF00"><span style="font-size:36px;">TESTETESTESTES</span></span></p></blockquote>';
584
- var expected = '<p dir="ltr"><strong>beste</strong><em>testestes</em><s>testestset</s><u>testestest</u></p><ul dir="ltr"> <li><u>test</u></li></ul><blockquote dir="ltr"> <ol> <li><u>​test</u></li><li><u>test</u></li><li style="text-align: right;"><u>test</u></li><li style="text-align: justify;"><u>test</u></li></ol> <p><u><span style="color:#00FF00;">test</span></u></p><p><span style="color:#00FF00;"><span style="font-size:36px;">TESTETESTESTES</span></span></p></blockquote>';
585
- assert.equal(
586
- sanitizeHtml(sanitizeString, {
587
- allowedTags: false,
588
- allowedAttributes: {
589
- '*': ["dir"],
590
- p: ["dir", "style"],
591
- li: ["style"],
592
- span: ["style"]
593
- },
594
- allowedStyles: {
595
- '*': {
596
- // Matches hex
597
- 'color': [/\#(0x)?[0-9a-f]+/i],
598
- 'text-align': [/left/, /right/, /center/, /justify/, /initial/, /inherit/],
599
- 'font-size': [/36px/]
600
- }
601
- }
602
- }).replace(/ /g,''), expected.replace(/ /g,'')
603
- )
604
- });
605
- it('Should remove empty style tags', function() {
606
- assert.equal(
607
- sanitizeHtml("<span style=''></span>", {
608
- allowedTags: false,
609
- allowedAttributes: false
610
- }),
611
- "<span></span>"
612
- );
613
- });
614
- it('Should remote invalid styles', function() {
615
- assert.equal(
616
- sanitizeHtml("<span style='color: blue; text-align: justify'></span>", {
617
- allowedTags: false,
618
- allowedAttributes: {
619
- "span": ["style"]
620
- },
621
- allowedStyles: {
622
- 'span': {
623
- "color": [/blue/],
624
- "text-align": [/left/]
625
- }
626
- }
627
- }), '<span style="color:blue;"></span>'
628
- );
629
- });
630
- it('Should allow a specific style from global', function() {
631
- assert.equal(
632
- sanitizeHtml("<span style='color: yellow; text-align: center; font-family: helvetica;'></span>", {
633
- allowedTags: false,
634
- allowedAttributes: {
635
- "span": ["style"]
636
- },
637
- allowedStyles: {
638
- '*': {
639
- "color": [/yellow/],
640
- "text-align": [/center/]
641
- },
642
- 'span': {
643
- "color": [/green/],
644
- "font-family": [/helvetica/]
645
- }
646
- }
647
- }), '<span style="color:yellow;text-align:center;font-family:helvetica;"></span>'
648
- );
649
- });
650
- it('Should allow hostnames in an iframe that are whitelisted', function() {
651
- assert.equal(
652
- sanitizeHtml('<iframe src="https://www.youtube.com/embed/c2IlcS7AHxM"></iframe>', {
653
-         allowedTags: ['p', 'iframe', 'a', 'img', 'i'],
654
-         allowedAttributes: {'iframe': ['src', 'href'], 'a': ['src', 'href'], 'img': ['src']},
655
-         allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com']
656
- }), '<iframe src="https://www.youtube.com/embed/c2IlcS7AHxM"></iframe>'
657
- );
658
- });
659
- it('Should remove iframe src urls that are not included in whitelisted hostnames', function() {
660
- assert.equal(
661
- sanitizeHtml('<iframe src="https://www.embed.vevo.com/USUV71704255"></iframe>', {
662
-         allowedTags: ['p', 'iframe', 'a', 'img', 'i'],
663
-         allowedAttributes: {'iframe': ['src', 'href'], 'a': ['src', 'href'], 'img': ['src']},
664
-         allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com']
665
- }), '<iframe></iframe>'
666
- );
667
- });
668
- it('Should not allow iframe urls that do not have proper hostname', function() {
669
- assert.equal(
670
- sanitizeHtml('<iframe src="https://www.vimeo.com/embed/c2IlcS7AHxM"></iframe>', {
671
-         allowedTags: ['p', 'iframe', 'a', 'img', 'i'],
672
-         allowedAttributes: {'iframe': ['src', 'href'], 'a': ['src', 'href'], 'img': ['src']},
673
-         allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com']
674
- }), '<iframe></iframe>'
675
- );
676
- });
677
- it('Should allow iframe through if no hostname option is set', function() {
678
- assert.equal(
679
- sanitizeHtml('<iframe src="https://www.vimeo.com/embed/c2IlcS7AHxM"></iframe>', {
680
-         allowedTags: ['p', 'iframe', 'a', 'img', 'i'],
681
-         allowedAttributes: {'iframe': ['src', 'href'], 'a': ['src', 'href'], 'img': ['src']}
682
- }), '<iframe src="https://www.vimeo.com/embed/c2IlcS7AHxM"></iframe>'
683
- );
684
- });
685
- it('Should allow relative URLs for iframes by default', function() {
686
- assert.equal(
687
- sanitizeHtml('<iframe src="/foo"></iframe>', {
688
-         allowedTags: ['p', 'iframe', 'a', 'img', 'i'],
689
-         allowedAttributes: {'iframe': ['src', 'href'], 'a': ['src', 'href'], 'img': ['src']}
690
- }), '<iframe src="/foo"></iframe>'
691
- );
692
- });
693
- it('Should allow relative URLs for iframes', function() {
694
- assert.equal(
695
- sanitizeHtml('<iframe src="/foo"></iframe>', {
696
-         allowedTags: ['p', 'iframe', 'a', 'img', 'i'],
697
-         allowedAttributes: {'iframe': ['src', 'href'], 'a': ['src', 'href'], 'img': ['src']},
698
- allowIframeRelativeUrls: true,
699
- }), '<iframe src="/foo"></iframe>'
700
- );
701
- });
702
- it('Should remove relative URLs for iframes', function() {
703
- assert.equal(
704
- sanitizeHtml('<iframe src="/foo"></iframe>', {
705
-         allowedTags: ['p', 'iframe', 'a', 'img', 'i'],
706
-         allowedAttributes: {'iframe': ['src', 'href'], 'a': ['src', 'href'], 'img': ['src']},
707
- allowIframeRelativeUrls: false,
708
- }), '<iframe></iframe>'
709
- );
710
- });
711
- it('Should remove relative URLs for iframes when whitelisted hostnames specified', function() {
712
- assert.equal(
713
- sanitizeHtml('<iframe src="/foo"></iframe><iframe src="https://www.youtube.com/embed/c2IlcS7AHxM"></iframe>', {
714
-         allowedTags: ['p', 'iframe', 'a', 'img', 'i'],
715
-         allowedAttributes: {'iframe': ['src', 'href'], 'a': ['src', 'href'], 'img': ['src']},
716
- allowedIframeHostnames: ['www.youtube.com']
717
- }), '<iframe></iframe><iframe src="https://www.youtube.com/embed/c2IlcS7AHxM"></iframe>'
718
- );
719
- });
720
- it('Should allow relative and whitelisted hostname URLs for iframes', function() {
721
- assert.equal(
722
- sanitizeHtml('<iframe src="/foo"></iframe><iframe src="https://www.youtube.com/embed/c2IlcS7AHxM"></iframe>', {
723
-         allowedTags: ['p', 'iframe', 'a', 'img', 'i'],
724
-         allowedAttributes: {'iframe': ['src', 'href'], 'a': ['src', 'href'], 'img': ['src']},
725
- allowIframeRelativeUrls: true,
726
- allowedIframeHostnames: ['www.youtube.com']
727
- }), '<iframe src="/foo"></iframe><iframe src="https://www.youtube.com/embed/c2IlcS7AHxM"></iframe>'
728
- );
729
- });
730
- it('Should allow protocol-relative URLs for the right domain for iframes', function() {
731
- assert.equal(
732
- sanitizeHtml('<iframe src="//www.youtube.com/embed/c2IlcS7AHxM"></iframe>', {
733
-         allowedTags: ['p', 'iframe', 'a', 'img', 'i'],
734
-         allowedAttributes: {'iframe': ['src', 'href'], 'a': ['src', 'href'], 'img': ['src']},
735
-         allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com']
736
- }), '<iframe src="//www.youtube.com/embed/c2IlcS7AHxM"></iframe>'
737
- );
738
- });
739
- it('Should not allow protocol-relative iframe urls that do not have proper hostname', function() {
740
- assert.equal(
741
- sanitizeHtml('<iframe src="//www.vimeo.com/embed/c2IlcS7AHxM"></iframe>', {
742
-         allowedTags: ['p', 'iframe', 'a', 'img', 'i'],
743
-         allowedAttributes: {'iframe': ['src', 'href'], 'a': ['src', 'href'], 'img': ['src']},
744
-         allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com']
745
- }), '<iframe></iframe>'
746
- );
747
- });
748
- it('Should only allow attributes to have any combination of specific values', function() {
749
- assert.equal(
750
- sanitizeHtml('<iframe name=\"IFRAME\" allowfullscreen=\"true\" sandbox=\"allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts allow-top-navigation\"></iframe>',{
751
- allowedTags: sanitizeHtml.defaults.allowedTags.concat( ['iframe'] ),
752
- allowedAttributes: {
753
- iframe: [
754
- {
755
- name: 'sandbox',
756
- multiple: true,
757
- values: ['allow-popups', 'allow-same-origin', 'allow-scripts']
758
- },
759
- 'allowfullscreen'
760
- ]
761
- }
762
- }), '<iframe allowfullscreen=\"true\" sandbox=\"allow-popups allow-same-origin allow-scripts\"></iframe>');
763
- });
764
- it('Should only allow attributes that match a specific value', function() {
765
- assert.equal(
766
- sanitizeHtml('<iframe sandbox=\"allow-popups allow-modals\"></iframe><iframe sandbox=\"allow-popups\"></iframe><iframe sandbox=\"allow-scripts\"></iframe>',{
767
- allowedTags: sanitizeHtml.defaults.allowedTags.concat( ['iframe'] ),
768
- allowedAttributes: {
769
- iframe: [
770
- {
771
- name: 'sandbox',
772
- multiple: false,
773
- values: ['allow-popups', 'allow-same-origin', 'allow-scripts']
774
- }
775
- ]
776
- }
777
- }), '<iframe sandbox></iframe><iframe sandbox=\"allow-popups\"></iframe><iframe sandbox=\"allow-scripts\"></iframe>');
778
- }
779
- );
780
- it('Should not allow cite urls that do not have an allowed scheme', function() {
781
- assert.equal(
782
- sanitizeHtml('<q cite=\"http://www.google.com\">HTTP</q><q cite=\"https://www.google.com\">HTTPS</q><q cite=\"mailto://www.google.com\">MAILTO</q><q cite=\"tel://www.google.com\">TEL</q><q cite=\"ftp://www.google.com\">FTP</q><q cite=\"data://www.google.com\">DATA</q><q cite=\"ldap://www.google.com\">LDAP</q><q cite=\"acrobat://www.google.com\">ACROBAT</q><q cite=\"vbscript://www.google.com\">VBSCRIPT</q><q cite=\"file://www.google.com\">FILE</q><q cite=\"rlogin://www.google.com\">RLOGIN</q><q cite=\"webcal://www.google.com\">WEBCAL</q><q cite=\"javascript://www.google.com\">JAVASCRIPT</q><q cite=\"mms://www.google.com\">MMS</q>',{
783
- allowedTags: sanitizeHtml.defaults.allowedTags.concat( ['q'] ),
784
- allowedAttributes: {q: [ 'cite' ]},
785
- allowedSchemes: sanitizeHtml.defaults.allowedSchemes.concat([ 'tel' ]),
786
- }), '<q cite=\"http://www.google.com\">HTTP</q><q cite=\"https://www.google.com\">HTTPS</q><q cite=\"mailto://www.google.com\">MAILTO</q><q cite=\"tel://www.google.com\">TEL</q><q cite=\"ftp://www.google.com\">FTP</q><q>DATA</q><q>LDAP</q><q>ACROBAT</q><q>VBSCRIPT</q><q>FILE</q><q>RLOGIN</q><q>WEBCAL</q><q>JAVASCRIPT</q><q>MMS</q>');
787
- });
788
- it('Should encode &, <, > and "', function() {
789
- assert.equal(sanitizeHtml('"< & >"'), '&quot;&lt; &amp; &gt;&quot;');
790
- });
791
- it('Should not double encode ampersands on HTML entities', function() {
792
- var textIn = 'This &amp; & that &reg; &#x0000A; &#10; &plusmn; OK?';
793
- var expectedResult = 'This &amp; &amp; that &reg; &#x0000A; &#10; &plusmn; OK?';
794
- var sanitizeHtmlOptions = {
795
- parser: {
796
- decodeEntities: false
797
- }
798
- };
799
- assert.equal(sanitizeHtml(textIn, sanitizeHtmlOptions), expectedResult);
800
- });
801
- });