sanitize 5.1.0 → 6.0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sanitize might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/HISTORY.md +155 -18
- data/LICENSE +1 -1
- data/README.md +67 -74
- data/lib/sanitize/config/default.rb +6 -1
- data/lib/sanitize/config/relaxed.rb +1 -1
- data/lib/sanitize/css.rb +2 -2
- data/lib/sanitize/transformers/clean_comment.rb +1 -1
- data/lib/sanitize/transformers/clean_css.rb +3 -3
- data/lib/sanitize/transformers/clean_doctype.rb +1 -1
- data/lib/sanitize/transformers/clean_element.rb +62 -20
- data/lib/sanitize/version.rb +1 -1
- data/lib/sanitize.rb +17 -13
- data/test/test_clean_comment.rb +16 -16
- data/test/test_clean_css.rb +5 -5
- data/test/test_clean_doctype.rb +15 -15
- data/test/test_clean_element.rb +130 -97
- data/test/test_config.rb +9 -9
- data/test/test_malicious_css.rb +7 -7
- data/test/test_malicious_html.rb +153 -30
- data/test/test_parser.rb +9 -9
- data/test/test_sanitize.rb +29 -29
- data/test/test_sanitize_css.rb +57 -57
- data/test/test_transformers.rb +48 -42
- metadata +17 -31
data/test/test_clean_element.rb
CHANGED
@@ -162,85 +162,95 @@ describe 'Sanitize::Transformers::CleanElement' do
|
|
162
162
|
}
|
163
163
|
|
164
164
|
describe 'Default config' do
|
165
|
-
it 'should remove non-
|
166
|
-
Sanitize.fragment('foo <b>bar</b> <strong><a href="#a">baz</a></strong> quux')
|
165
|
+
it 'should remove non-allowlisted elements, leaving safe contents behind' do
|
166
|
+
_(Sanitize.fragment('foo <b>bar</b> <strong><a href="#a">baz</a></strong> quux'))
|
167
167
|
.must_equal 'foo bar baz quux'
|
168
168
|
|
169
|
-
Sanitize.fragment('<script>alert("<xss>");</script>')
|
169
|
+
_(Sanitize.fragment('<script>alert("<xss>");</script>'))
|
170
170
|
.must_equal ''
|
171
171
|
|
172
|
-
Sanitize.fragment('<<script>script>alert("<xss>");</<script>>')
|
172
|
+
_(Sanitize.fragment('<<script>script>alert("<xss>");</<script>>'))
|
173
173
|
.must_equal '<'
|
174
174
|
|
175
|
-
Sanitize.fragment('< script <>> alert("<xss>");</script>')
|
175
|
+
_(Sanitize.fragment('< script <>> alert("<xss>");</script>'))
|
176
176
|
.must_equal '< script <>> alert("");'
|
177
177
|
end
|
178
178
|
|
179
179
|
it 'should surround the contents of :whitespace_elements with space characters when removing the element' do
|
180
|
-
Sanitize.fragment('foo<div>bar</div>baz')
|
180
|
+
_(Sanitize.fragment('foo<div>bar</div>baz'))
|
181
181
|
.must_equal 'foo bar baz'
|
182
182
|
|
183
|
-
Sanitize.fragment('foo<br>bar<br>baz')
|
183
|
+
_(Sanitize.fragment('foo<br>bar<br>baz'))
|
184
184
|
.must_equal 'foo bar baz'
|
185
185
|
|
186
|
-
Sanitize.fragment('foo<hr>bar<hr>baz')
|
186
|
+
_(Sanitize.fragment('foo<hr>bar<hr>baz'))
|
187
187
|
.must_equal 'foo bar baz'
|
188
188
|
end
|
189
189
|
|
190
190
|
it 'should not choke on several instances of the same element in a row' do
|
191
|
-
Sanitize.fragment('<img src="http://www.google.com/intl/en_ALL/images/logo.gif"><img src="http://www.google.com/intl/en_ALL/images/logo.gif"><img src="http://www.google.com/intl/en_ALL/images/logo.gif"><img src="http://www.google.com/intl/en_ALL/images/logo.gif">')
|
191
|
+
_(Sanitize.fragment('<img src="http://www.google.com/intl/en_ALL/images/logo.gif"><img src="http://www.google.com/intl/en_ALL/images/logo.gif"><img src="http://www.google.com/intl/en_ALL/images/logo.gif"><img src="http://www.google.com/intl/en_ALL/images/logo.gif">'))
|
192
192
|
.must_equal ''
|
193
193
|
end
|
194
194
|
|
195
|
-
it 'should
|
196
|
-
Sanitize.fragment('<
|
197
|
-
.must_equal '
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'should escape the content of removed `xmp` elements' do
|
201
|
-
Sanitize.fragment('<xmp>hello! <script>alert(0)</script></xmp>')
|
202
|
-
.must_equal 'hello! <script>alert(0)</script>'
|
195
|
+
it 'should not preserve the content of removed `iframe` elements' do
|
196
|
+
_(Sanitize.fragment('<iframe>hello! <script>alert(0)</script></iframe>'))
|
197
|
+
.must_equal ''
|
203
198
|
end
|
204
199
|
|
205
|
-
it 'should not preserve the content of removed `
|
206
|
-
Sanitize.fragment('<
|
200
|
+
it 'should not preserve the content of removed `math` elements' do
|
201
|
+
_(Sanitize.fragment('<math>hello! <script>alert(0)</script></math>'))
|
207
202
|
.must_equal ''
|
208
203
|
end
|
209
204
|
|
210
205
|
it 'should not preserve the content of removed `noembed` elements' do
|
211
|
-
Sanitize.fragment('<noembed>hello! <script>alert(0)</script></noembed>')
|
206
|
+
_(Sanitize.fragment('<noembed>hello! <script>alert(0)</script></noembed>'))
|
212
207
|
.must_equal ''
|
213
208
|
end
|
214
209
|
|
215
210
|
it 'should not preserve the content of removed `noframes` elements' do
|
216
|
-
Sanitize.fragment('<noframes>hello! <script>alert(0)</script></noframes>')
|
211
|
+
_(Sanitize.fragment('<noframes>hello! <script>alert(0)</script></noframes>'))
|
217
212
|
.must_equal ''
|
218
213
|
end
|
219
214
|
|
220
215
|
it 'should not preserve the content of removed `noscript` elements' do
|
221
|
-
Sanitize.fragment('<noscript>hello! <script>alert(0)</script></noscript>')
|
216
|
+
_(Sanitize.fragment('<noscript>hello! <script>alert(0)</script></noscript>'))
|
217
|
+
.must_equal ''
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'should not preserve the content of removed `plaintext` elements' do
|
221
|
+
_(Sanitize.fragment('<plaintext>hello! <script>alert(0)</script>'))
|
222
222
|
.must_equal ''
|
223
223
|
end
|
224
224
|
|
225
225
|
it 'should not preserve the content of removed `script` elements' do
|
226
|
-
Sanitize.fragment('<script>hello! <script>alert(0)</script></script>')
|
226
|
+
_(Sanitize.fragment('<script>hello! <script>alert(0)</script></script>'))
|
227
227
|
.must_equal ''
|
228
228
|
end
|
229
229
|
|
230
230
|
it 'should not preserve the content of removed `style` elements' do
|
231
|
-
Sanitize.fragment('<style>hello! <script>alert(0)</script></style>')
|
231
|
+
_(Sanitize.fragment('<style>hello! <script>alert(0)</script></style>'))
|
232
|
+
.must_equal ''
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'should not preserve the content of removed `svg` elements' do
|
236
|
+
_(Sanitize.fragment('<svg>hello! <script>alert(0)</script></svg>'))
|
237
|
+
.must_equal ''
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'should not preserve the content of removed `xmp` elements' do
|
241
|
+
_(Sanitize.fragment('<xmp>hello! <script>alert(0)</script></xmp>'))
|
232
242
|
.must_equal ''
|
233
243
|
end
|
234
244
|
|
235
245
|
strings.each do |name, data|
|
236
246
|
it "should clean #{name} HTML" do
|
237
|
-
Sanitize.fragment(data[:html]).must_equal(data[:default])
|
247
|
+
_(Sanitize.fragment(data[:html])).must_equal(data[:default])
|
238
248
|
end
|
239
249
|
end
|
240
250
|
|
241
251
|
protocols.each do |name, data|
|
242
252
|
it "should not allow #{name}" do
|
243
|
-
Sanitize.fragment(data[:html]).must_equal(data[:default])
|
253
|
+
_(Sanitize.fragment(data[:html])).must_equal(data[:default])
|
244
254
|
end
|
245
255
|
end
|
246
256
|
end
|
@@ -252,13 +262,13 @@ describe 'Sanitize::Transformers::CleanElement' do
|
|
252
262
|
|
253
263
|
strings.each do |name, data|
|
254
264
|
it "should clean #{name} HTML" do
|
255
|
-
@s.fragment(data[:html]).must_equal(data[:restricted])
|
265
|
+
_(@s.fragment(data[:html])).must_equal(data[:restricted])
|
256
266
|
end
|
257
267
|
end
|
258
268
|
|
259
269
|
protocols.each do |name, data|
|
260
270
|
it "should not allow #{name}" do
|
261
|
-
@s.fragment(data[:html]).must_equal(data[:restricted])
|
271
|
+
_(@s.fragment(data[:html])).must_equal(data[:restricted])
|
262
272
|
end
|
263
273
|
end
|
264
274
|
end
|
@@ -269,24 +279,24 @@ describe 'Sanitize::Transformers::CleanElement' do
|
|
269
279
|
end
|
270
280
|
|
271
281
|
it 'should not choke on valueless attributes' do
|
272
|
-
@s.fragment('foo <a href>foo</a> bar')
|
282
|
+
_(@s.fragment('foo <a href>foo</a> bar'))
|
273
283
|
.must_equal 'foo <a href="" rel="nofollow">foo</a> bar'
|
274
284
|
end
|
275
285
|
|
276
286
|
it 'should downcase attribute names' do
|
277
|
-
@s.fragment('<a HREF="javascript:alert(\'foo\')">bar</a>')
|
287
|
+
_(@s.fragment('<a HREF="javascript:alert(\'foo\')">bar</a>'))
|
278
288
|
.must_equal '<a rel="nofollow">bar</a>'
|
279
289
|
end
|
280
290
|
|
281
291
|
strings.each do |name, data|
|
282
292
|
it "should clean #{name} HTML" do
|
283
|
-
@s.fragment(data[:html]).must_equal(data[:basic])
|
293
|
+
_(@s.fragment(data[:html])).must_equal(data[:basic])
|
284
294
|
end
|
285
295
|
end
|
286
296
|
|
287
297
|
protocols.each do |name, data|
|
288
298
|
it "should not allow #{name}" do
|
289
|
-
@s.fragment(data[:html]).must_equal(data[:basic])
|
299
|
+
_(@s.fragment(data[:html])).must_equal(data[:basic])
|
290
300
|
end
|
291
301
|
end
|
292
302
|
end
|
@@ -297,124 +307,124 @@ describe 'Sanitize::Transformers::CleanElement' do
|
|
297
307
|
end
|
298
308
|
|
299
309
|
it 'should encode special chars in attribute values' do
|
300
|
-
@s.fragment('<a href="http://example.com" title="<b>éxamples</b> & things">foo</a>')
|
310
|
+
_(@s.fragment('<a href="http://example.com" title="<b>éxamples</b> & things">foo</a>'))
|
301
311
|
.must_equal '<a href="http://example.com" title="<b>éxamples</b> & things">foo</a>'
|
302
312
|
end
|
303
313
|
|
304
314
|
strings.each do |name, data|
|
305
315
|
it "should clean #{name} HTML" do
|
306
|
-
@s.fragment(data[:html]).must_equal(data[:relaxed])
|
316
|
+
_(@s.fragment(data[:html])).must_equal(data[:relaxed])
|
307
317
|
end
|
308
318
|
end
|
309
319
|
|
310
320
|
protocols.each do |name, data|
|
311
321
|
it "should not allow #{name}" do
|
312
|
-
@s.fragment(data[:html]).must_equal(data[:relaxed])
|
322
|
+
_(@s.fragment(data[:html])).must_equal(data[:relaxed])
|
313
323
|
end
|
314
324
|
end
|
315
325
|
end
|
316
326
|
|
317
327
|
describe 'Custom configs' do
|
318
|
-
it 'should allow attributes on all elements if
|
328
|
+
it 'should allow attributes on all elements if allowlisted under :all' do
|
319
329
|
input = '<p class="foo">bar</p>'
|
320
330
|
|
321
|
-
Sanitize.fragment(input).must_equal ' bar '
|
331
|
+
_(Sanitize.fragment(input)).must_equal ' bar '
|
322
332
|
|
323
|
-
Sanitize.fragment(input, {
|
333
|
+
_(Sanitize.fragment(input, {
|
324
334
|
:elements => ['p'],
|
325
335
|
:attributes => {:all => ['class']}
|
326
|
-
}).must_equal input
|
336
|
+
})).must_equal input
|
327
337
|
|
328
|
-
Sanitize.fragment(input, {
|
338
|
+
_(Sanitize.fragment(input, {
|
329
339
|
:elements => ['p'],
|
330
340
|
:attributes => {'div' => ['class']}
|
331
|
-
}).must_equal '<p>bar</p>'
|
341
|
+
})).must_equal '<p>bar</p>'
|
332
342
|
|
333
|
-
Sanitize.fragment(input, {
|
343
|
+
_(Sanitize.fragment(input, {
|
334
344
|
:elements => ['p'],
|
335
345
|
:attributes => {'p' => ['title'], :all => ['class']}
|
336
|
-
}).must_equal input
|
346
|
+
})).must_equal input
|
337
347
|
end
|
338
348
|
|
339
|
-
it "should not allow relative URLs when relative URLs aren't
|
349
|
+
it "should not allow relative URLs when relative URLs aren't allowlisted" do
|
340
350
|
input = '<a href="/foo/bar">Link</a>'
|
341
351
|
|
342
|
-
Sanitize.fragment(input,
|
352
|
+
_(Sanitize.fragment(input,
|
343
353
|
:elements => ['a'],
|
344
354
|
:attributes => {'a' => ['href']},
|
345
355
|
:protocols => {'a' => {'href' => ['http']}}
|
346
|
-
).must_equal '<a>Link</a>'
|
356
|
+
)).must_equal '<a>Link</a>'
|
347
357
|
end
|
348
358
|
|
349
359
|
it 'should allow relative URLs containing colons when the colon is not in the first path segment' do
|
350
360
|
input = '<a href="/wiki/Special:Random">Random Page</a>'
|
351
361
|
|
352
|
-
Sanitize.fragment(input, {
|
362
|
+
_(Sanitize.fragment(input, {
|
353
363
|
:elements => ['a'],
|
354
364
|
:attributes => {'a' => ['href']},
|
355
365
|
:protocols => {'a' => {'href' => [:relative]}}
|
356
|
-
}).must_equal input
|
366
|
+
})).must_equal input
|
357
367
|
end
|
358
368
|
|
359
369
|
it 'should allow relative URLs containing colons when the colon is part of an anchor' do
|
360
370
|
input = '<a href="#fn:1">Footnote 1</a>'
|
361
371
|
|
362
|
-
Sanitize.fragment(input, {
|
372
|
+
_(Sanitize.fragment(input, {
|
363
373
|
:elements => ['a'],
|
364
374
|
:attributes => {'a' => ['href']},
|
365
375
|
:protocols => {'a' => {'href' => [:relative]}}
|
366
|
-
}).must_equal input
|
376
|
+
})).must_equal input
|
367
377
|
|
368
378
|
input = '<a href="somepage#fn:1">Footnote 1</a>'
|
369
379
|
|
370
|
-
Sanitize.fragment(input, {
|
380
|
+
_(Sanitize.fragment(input, {
|
371
381
|
:elements => ['a'],
|
372
382
|
:attributes => {'a' => ['href']},
|
373
383
|
:protocols => {'a' => {'href' => [:relative]}}
|
374
|
-
}).must_equal input
|
384
|
+
})).must_equal input
|
375
385
|
end
|
376
386
|
|
377
387
|
it 'should remove the contents of filtered nodes when :remove_contents is true' do
|
378
|
-
Sanitize.fragment('foo bar <div>baz<span>quux</span></div>',
|
388
|
+
_(Sanitize.fragment('foo bar <div>baz<span>quux</span></div>',
|
379
389
|
:remove_contents => true
|
380
|
-
).must_equal 'foo bar '
|
390
|
+
)).must_equal 'foo bar '
|
381
391
|
end
|
382
392
|
|
383
393
|
it 'should remove the contents of specified nodes when :remove_contents is an Array or Set of element names as strings' do
|
384
|
-
Sanitize.fragment('foo bar <div>baz<span>quux</span> <b>hi</b><script>alert("hello!");</script></div>',
|
394
|
+
_(Sanitize.fragment('foo bar <div>baz<span>quux</span> <b>hi</b><script>alert("hello!");</script></div>',
|
385
395
|
:remove_contents => ['script', 'span']
|
386
|
-
).must_equal 'foo bar baz hi '
|
396
|
+
)).must_equal 'foo bar baz hi '
|
387
397
|
|
388
|
-
Sanitize.fragment('foo bar <div>baz<span>quux</span> <b>hi</b><script>alert("hello!");</script></div>',
|
398
|
+
_(Sanitize.fragment('foo bar <div>baz<span>quux</span> <b>hi</b><script>alert("hello!");</script></div>',
|
389
399
|
:remove_contents => Set.new(['script', 'span'])
|
390
|
-
).must_equal 'foo bar baz hi '
|
400
|
+
)).must_equal 'foo bar baz hi '
|
391
401
|
end
|
392
402
|
|
393
403
|
it 'should remove the contents of specified nodes when :remove_contents is an Array or Set of element names as symbols' do
|
394
|
-
Sanitize.fragment('foo bar <div>baz<span>quux</span> <b>hi</b><script>alert("hello!");</script></div>',
|
404
|
+
_(Sanitize.fragment('foo bar <div>baz<span>quux</span> <b>hi</b><script>alert("hello!");</script></div>',
|
395
405
|
:remove_contents => [:script, :span]
|
396
|
-
).must_equal 'foo bar baz hi '
|
406
|
+
)).must_equal 'foo bar baz hi '
|
397
407
|
|
398
|
-
Sanitize.fragment('foo bar <div>baz<span>quux</span> <b>hi</b><script>alert("hello!");</script></div>',
|
408
|
+
_(Sanitize.fragment('foo bar <div>baz<span>quux</span> <b>hi</b><script>alert("hello!");</script></div>',
|
399
409
|
:remove_contents => Set.new([:script, :span])
|
400
|
-
).must_equal 'foo bar baz hi '
|
410
|
+
)).must_equal 'foo bar baz hi '
|
401
411
|
end
|
402
412
|
|
403
|
-
it 'should remove the contents of
|
404
|
-
Sanitize.fragment('<iframe>hi <script>hello</script></iframe>',
|
413
|
+
it 'should remove the contents of allowlisted iframes' do
|
414
|
+
_(Sanitize.fragment('<iframe>hi <script>hello</script></iframe>',
|
405
415
|
:elements => ['iframe']
|
406
|
-
).must_equal '<iframe></iframe>'
|
416
|
+
)).must_equal '<iframe></iframe>'
|
407
417
|
end
|
408
418
|
|
409
419
|
it 'should not allow arbitrary HTML5 data attributes by default' do
|
410
|
-
Sanitize.fragment('<b data-foo="bar"></b>',
|
420
|
+
_(Sanitize.fragment('<b data-foo="bar"></b>',
|
411
421
|
:elements => ['b']
|
412
|
-
).must_equal '<b></b>'
|
422
|
+
)).must_equal '<b></b>'
|
413
423
|
|
414
|
-
Sanitize.fragment('<b class="foo" data-foo="bar"></b>',
|
424
|
+
_(Sanitize.fragment('<b class="foo" data-foo="bar"></b>',
|
415
425
|
:attributes => {'b' => ['class']},
|
416
426
|
:elements => ['b']
|
417
|
-
).must_equal '<b class="foo"></b>'
|
427
|
+
)).must_equal '<b class="foo"></b>'
|
418
428
|
end
|
419
429
|
|
420
430
|
it 'should allow arbitrary HTML5 data attributes when the :attributes config includes :data' do
|
@@ -423,28 +433,28 @@ describe 'Sanitize::Transformers::CleanElement' do
|
|
423
433
|
:elements => ['b']
|
424
434
|
)
|
425
435
|
|
426
|
-
s.fragment('<b data-foo="valid" data-bar="valid"></b>')
|
436
|
+
_(s.fragment('<b data-foo="valid" data-bar="valid"></b>'))
|
427
437
|
.must_equal '<b data-foo="valid" data-bar="valid"></b>'
|
428
438
|
|
429
|
-
s.fragment('<b data-="invalid"></b>')
|
439
|
+
_(s.fragment('<b data-="invalid"></b>'))
|
430
440
|
.must_equal '<b></b>'
|
431
441
|
|
432
|
-
s.fragment('<b data-="invalid"></b>')
|
442
|
+
_(s.fragment('<b data-="invalid"></b>'))
|
433
443
|
.must_equal '<b></b>'
|
434
444
|
|
435
|
-
s.fragment('<b data-xml="invalid"></b>')
|
445
|
+
_(s.fragment('<b data-xml="invalid"></b>'))
|
436
446
|
.must_equal '<b></b>'
|
437
447
|
|
438
|
-
s.fragment('<b data-xmlfoo="invalid"></b>')
|
448
|
+
_(s.fragment('<b data-xmlfoo="invalid"></b>'))
|
439
449
|
.must_equal '<b></b>'
|
440
450
|
|
441
|
-
s.fragment('<b data-f:oo="valid"></b>')
|
451
|
+
_(s.fragment('<b data-f:oo="valid"></b>'))
|
442
452
|
.must_equal '<b></b>'
|
443
453
|
|
444
|
-
s.fragment('<b data-f/oo="partial"></b>')
|
454
|
+
_(s.fragment('<b data-f/oo="partial"></b>'))
|
445
455
|
.must_equal '<b data-f=""></b>' # Nokogiri quirk; not ideal, but harmless
|
446
456
|
|
447
|
-
s.fragment('<b data-éfoo="valid"></b>')
|
457
|
+
_(s.fragment('<b data-éfoo="valid"></b>'))
|
448
458
|
.must_equal '<b></b>' # Another annoying Nokogiri quirk.
|
449
459
|
end
|
450
460
|
|
@@ -457,62 +467,85 @@ describe 'Sanitize::Transformers::CleanElement' do
|
|
457
467
|
}
|
458
468
|
)
|
459
469
|
|
460
|
-
s.fragment('<p>foo</p>').must_equal "\nfoo\n"
|
461
|
-
s.fragment('<p>foo</p><p>bar</p>').must_equal "\nfoo\n\nbar\n"
|
462
|
-
s.fragment('foo<div>bar</div>baz').must_equal "foo\nbar\nbaz"
|
463
|
-
s.fragment('foo<br>bar<br>baz').must_equal "foo\nbar\nbaz"
|
470
|
+
_(s.fragment('<p>foo</p>')).must_equal "\nfoo\n"
|
471
|
+
_(s.fragment('<p>foo</p><p>bar</p>')).must_equal "\nfoo\n\nbar\n"
|
472
|
+
_(s.fragment('foo<div>bar</div>baz')).must_equal "foo\nbar\nbaz"
|
473
|
+
_(s.fragment('foo<br>bar<br>baz')).must_equal "foo\nbar\nbaz"
|
464
474
|
end
|
465
475
|
|
466
476
|
it 'should handle protocols correctly regardless of case' do
|
467
477
|
input = '<a href="hTTpS://foo.com/">Text</a>'
|
468
478
|
|
469
|
-
Sanitize.fragment(input, {
|
479
|
+
_(Sanitize.fragment(input, {
|
470
480
|
:elements => ['a'],
|
471
481
|
:attributes => {'a' => ['href']},
|
472
482
|
:protocols => {'a' => {'href' => ['https']}}
|
473
|
-
}).must_equal input
|
483
|
+
})).must_equal input
|
474
484
|
|
475
485
|
input = '<a href="mailto:someone@example.com?Subject=Hello">Text</a>'
|
476
486
|
|
477
|
-
Sanitize.fragment(input, {
|
487
|
+
_(Sanitize.fragment(input, {
|
478
488
|
:elements => ['a'],
|
479
489
|
:attributes => {'a' => ['href']},
|
480
490
|
:protocols => {'a' => {'href' => ['https']}}
|
481
|
-
}).must_equal "<a>Text</a>"
|
491
|
+
})).must_equal "<a>Text</a>"
|
492
|
+
end
|
493
|
+
|
494
|
+
it 'should sanitize protocols in data attributes even if data attributes are generically allowed' do
|
495
|
+
input = '<a data-url="mailto:someone@example.com">Text</a>'
|
496
|
+
|
497
|
+
_(Sanitize.fragment(input, {
|
498
|
+
:elements => ['a'],
|
499
|
+
:attributes => {'a' => [:data]},
|
500
|
+
:protocols => {'a' => {'data-url' => ['https']}}
|
501
|
+
})).must_equal "<a>Text</a>"
|
502
|
+
|
503
|
+
_(Sanitize.fragment(input, {
|
504
|
+
:elements => ['a'],
|
505
|
+
:attributes => {'a' => [:data]},
|
506
|
+
:protocols => {'a' => {'data-url' => ['mailto']}}
|
507
|
+
})).must_equal input
|
482
508
|
end
|
483
509
|
|
484
510
|
it 'should prevent `<meta>` tags from being used to set a non-UTF-8 charset' do
|
485
|
-
Sanitize.document('<html><head><meta charset="utf-8"></head><body>Howdy!</body></html>',
|
511
|
+
_(Sanitize.document('<html><head><meta charset="utf-8"></head><body>Howdy!</body></html>',
|
486
512
|
:elements => %w[html head meta body],
|
487
513
|
:attributes => {'meta' => ['charset']}
|
488
|
-
).must_equal "<html><head><meta charset=\"utf-8\"></head><body>Howdy!</body></html>"
|
514
|
+
)).must_equal "<html><head><meta charset=\"utf-8\"></head><body>Howdy!</body></html>"
|
489
515
|
|
490
|
-
Sanitize.document('<html><meta charset="utf-8">Howdy!</html>',
|
516
|
+
_(Sanitize.document('<html><meta charset="utf-8">Howdy!</html>',
|
491
517
|
:elements => %w[html meta],
|
492
518
|
:attributes => {'meta' => ['charset']}
|
493
|
-
).must_equal "<html><meta charset=\"utf-8\">Howdy!</html>"
|
519
|
+
)).must_equal "<html><meta charset=\"utf-8\">Howdy!</html>"
|
494
520
|
|
495
|
-
Sanitize.document('<html><meta charset="us-ascii">Howdy!</html>',
|
521
|
+
_(Sanitize.document('<html><meta charset="us-ascii">Howdy!</html>',
|
496
522
|
:elements => %w[html meta],
|
497
523
|
:attributes => {'meta' => ['charset']}
|
498
|
-
).must_equal "<html><meta charset=\"utf-8\">Howdy!</html>"
|
524
|
+
)).must_equal "<html><meta charset=\"utf-8\">Howdy!</html>"
|
499
525
|
|
500
|
-
Sanitize.document('<html><meta http-equiv="content-type" content=" text/html; charset=us-ascii">Howdy!</html>',
|
526
|
+
_(Sanitize.document('<html><meta http-equiv="content-type" content=" text/html; charset=us-ascii">Howdy!</html>',
|
501
527
|
:elements => %w[html meta],
|
502
528
|
:attributes => {'meta' => %w[content http-equiv]}
|
503
|
-
).must_equal "<html><meta http-equiv=\"content-type\" content=\" text/html;charset=utf-8\">Howdy!</html>"
|
529
|
+
)).must_equal "<html><meta http-equiv=\"content-type\" content=\" text/html;charset=utf-8\">Howdy!</html>"
|
504
530
|
|
505
|
-
Sanitize.document('<html><meta http-equiv="Content-Type" content="text/plain;charset = us-ascii">Howdy!</html>',
|
531
|
+
_(Sanitize.document('<html><meta http-equiv="Content-Type" content="text/plain;charset = us-ascii">Howdy!</html>',
|
506
532
|
:elements => %w[html meta],
|
507
533
|
:attributes => {'meta' => %w[content http-equiv]}
|
508
|
-
).must_equal "<html><meta http-equiv=\"Content-Type\" content=\"text/plain;charset=utf-8\">Howdy!</html>"
|
534
|
+
)).must_equal "<html><meta http-equiv=\"Content-Type\" content=\"text/plain;charset=utf-8\">Howdy!</html>"
|
509
535
|
end
|
510
536
|
|
511
537
|
it 'should not modify `<meta>` tags that already set a UTF-8 charset' do
|
512
|
-
Sanitize.document('<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"></head><body>Howdy!</body></html>',
|
538
|
+
_(Sanitize.document('<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"></head><body>Howdy!</body></html>',
|
513
539
|
:elements => %w[html head meta body],
|
514
540
|
:attributes => {'meta' => %w[content http-equiv]}
|
515
|
-
).must_equal "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"></head><body>Howdy!</body></html>"
|
541
|
+
)).must_equal "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"></head><body>Howdy!</body></html>"
|
542
|
+
end
|
543
|
+
|
544
|
+
it 'always removes `<noscript>` elements even if `noscript` is in the allowlist' do
|
545
|
+
assert_equal(
|
546
|
+
'',
|
547
|
+
Sanitize.fragment('<noscript>foo</noscript>', elements: ['noscript'])
|
548
|
+
)
|
516
549
|
end
|
517
550
|
|
518
551
|
end
|
data/test/test_config.rb
CHANGED
@@ -6,7 +6,7 @@ describe 'Config' do
|
|
6
6
|
parallelize_me!
|
7
7
|
|
8
8
|
def verify_deeply_frozen(config)
|
9
|
-
config.must_be :frozen?
|
9
|
+
_(config).must_be :frozen?
|
10
10
|
|
11
11
|
if Hash === config
|
12
12
|
config.each_value {|v| verify_deeply_frozen(v) }
|
@@ -27,7 +27,7 @@ describe 'Config' do
|
|
27
27
|
a = {:one => {:one_one => [0, '1', :a], :one_two => false, :one_three => Set.new([:a, :b, :c])}}
|
28
28
|
b = Sanitize::Config.freeze_config(a)
|
29
29
|
|
30
|
-
b.must_be_same_as a
|
30
|
+
_(b).must_be_same_as a
|
31
31
|
verify_deeply_frozen a
|
32
32
|
end
|
33
33
|
end
|
@@ -40,10 +40,10 @@ describe 'Config' do
|
|
40
40
|
|
41
41
|
c = Sanitize::Config.merge(a, b)
|
42
42
|
|
43
|
-
c.wont_be_same_as a
|
44
|
-
c.wont_be_same_as b
|
43
|
+
_(c).wont_be_same_as a
|
44
|
+
_(c).wont_be_same_as b
|
45
45
|
|
46
|
-
c.must_equal(
|
46
|
+
_(c).must_equal(
|
47
47
|
:one => {
|
48
48
|
:one_one => [0, '1', :a],
|
49
49
|
:one_two => true,
|
@@ -53,13 +53,13 @@ describe 'Config' do
|
|
53
53
|
:two => 2
|
54
54
|
)
|
55
55
|
|
56
|
-
c[:one].wont_be_same_as a[:one]
|
57
|
-
c[:one][:one_one].wont_be_same_as a[:one][:one_one]
|
56
|
+
_(c[:one]).wont_be_same_as a[:one]
|
57
|
+
_(c[:one][:one_one]).wont_be_same_as a[:one][:one_one]
|
58
58
|
end
|
59
59
|
|
60
60
|
it 'should raise an ArgumentError if either argument is not a Hash' do
|
61
|
-
proc { Sanitize::Config.merge('foo', {}) }.must_raise ArgumentError
|
62
|
-
proc { Sanitize::Config.merge({}, 'foo') }.must_raise ArgumentError
|
61
|
+
_(proc { Sanitize::Config.merge('foo', {}) }).must_raise ArgumentError
|
62
|
+
_(proc { Sanitize::Config.merge({}, 'foo') }).must_raise ArgumentError
|
63
63
|
end
|
64
64
|
end
|
65
65
|
end
|
data/test/test_malicious_css.rb
CHANGED
@@ -16,27 +16,27 @@ describe 'Malicious CSS' do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'should not be possible to inject an expression by munging it with a comment' do
|
19
|
-
@s.properties(%[width:expr/*XSS*/ession(alert('XSS'))]).
|
19
|
+
_(@s.properties(%[width:expr/*XSS*/ession(alert('XSS'))])).
|
20
20
|
must_equal ''
|
21
21
|
|
22
|
-
@s.properties(%[width:ex/*XSS*//*/*/pression(alert("XSS"))]).
|
22
|
+
_(@s.properties(%[width:ex/*XSS*//*/*/pression(alert("XSS"))])).
|
23
23
|
must_equal ''
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'should not be possible to inject an expression by munging it with a newline' do
|
27
|
-
@s.properties(%[width:\nexpression(alert('XSS'));]).
|
27
|
+
_(@s.properties(%[width:\nexpression(alert('XSS'));])).
|
28
28
|
must_equal ''
|
29
29
|
end
|
30
30
|
|
31
31
|
it 'should not allow the javascript protocol' do
|
32
|
-
@s.properties(%[background-image:url("javascript:alert('XSS')");]).
|
32
|
+
_(@s.properties(%[background-image:url("javascript:alert('XSS')");])).
|
33
33
|
must_equal ''
|
34
34
|
|
35
|
-
Sanitize.fragment(%[<div style="background-image: url(javascript:alert('XSS'))">],
|
36
|
-
Sanitize::Config::RELAXED).must_equal '<div></div>'
|
35
|
+
_(Sanitize.fragment(%[<div style="background-image: url(javascript:alert('XSS'))">],
|
36
|
+
Sanitize::Config::RELAXED)).must_equal '<div></div>'
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'should not allow behaviors' do
|
40
|
-
@s.properties(%[behavior: url(xss.htc);]).must_equal ''
|
40
|
+
_(@s.properties(%[behavior: url(xss.htc);])).must_equal ''
|
41
41
|
end
|
42
42
|
end
|