sanitize 7.0.0 → 7.0.1

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.
@@ -1,340 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "common"
4
-
5
- # Miscellaneous attempts to sneak maliciously crafted HTML past Sanitize. Many
6
- # of these are courtesy of (or inspired by) the OWASP XSS Filter Evasion Cheat
7
- # Sheet.
8
- #
9
- # https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
10
-
11
- describe "Malicious HTML" do
12
- make_my_diffs_pretty!
13
- parallelize_me!
14
-
15
- before do
16
- @s = Sanitize.new(Sanitize::Config::RELAXED)
17
- end
18
-
19
- describe "comments" do
20
- it "should not allow script injection via conditional comments" do
21
- _(@s.fragment(%[<!--[if gte IE 4]>\n<script>alert('XSS');</script>\n<![endif]-->]))
22
- .must_equal ""
23
- end
24
- end
25
-
26
- describe "interpolation (ERB, PHP, etc.)" do
27
- it "should escape ERB-style tags" do
28
- _(@s.fragment("<% naughty_ruby_code %>"))
29
- .must_equal "&lt;% naughty_ruby_code %&gt;"
30
-
31
- _(@s.fragment("<%= naughty_ruby_code %>"))
32
- .must_equal "&lt;%= naughty_ruby_code %&gt;"
33
- end
34
-
35
- it "should remove PHP-style tags" do
36
- _(@s.fragment("<? naughtyPHPCode(); ?>"))
37
- .must_equal ""
38
-
39
- _(@s.fragment("<?= naughtyPHPCode(); ?>"))
40
- .must_equal ""
41
- end
42
- end
43
-
44
- describe "<body>" do
45
- it "should not be possible to inject JS via a malformed event attribute" do
46
- _(@s.document('<html><head></head><body onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert("XSS")></body></html>'))
47
- .must_equal "<html><head></head><body></body></html>"
48
- end
49
- end
50
-
51
- describe "<iframe>" do
52
- it "should not be possible to inject an iframe using an improperly closed tag" do
53
- _(@s.fragment(%(<iframe src=http://ha.ckers.org/scriptlet.html <)))
54
- .must_equal ""
55
- end
56
- end
57
-
58
- describe "<img>" do
59
- it "should not be possible to inject JS via an unquoted <img> src attribute" do
60
- _(@s.fragment("<img src=javascript:alert('XSS')>")).must_equal "<img>"
61
- end
62
-
63
- it "should not be possible to inject JS using grave accents as <img> src delimiters" do
64
- _(@s.fragment("<img src=`javascript:alert('XSS')`>")).must_equal "<img>"
65
- end
66
-
67
- it "should not be possible to inject <script> via a malformed <img> tag" do
68
- _(@s.fragment('<img """><script>alert("XSS")</script>">'))
69
- .must_equal '<img>"&gt;'
70
- end
71
-
72
- it "should not be possible to inject protocol-based JS" do
73
- _(@s.fragment("<img src=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>"))
74
- .must_equal "<img>"
75
-
76
- _(@s.fragment("<img src=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>"))
77
- .must_equal "<img>"
78
-
79
- _(@s.fragment("<img src=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>"))
80
- .must_equal "<img>"
81
-
82
- # Encoded tab character.
83
- _(@s.fragment(%[<img src="jav&#x09;ascript:alert('XSS');">]))
84
- .must_equal "<img>"
85
-
86
- # Encoded newline.
87
- _(@s.fragment(%[<img src="jav&#x0A;ascript:alert('XSS');">]))
88
- .must_equal "<img>"
89
-
90
- # Encoded carriage return.
91
- _(@s.fragment(%[<img src="jav&#x0D;ascript:alert('XSS');">]))
92
- .must_equal "<img>"
93
-
94
- # Null byte.
95
- _(@s.fragment(%[<img src=java\0script:alert("XSS")>]))
96
- .must_equal "<img>"
97
-
98
- # Spaces plus meta char.
99
- _(@s.fragment(%[<img src=" &#14; javascript:alert('XSS');">]))
100
- .must_equal "<img>"
101
-
102
- # Mixed spaces and tabs.
103
- _(@s.fragment(%[<img src="j\na v\tascript://alert('XSS');">]))
104
- .must_equal "<img>"
105
- end
106
-
107
- it "should not be possible to inject protocol-based JS via whitespace" do
108
- _(@s.fragment(%[<img src="jav\tascript:alert('XSS');">]))
109
- .must_equal "<img>"
110
- end
111
-
112
- it "should not be possible to inject JS using a half-open <img> tag" do
113
- _(@s.fragment(%[<img src="javascript:alert('XSS')"]))
114
- .must_equal ""
115
- end
116
- end
117
-
118
- describe "<script>" do
119
- it "should not be possible to inject <script> using a malformed non-alphanumeric tag name" do
120
- _(@s.fragment(%[<script/xss src="http://ha.ckers.org/xss.js">alert(1)</script>]))
121
- .must_equal ""
122
- end
123
-
124
- it "should not be possible to inject <script> via extraneous open brackets" do
125
- _(@s.fragment(%[<<script>alert("XSS");//<</script>]))
126
- .must_equal "&lt;"
127
- end
128
- end
129
-
130
- # libxml2 >= 2.9.2 doesn't escape comments within some attributes, in an
131
- # attempt to preserve server-side includes. This can result in XSS since an
132
- # unescaped double quote can allow an attacker to inject a non-allowlisted
133
- # attribute. Sanitize works around this by implementing its own escaping for
134
- # affected attributes.
135
- #
136
- # The relevant libxml2 code is here:
137
- # <https://github.com/GNOME/libxml2/commit/960f0e275616cadc29671a218d7fb9b69eb35588>
138
- describe "unsafe libxml2 server-side includes in attributes" do
139
- using_unpatched_libxml2 = Nokogiri::VersionInfo.instance.libxml2_using_system?
140
-
141
- tag_configs = [
142
- {
143
- tag_name: "a",
144
- escaped_attrs: %w[action href src name],
145
- unescaped_attrs: []
146
- },
147
-
148
- {
149
- tag_name: "div",
150
- escaped_attrs: %w[action href src],
151
- unescaped_attrs: %w[name]
152
- }
153
- ]
154
-
155
- before do
156
- @s = Sanitize.new({
157
- elements: %w[a div],
158
-
159
- attributes: {
160
- all: %w[action href src name]
161
- }
162
- })
163
- end
164
-
165
- tag_configs.each do |tag_config|
166
- tag_name = tag_config[:tag_name]
167
-
168
- tag_config[:escaped_attrs].each do |attr_name|
169
- input = %[<#{tag_name} #{attr_name}='examp<!--" onmouseover=alert(1)>-->le.com'>foo</#{tag_name}>]
170
-
171
- it "should escape unsafe characters in attributes" do
172
- skip "behavior should only exist in nokogiri's patched libxml" if using_unpatched_libxml2
173
-
174
- # This uses Nokogumbo's HTML-compliant serializer rather than
175
- # libxml2's.
176
- _(@s.fragment(input))
177
- .must_equal(%[<#{tag_name} #{attr_name}="examp<!--%22%20onmouseover=alert(1)>-->le.com">foo</#{tag_name}>])
178
-
179
- # This uses the not-quite-standards-compliant libxml2 serializer via
180
- # Nokogiri, so the output may be a little different as of Nokogiri
181
- # 1.10.2 when using Nokogiri's vendored libxml2 due to this patch:
182
- # https://github.com/sparklemotion/nokogiri/commit/4852e43cb6039e26d8c51af78621e539cbf46c5d
183
- fragment = Nokogiri::HTML.fragment(input)
184
- @s.node!(fragment)
185
- _(fragment.to_html)
186
- .must_equal(%[<#{tag_name} #{attr_name}="examp&lt;!--%22%20onmouseover=alert(1)&gt;--&gt;le.com">foo</#{tag_name}>])
187
- end
188
-
189
- it "should round-trip to the same output" do
190
- output = @s.fragment(input)
191
- _(@s.fragment(output)).must_equal(output)
192
- end
193
- end
194
-
195
- tag_config[:unescaped_attrs].each do |attr_name|
196
- input = %[<#{tag_name} #{attr_name}='examp<!--" onmouseover=alert(1)>-->le.com'>foo</#{tag_name}>]
197
-
198
- it "should not escape characters unnecessarily" do
199
- skip "behavior should only exist in nokogiri's patched libxml" if using_unpatched_libxml2
200
-
201
- # This uses Nokogumbo's HTML-compliant serializer rather than
202
- # libxml2's.
203
- _(@s.fragment(input))
204
- .must_equal(%[<#{tag_name} #{attr_name}="examp<!--&quot; onmouseover=alert(1)>-->le.com">foo</#{tag_name}>])
205
-
206
- # This uses the not-quite-standards-compliant libxml2 serializer via
207
- # Nokogiri, so the output may be a little different as of Nokogiri
208
- # 1.10.2 when using Nokogiri's vendored libxml2 due to this patch:
209
- # https://github.com/sparklemotion/nokogiri/commit/4852e43cb6039e26d8c51af78621e539cbf46c5d
210
- fragment = Nokogiri::HTML.fragment(input)
211
- @s.node!(fragment)
212
- _(fragment.to_html)
213
- .must_equal(%[<#{tag_name} #{attr_name}='examp&lt;!--" onmouseover=alert(1)&gt;--&gt;le.com'>foo</#{tag_name}>])
214
- end
215
-
216
- it "should round-trip to the same output" do
217
- output = @s.fragment(input)
218
- _(@s.fragment(output)).must_equal(output)
219
- end
220
- end
221
- end
222
- end
223
-
224
- # https://github.com/rgrove/sanitize/security/advisories/GHSA-p4x4-rw2p-8j8m
225
- describe "foreign content bypass in relaxed config" do
226
- it "prevents a sanitization bypass via carefully crafted foreign content" do
227
- %w[iframe noembed noframes noscript plaintext script style xmp].each do |tag_name|
228
- _(@s.fragment(%[<math><#{tag_name}>/*&lt;/#{tag_name}&gt;&lt;img src onerror=alert(1)>*/]))
229
- .must_equal ""
230
-
231
- _(@s.fragment(%[<svg><#{tag_name}>/*&lt;/#{tag_name}&gt;&lt;img src onerror=alert(1)>*/]))
232
- .must_equal ""
233
- end
234
- end
235
- end
236
-
237
- # These tests cover an unsupported and unsafe custom config that allows MathML
238
- # and SVG elements, which Sanitize's docs specifically say multiple times in
239
- # big prominent warnings that you SHOULD NOT DO because Sanitize doesn't
240
- # support MathML or SVG.
241
- #
242
- # Do not use the custom configs you see in these tests! If you do, you may be
243
- # creating XSS vulnerabilities in your application.
244
- describe "foreign content bypass in unsafe custom config that allows MathML or SVG" do
245
- unescaped_content_elements = %w[
246
- noembed
247
- noframes
248
- plaintext
249
- script
250
- xmp
251
- ]
252
-
253
- removed_content_elements = %w[
254
- iframe
255
- ]
256
-
257
- removed_elements = %w[
258
- noscript
259
- style
260
- ]
261
-
262
- before do
263
- @s = Sanitize.new(
264
- Sanitize::Config.merge(
265
- Sanitize::Config::RELAXED,
266
- elements: Sanitize::Config::RELAXED[:elements] +
267
- unescaped_content_elements +
268
- removed_content_elements +
269
- %w[math svg]
270
- )
271
- )
272
- end
273
-
274
- unescaped_content_elements.each do |name|
275
- it "forcibly escapes text content inside `<#{name}>` in a MathML namespace" do
276
- assert_equal(
277
- "<math><#{name}>&lt;img src=x onerror=alert(1)&gt;</#{name}></math>",
278
- @s.fragment("<math><#{name}>&lt;img src=x onerror=alert(1)&gt;</#{name}>")
279
- )
280
- end
281
-
282
- it "forcibly escapes text content inside `<#{name}>` in an SVG namespace" do
283
- assert_equal(
284
- "<svg><#{name}>&lt;img src=x onerror=alert(1)&gt;</#{name}></svg>",
285
- @s.fragment("<svg><#{name}>&lt;img src=x onerror=alert(1)&gt;</#{name}>")
286
- )
287
- end
288
- end
289
-
290
- removed_content_elements.each do |name|
291
- it "removes text content inside `<#{name}>` in a MathML namespace" do
292
- assert_equal(
293
- "<math><#{name}></#{name}></math>",
294
- @s.fragment("<math><#{name}>&lt;img src=x onerror=alert(1)&gt;</#{name}>")
295
- )
296
- end
297
-
298
- it "removes text content inside `<#{name}>` in an SVG namespace" do
299
- assert_equal(
300
- "<svg><#{name}></#{name}></svg>",
301
- @s.fragment("<svg><#{name}>&lt;img src=x onerror=alert(1)&gt;</#{name}>")
302
- )
303
- end
304
- end
305
-
306
- removed_elements.each do |name|
307
- it "removes `<#{name}>` elements in a MathML namespace" do
308
- assert_equal(
309
- "<math></math>",
310
- @s.fragment("<math><#{name}>&lt;img src=x onerror=alert(1)&gt;</#{name}>")
311
- )
312
- end
313
-
314
- it "removes `<#{name}>` elements in an SVG namespace" do
315
- assert_equal(
316
- "<svg></svg>",
317
- @s.fragment("<svg><#{name}>&lt;img src=x onerror=alert(1)&gt;</#{name}>")
318
- )
319
- end
320
- end
321
- end
322
-
323
- describe "sanitization bypass by exploiting scripting-disabled <noscript> behavior" do
324
- before do
325
- @s = Sanitize.new(
326
- Sanitize::Config.merge(
327
- Sanitize::Config::RELAXED,
328
- elements: Sanitize::Config::RELAXED[:elements] + ["noscript"]
329
- )
330
- )
331
- end
332
-
333
- it "is prevented by removing `<noscript>` elements regardless of the allowlist" do
334
- assert_equal(
335
- "",
336
- @s.fragment(%[<noscript><div id='</noscript>&lt;img src=x onerror=alert(1)&gt; '>])
337
- )
338
- end
339
- end
340
- end
data/test/test_parser.rb DELETED
@@ -1,76 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "common"
4
-
5
- describe "Parser" do
6
- make_my_diffs_pretty!
7
- parallelize_me!
8
-
9
- it "should translate valid entities into characters" do
10
- _(Sanitize.fragment("&apos;&eacute;&amp;")).must_equal("'é&amp;")
11
- end
12
-
13
- it "should translate orphaned ampersands into entities" do
14
- _(Sanitize.fragment("at&t")).must_equal("at&amp;t")
15
- end
16
-
17
- it "should not add newlines after tags when serializing a fragment" do
18
- _(Sanitize.fragment("<div>foo\n\n<p>bar</p><div>\nbaz</div></div><div>quux</div>", elements: ["div", "p"]))
19
- .must_equal "<div>foo\n\n<p>bar</p><div>\nbaz</div></div><div>quux</div>"
20
- end
21
-
22
- it "should not have the Nokogiri 1.4.2+ unterminated script/style element bug" do
23
- _(Sanitize.fragment("foo <script>bar")).must_equal "foo "
24
- _(Sanitize.fragment("foo <style>bar")).must_equal "foo "
25
- end
26
-
27
- it 'ambiguous non-tag brackets like "1 > 2 and 2 < 1" should be parsed correctly' do
28
- _(Sanitize.fragment("1 > 2 and 2 < 1")).must_equal "1 &gt; 2 and 2 &lt; 1"
29
- _(Sanitize.fragment("OMG HAPPY BIRTHDAY! *<:-D")).must_equal "OMG HAPPY BIRTHDAY! *&lt;:-D"
30
- end
31
-
32
- describe "when siblings are added after a node during traversal" do
33
- it "the added siblings should be traversed" do
34
- html = %(
35
- <div id="one">
36
- <div id="one_one">
37
- <div id="one_one_one"></div>
38
- </div>
39
- <div id="one_two"></div>
40
- </div>
41
- <div id="two">
42
- <div id="two_one"><div id="two_one_one"></div></div>
43
- <div id="two_two"></div>
44
- </div>
45
- <div id="three"></div>
46
- )
47
-
48
- siblings = []
49
-
50
- Sanitize.fragment(html, transformers: ->(env) {
51
- name = env[:node].name
52
-
53
- if name == "div"
54
- env[:node].add_next_sibling('<b id="added_' + env[:node]["id"] + '">')
55
- elsif name == "b"
56
- siblings << env[:node][:id]
57
- end
58
-
59
- {node_allowlist: [env[:node]]}
60
- })
61
-
62
- # All siblings should be traversed, and in the order added.
63
- _(siblings).must_equal [
64
- "added_one_one_one",
65
- "added_one_one",
66
- "added_one_two",
67
- "added_one",
68
- "added_two_one_one",
69
- "added_two_one",
70
- "added_two_two",
71
- "added_two",
72
- "added_three"
73
- ]
74
- end
75
- end
76
- end
@@ -1,198 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "common"
4
-
5
- describe "Sanitize" do
6
- describe "initializer" do
7
- it "should not modify a transformers array in the given config" do
8
- transformers = [
9
- lambda {}
10
- ]
11
-
12
- Sanitize.new({transformers: transformers})
13
- _(transformers.length).must_equal(1)
14
- end
15
- end
16
-
17
- describe "instance methods" do
18
- before do
19
- @s = Sanitize.new
20
- end
21
-
22
- describe "#document" do
23
- before do
24
- @s = Sanitize.new(elements: ["html"])
25
- end
26
-
27
- it "should sanitize an HTML document" do
28
- _(@s.document('<!doctype html><html><b>Lo<!-- comment -->rem</b> <a href="pants" title="foo">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br/>amet <script>alert("hello world");</script></html>'))
29
- .must_equal "<html>Lorem ipsum dolor sit amet </html>"
30
- end
31
-
32
- it "should not modify the input string" do
33
- input = "<!DOCTYPE html><b>foo</b>"
34
- @s.document(input)
35
- _(input).must_equal("<!DOCTYPE html><b>foo</b>")
36
- end
37
-
38
- it "should not choke on frozen documents" do
39
- _(@s.document("<!doctype html><html><b>foo</b>")).must_equal "<html>foo</html>"
40
- end
41
-
42
- it "should normalize newlines" do
43
- _(@s.document("a\r\n\n\r\r\r\nz")).must_equal "<html>a\n\n\n\n\nz</html>"
44
- end
45
-
46
- it "should strip control characters (except ASCII whitespace)" do
47
- sample_control_chars = "\u0001\u0008\u000b\u000e\u001f\u007f\u009f"
48
- whitespace = "\t\n\f\u0020"
49
- _(@s.document("a#{sample_control_chars}#{whitespace}z")).must_equal "<html>a#{whitespace}z</html>"
50
- end
51
-
52
- it "should strip non-characters" do
53
- sample_non_chars = "\ufdd0\ufdef\ufffe\uffff\u{1fffe}\u{1ffff}\u{2fffe}\u{2ffff}\u{3fffe}\u{3ffff}\u{4fffe}\u{4ffff}\u{5fffe}\u{5ffff}\u{6fffe}\u{6ffff}\u{7fffe}\u{7ffff}\u{8fffe}\u{8ffff}\u{9fffe}\u{9ffff}\u{afffe}\u{affff}\u{bfffe}\u{bffff}\u{cfffe}\u{cffff}\u{dfffe}\u{dffff}\u{efffe}\u{effff}\u{ffffe}\u{fffff}\u{10fffe}\u{10ffff}"
54
- _(@s.document("a#{sample_non_chars}z")).must_equal "<html>az</html>"
55
- end
56
-
57
- describe "when html body exceeds Nokogiri::Gumbo::DEFAULT_MAX_TREE_DEPTH" do
58
- let(:content) do
59
- content = nest_html_content("<b>foo</b>", Nokogiri::Gumbo::DEFAULT_MAX_TREE_DEPTH)
60
- "<html>#{content}</html>"
61
- end
62
-
63
- it "raises an ArgumentError exception" do
64
- assert_raises ArgumentError do
65
- @s.document(content)
66
- end
67
- end
68
-
69
- describe "and :max_tree_depth of -1 is supplied in :parser_options" do
70
- before do
71
- @s = Sanitize.new(elements: ["html"], parser_options: {max_tree_depth: -1})
72
- end
73
-
74
- it "does not raise an ArgumentError exception" do
75
- _(@s.document(content)).must_equal "<html>foo</html>"
76
- end
77
- end
78
- end
79
- end
80
-
81
- describe "#fragment" do
82
- it "should sanitize an HTML fragment" do
83
- _(@s.fragment('<b>Lo<!-- comment -->rem</b> <a href="pants" title="foo">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br/>amet <script>alert("hello world");</script>'))
84
- .must_equal "Lorem ipsum dolor sit amet "
85
- end
86
-
87
- it "should not modify the input string" do
88
- input = "<b>foo</b>"
89
- @s.fragment(input)
90
- _(input).must_equal "<b>foo</b>"
91
- end
92
-
93
- it "should not choke on fragments containing <html> or <body>" do
94
- _(@s.fragment("<html><b>foo</b></html>")).must_equal "foo"
95
- _(@s.fragment("<body><b>foo</b></body>")).must_equal "foo"
96
- _(@s.fragment("<html><body><b>foo</b></body></html>")).must_equal "foo"
97
- _(@s.fragment("<!DOCTYPE html><html><body><b>foo</b></body></html>")).must_equal "foo"
98
- end
99
-
100
- it "should not choke on frozen fragments" do
101
- _(@s.fragment("<b>foo</b>")).must_equal "foo"
102
- end
103
-
104
- it "should normalize newlines" do
105
- _(@s.fragment("a\r\n\n\r\r\r\nz")).must_equal "a\n\n\n\n\nz"
106
- end
107
-
108
- it "should strip control characters (except ASCII whitespace)" do
109
- sample_control_chars = "\u0001\u0008\u000b\u000e\u001f\u007f\u009f"
110
- whitespace = "\t\n\f\u0020"
111
- _(@s.fragment("a#{sample_control_chars}#{whitespace}z")).must_equal "a#{whitespace}z"
112
- end
113
-
114
- it "should strip non-characters" do
115
- sample_non_chars = "\ufdd0\ufdef\ufffe\uffff\u{1fffe}\u{1ffff}\u{2fffe}\u{2ffff}\u{3fffe}\u{3ffff}\u{4fffe}\u{4ffff}\u{5fffe}\u{5ffff}\u{6fffe}\u{6ffff}\u{7fffe}\u{7ffff}\u{8fffe}\u{8ffff}\u{9fffe}\u{9ffff}\u{afffe}\u{affff}\u{bfffe}\u{bffff}\u{cfffe}\u{cffff}\u{dfffe}\u{dffff}\u{efffe}\u{effff}\u{ffffe}\u{fffff}\u{10fffe}\u{10ffff}"
116
- _(@s.fragment("a#{sample_non_chars}z")).must_equal "az"
117
- end
118
-
119
- describe "when html body exceeds Nokogiri::Gumbo::DEFAULT_MAX_TREE_DEPTH" do
120
- let(:content) do
121
- content = nest_html_content("<b>foo</b>", Nokogiri::Gumbo::DEFAULT_MAX_TREE_DEPTH)
122
- "<body>#{content}</body>"
123
- end
124
-
125
- it "raises an ArgumentError exception" do
126
- assert_raises ArgumentError do
127
- @s.fragment(content)
128
- end
129
- end
130
-
131
- describe "and :max_tree_depth of -1 is supplied in :parser_options" do
132
- before do
133
- @s = Sanitize.new(parser_options: {max_tree_depth: -1})
134
- end
135
-
136
- it "does not raise an ArgumentError exception" do
137
- _(@s.fragment(content)).must_equal "foo"
138
- end
139
- end
140
- end
141
- end
142
-
143
- describe "#node!" do
144
- it "should sanitize a Nokogiri::XML::Node" do
145
- doc = Nokogiri::HTML5.parse('<b>Lo<!-- comment -->rem</b> <a href="pants" title="foo">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br/>amet <script>alert("hello world");</script>')
146
- frag = doc.fragment
147
-
148
- doc.xpath("/html/body/node()").each { |node| frag << node }
149
-
150
- @s.node!(frag)
151
- _(frag.to_html).must_equal "Lorem ipsum dolor sit amet "
152
- end
153
-
154
- describe "when the given node is a document and <html> isn't allowlisted" do
155
- it "should raise a Sanitize::Error" do
156
- doc = Nokogiri::HTML5.parse("foo")
157
- _(proc { @s.node!(doc) }).must_raise Sanitize::Error
158
- end
159
- end
160
- end
161
- end
162
-
163
- describe "class methods" do
164
- describe ".document" do
165
- it "should sanitize an HTML document with the given config" do
166
- html = '<!doctype html><html><b>Lo<!-- comment -->rem</b> <a href="pants" title="foo">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br/>amet <script>alert("hello world");</script></html>'
167
- _(Sanitize.document(html, elements: ["html"]))
168
- .must_equal "<html>Lorem ipsum dolor sit amet </html>"
169
- end
170
- end
171
-
172
- describe ".fragment" do
173
- it "should sanitize an HTML fragment with the given config" do
174
- html = '<b>Lo<!-- comment -->rem</b> <a href="pants" title="foo">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br/>amet <script>alert("hello world");</script>'
175
- _(Sanitize.fragment(html, elements: ["strong"]))
176
- .must_equal "Lorem ipsum <strong>dolor</strong> sit amet "
177
- end
178
- end
179
-
180
- describe ".node!" do
181
- it "should sanitize a Nokogiri::XML::Node with the given config" do
182
- doc = Nokogiri::HTML5.parse('<b>Lo<!-- comment -->rem</b> <a href="pants" title="foo">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br/>amet <script>alert("hello world");</script>')
183
- frag = doc.fragment
184
-
185
- doc.xpath("/html/body/node()").each { |node| frag << node }
186
-
187
- Sanitize.node!(frag, elements: ["strong"])
188
- _(frag.to_html).must_equal "Lorem ipsum <strong>dolor</strong> sit amet "
189
- end
190
- end
191
- end
192
-
193
- private
194
-
195
- def nest_html_content(html_content, depth)
196
- "#{"<span>" * depth}#{html_content}#{"</span>" * depth}"
197
- end
198
- end