loofah 2.3.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of loofah might be problematic. Click here for more details.

Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG.md +336 -0
  4. data/Gemfile +22 -0
  5. data/MIT-LICENSE.txt +23 -0
  6. data/Manifest.txt +41 -0
  7. data/README.md +363 -0
  8. data/Rakefile +81 -0
  9. data/SECURITY.md +18 -0
  10. data/benchmark/benchmark.rb +149 -0
  11. data/benchmark/fragment.html +96 -0
  12. data/benchmark/helper.rb +73 -0
  13. data/benchmark/www.slashdot.com.html +2560 -0
  14. data/lib/loofah.rb +83 -0
  15. data/lib/loofah/elements.rb +92 -0
  16. data/lib/loofah/helpers.rb +103 -0
  17. data/lib/loofah/html/document.rb +18 -0
  18. data/lib/loofah/html/document_fragment.rb +40 -0
  19. data/lib/loofah/html5/libxml2_workarounds.rb +26 -0
  20. data/lib/loofah/html5/safelist.rb +796 -0
  21. data/lib/loofah/html5/scrub.rb +133 -0
  22. data/lib/loofah/instance_methods.rb +127 -0
  23. data/lib/loofah/metahelpers.rb +13 -0
  24. data/lib/loofah/scrubber.rb +133 -0
  25. data/lib/loofah/scrubbers.rb +297 -0
  26. data/lib/loofah/xml/document.rb +13 -0
  27. data/lib/loofah/xml/document_fragment.rb +23 -0
  28. data/test/assets/msword.html +63 -0
  29. data/test/assets/testdata_sanitizer_tests1.dat +502 -0
  30. data/test/helper.rb +18 -0
  31. data/test/html5/test_sanitizer.rb +401 -0
  32. data/test/html5/test_scrub.rb +10 -0
  33. data/test/integration/test_ad_hoc.rb +220 -0
  34. data/test/integration/test_helpers.rb +43 -0
  35. data/test/integration/test_html.rb +72 -0
  36. data/test/integration/test_scrubbers.rb +400 -0
  37. data/test/integration/test_xml.rb +55 -0
  38. data/test/unit/test_api.rb +142 -0
  39. data/test/unit/test_encoding.rb +20 -0
  40. data/test/unit/test_helpers.rb +62 -0
  41. data/test/unit/test_scrubber.rb +229 -0
  42. data/test/unit/test_scrubbers.rb +14 -0
  43. metadata +287 -0
@@ -0,0 +1,55 @@
1
+ require "helper"
2
+
3
+ class IntegrationTestXml < Loofah::TestCase
4
+ context "integration test" do
5
+ context "xml document" do
6
+ context "custom scrubber" do
7
+ it "act as expected" do
8
+ xml = Loofah.xml_document <<-EOXML
9
+ <root>
10
+ <employee deceased='true'>Abraham Lincoln</employee>
11
+ <employee deceased='false'>Abe Vigoda</employee>
12
+ </root>
13
+ EOXML
14
+ bring_out_your_dead = Loofah::Scrubber.new do |node|
15
+ if node.name == "employee" and node["deceased"] == "true"
16
+ node.remove
17
+ Loofah::Scrubber::STOP # don't bother with the rest of the subtree
18
+ end
19
+ end
20
+ assert_equal 2, xml.css("employee").length
21
+
22
+ xml.scrub!(bring_out_your_dead)
23
+
24
+ employees = xml.css "employee"
25
+ assert_equal 1, employees.length
26
+ assert_equal "Abe Vigoda", employees.first.inner_text
27
+ end
28
+ end
29
+ end
30
+
31
+ context "xml fragment" do
32
+ context "custom scrubber" do
33
+ it "act as expected" do
34
+ xml = Loofah.xml_fragment <<-EOXML
35
+ <employee deceased='true'>Abraham Lincoln</employee>
36
+ <employee deceased='false'>Abe Vigoda</employee>
37
+ EOXML
38
+ bring_out_your_dead = Loofah::Scrubber.new do |node|
39
+ if node.name == "employee" and node["deceased"] == "true"
40
+ node.remove
41
+ Loofah::Scrubber::STOP # don't bother with the rest of the subtree
42
+ end
43
+ end
44
+ assert_equal 2, xml.css("employee").length
45
+
46
+ xml.scrub!(bring_out_your_dead)
47
+
48
+ employees = xml.css "employee"
49
+ assert_equal 1, employees.length
50
+ assert_equal "Abe Vigoda", employees.first.inner_text
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,142 @@
1
+ require "helper"
2
+
3
+ class UnitTestApi < Loofah::TestCase
4
+
5
+ HTML = "<div>a</div>\n<div>b</div>"
6
+ XML_FRAGMENT = "<div>a</div>\n<div>b</div>"
7
+ XML = "<root>#{XML_FRAGMENT}</root>"
8
+
9
+ describe "HTML" do
10
+ it "creates documents" do
11
+ doc = Loofah.document(HTML)
12
+ assert_html_documentish doc
13
+ end
14
+
15
+ it "creates fragments" do
16
+ doc = Loofah.fragment(HTML)
17
+ assert_html_fragmentish doc
18
+ end
19
+
20
+ it "parses documents" do
21
+ doc = Loofah::HTML::Document.parse(HTML)
22
+ assert_html_documentish doc
23
+ end
24
+
25
+ it "parses document fragment" do
26
+ doc = Loofah::HTML::DocumentFragment.parse(HTML)
27
+ assert_html_fragmentish doc
28
+ end
29
+
30
+ it "scrubs documents" do
31
+ doc = Loofah.document(HTML).scrub!(:strip)
32
+ assert_html_documentish doc
33
+ end
34
+
35
+ it "scrubs fragments" do
36
+ doc = Loofah.fragment(HTML).scrub!(:strip)
37
+ assert_html_fragmentish doc
38
+ end
39
+
40
+ it "scrubs document nodes" do
41
+ doc = Loofah.document(HTML)
42
+ assert(node = doc.at_css("div"))
43
+ node.scrub!(:strip)
44
+ end
45
+
46
+ it "scrubs fragment nodes" do
47
+ doc = Loofah.fragment(HTML)
48
+ assert(node = doc.at_css("div"))
49
+ node.scrub!(:strip)
50
+ end
51
+
52
+ it "scrubs document nodesets" do
53
+ doc = Loofah.document(HTML)
54
+ assert(node_set = doc.css("div"))
55
+ assert_instance_of Nokogiri::XML::NodeSet, node_set
56
+ node_set.scrub!(:strip)
57
+ end
58
+
59
+ it "exposes serialize_root on HTML::DocumentFragment" do
60
+ doc = Loofah.fragment(HTML)
61
+ assert_equal HTML, doc.serialize_root.to_html
62
+ end
63
+
64
+ it "exposes serialize_root on HTML::Document" do
65
+ doc = Loofah.document(HTML)
66
+ assert_equal HTML, doc.serialize_root.children.to_html
67
+ end
68
+ end
69
+
70
+ describe "XML" do
71
+ it "creates documents" do
72
+ doc = Loofah.xml_document(XML)
73
+ assert_xml_documentish doc
74
+ end
75
+
76
+ it "creates fragments" do
77
+ doc = Loofah.xml_fragment(XML_FRAGMENT)
78
+ assert_xml_fragmentish doc
79
+ end
80
+
81
+ it "parses documents" do
82
+ doc = Loofah::XML::Document.parse(XML)
83
+ assert_xml_documentish doc
84
+ end
85
+
86
+ it "parses document fragments" do
87
+ doc = Loofah::XML::DocumentFragment.parse(XML_FRAGMENT)
88
+ assert_xml_fragmentish doc
89
+ end
90
+
91
+ it "scrubs documents" do
92
+ scrubber = Loofah::Scrubber.new { |node| }
93
+ doc = Loofah.xml_document(XML).scrub!(scrubber)
94
+ assert_xml_documentish doc
95
+ end
96
+
97
+ it "scrubs fragments" do
98
+ scrubber = Loofah::Scrubber.new { |node| }
99
+ doc = Loofah.xml_fragment(XML_FRAGMENT).scrub!(scrubber)
100
+ assert_xml_fragmentish doc
101
+ end
102
+
103
+ it "scrubs document nodes" do
104
+ doc = Loofah.xml_document(XML)
105
+ assert(node = doc.at_css("div"))
106
+ node.scrub!(:strip)
107
+ end
108
+
109
+ it "scrubs fragment nodes" do
110
+ doc = Loofah.xml_fragment(XML)
111
+ assert(node = doc.at_css("div"))
112
+ node.scrub!(:strip)
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ def assert_html_documentish(doc)
119
+ assert_kind_of Nokogiri::HTML::Document, doc
120
+ assert_kind_of Loofah::HTML::Document, doc
121
+ assert_equal HTML, doc.xpath("/html/body").inner_html
122
+ end
123
+
124
+ def assert_html_fragmentish(doc)
125
+ assert_kind_of Nokogiri::HTML::DocumentFragment, doc
126
+ assert_kind_of Loofah::HTML::DocumentFragment, doc
127
+ assert_equal HTML, doc.inner_html
128
+ end
129
+
130
+ def assert_xml_documentish(doc)
131
+ assert_kind_of Nokogiri::XML::Document, doc
132
+ assert_kind_of Loofah::XML::Document, doc
133
+ assert_equal XML, doc.root.to_xml
134
+ end
135
+
136
+ def assert_xml_fragmentish(doc)
137
+ assert_kind_of Nokogiri::XML::DocumentFragment, doc
138
+ assert_kind_of Loofah::XML::DocumentFragment, doc
139
+ assert_equal XML_FRAGMENT, doc.children.to_xml
140
+ end
141
+
142
+ end
@@ -0,0 +1,20 @@
1
+ # :coding: utf-8
2
+ require "helper"
3
+
4
+ class UnitTestEncoding < Loofah::TestCase
5
+ UTF8_STRING = "日本語"
6
+
7
+ if String.new.respond_to?(:encoding)
8
+ describe "scrub_fragment" do
9
+ it "sets the encoding for html" do
10
+ escaped = Loofah.scrub_fragment(UTF8_STRING, :escape).to_s
11
+ assert_equal UTF8_STRING.encoding, escaped.encoding
12
+ end
13
+
14
+ it "sets the encoding for xml" do
15
+ escaped = Loofah.scrub_xml_fragment(UTF8_STRING, :escape).to_s
16
+ assert_equal UTF8_STRING.encoding, escaped.encoding
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,62 @@
1
+ require "helper"
2
+
3
+ class UnitTestHelpers < Loofah::TestCase
4
+
5
+ HTML_STRING = "<div>omgwtfbbq</div>"
6
+
7
+ describe "Helpers" do
8
+ context ".strip_tags" do
9
+ it "invoke Loofah.fragment.text" do
10
+ mock_doc = Object.new
11
+ mock(Loofah).fragment(HTML_STRING) { mock_doc }
12
+ mock(mock_doc).text
13
+
14
+ Loofah::Helpers.strip_tags HTML_STRING
15
+ end
16
+ end
17
+
18
+ context ".sanitize" do
19
+ it "invoke Loofah.scrub_fragment(:strip).to_s" do
20
+ mock_doc = Object.new
21
+ mock_node = Object.new
22
+ mock(Loofah).fragment(HTML_STRING) { mock_doc }
23
+ mock(mock_doc).scrub!(:strip) { mock_doc }
24
+ mock(mock_doc).xpath("./form") { [mock_node] }
25
+ mock(mock_node).remove
26
+ mock(mock_doc).to_s
27
+
28
+ Loofah::Helpers.sanitize HTML_STRING
29
+ end
30
+ end
31
+
32
+ context ".sanitize_css" do
33
+ it "invokes HTML5lib's css scrubber" do
34
+ mock(Loofah::HTML5::Scrub).scrub_css("foobar")
35
+ Loofah::Helpers.sanitize_css("foobar")
36
+ end
37
+ end
38
+
39
+ describe "ActionView" do
40
+ describe "FullSanitizer#sanitize" do
41
+ it "calls .strip_tags" do
42
+ mock(Loofah::Helpers).strip_tags("foobar")
43
+ Loofah::Helpers::ActionView::FullSanitizer.new.sanitize "foobar"
44
+ end
45
+ end
46
+
47
+ describe "SafeListSanitizer#sanitize" do
48
+ it "calls .sanitize" do
49
+ mock(Loofah::Helpers).sanitize("foobar")
50
+ Loofah::Helpers::ActionView::SafeListSanitizer.new.sanitize "foobar"
51
+ end
52
+ end
53
+
54
+ describe "SafeListSanitizer#sanitize_css" do
55
+ it "calls .sanitize_css" do
56
+ mock(Loofah::Helpers).sanitize_css("foobar")
57
+ Loofah::Helpers::ActionView::SafeListSanitizer.new.sanitize_css "foobar"
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,229 @@
1
+ require "helper"
2
+
3
+ class UnitTestScrubber < Loofah::TestCase
4
+
5
+ FRAGMENT = "<span>hello</span><span>goodbye</span>"
6
+ FRAGMENT_NODE_COUNT = 4 # span, text, span, text
7
+ FRAGMENT_NODE_STOP_TOP_DOWN = 2 # span, span
8
+ DOCUMENT = "<html><head><link></link></head><body><span>hello</span><span>goodbye</span></body></html>"
9
+ DOCUMENT_NODE_COUNT = 8 # html, head, link, body, span, text, span, text
10
+ DOCUMENT_NODE_STOP_TOP_DOWN = 1 # html
11
+
12
+ context "receiving a block" do
13
+ before do
14
+ @count = 0
15
+ end
16
+
17
+ context "returning CONTINUE" do
18
+ before do
19
+ @scrubber = Loofah::Scrubber.new do |node|
20
+ @count += 1
21
+ Loofah::Scrubber::CONTINUE
22
+ end
23
+ end
24
+
25
+ it "operate properly on a fragment" do
26
+ Loofah.scrub_fragment(FRAGMENT, @scrubber)
27
+ assert_equal FRAGMENT_NODE_COUNT, @count
28
+ end
29
+
30
+ it "operate properly on a document" do
31
+ Loofah.scrub_document(DOCUMENT, @scrubber)
32
+ assert_equal DOCUMENT_NODE_COUNT, @count
33
+ end
34
+ end
35
+
36
+ context "returning STOP" do
37
+ before do
38
+ @scrubber = Loofah::Scrubber.new do |node|
39
+ @count += 1
40
+ Loofah::Scrubber::STOP
41
+ end
42
+ end
43
+
44
+ it "operate as top-down on a fragment" do
45
+ Loofah.scrub_fragment(FRAGMENT, @scrubber)
46
+ assert_equal FRAGMENT_NODE_STOP_TOP_DOWN, @count
47
+ end
48
+
49
+ it "operate as top-down on a document" do
50
+ Loofah.scrub_document(DOCUMENT, @scrubber)
51
+ assert_equal DOCUMENT_NODE_STOP_TOP_DOWN, @count
52
+ end
53
+ end
54
+
55
+ context "returning neither CONTINUE nor STOP" do
56
+ before do
57
+ @scrubber = Loofah::Scrubber.new do |node|
58
+ @count += 1
59
+ end
60
+ end
61
+
62
+ it "act as if CONTINUE was returned" do
63
+ Loofah.scrub_fragment(FRAGMENT, @scrubber)
64
+ assert_equal FRAGMENT_NODE_COUNT, @count
65
+ end
66
+ end
67
+
68
+ context "not specifying direction" do
69
+ before do
70
+ @scrubber = Loofah::Scrubber.new() do |node|
71
+ @count += 1
72
+ Loofah::Scrubber::STOP
73
+ end
74
+ end
75
+
76
+ it "operate as top-down on a fragment" do
77
+ Loofah.scrub_fragment(FRAGMENT, @scrubber)
78
+ assert_equal FRAGMENT_NODE_STOP_TOP_DOWN, @count
79
+ end
80
+
81
+ it "operate as top-down on a document" do
82
+ Loofah.scrub_document(DOCUMENT, @scrubber)
83
+ assert_equal DOCUMENT_NODE_STOP_TOP_DOWN, @count
84
+ end
85
+ end
86
+
87
+ context "specifying top-down direction" do
88
+ before do
89
+ @scrubber = Loofah::Scrubber.new(:direction => :top_down) do |node|
90
+ @count += 1
91
+ Loofah::Scrubber::STOP
92
+ end
93
+ end
94
+
95
+ it "operate as top-down on a fragment" do
96
+ Loofah.scrub_fragment(FRAGMENT, @scrubber)
97
+ assert_equal FRAGMENT_NODE_STOP_TOP_DOWN, @count
98
+ end
99
+
100
+ it "operate as top-down on a document" do
101
+ Loofah.scrub_document(DOCUMENT, @scrubber)
102
+ assert_equal DOCUMENT_NODE_STOP_TOP_DOWN, @count
103
+ end
104
+ end
105
+
106
+ context "specifying bottom-up direction" do
107
+ before do
108
+ @scrubber = Loofah::Scrubber.new(:direction => :bottom_up) do |node|
109
+ @count += 1
110
+ end
111
+ end
112
+
113
+ it "operate as bottom-up on a fragment" do
114
+ Loofah.scrub_fragment(FRAGMENT, @scrubber)
115
+ assert_equal FRAGMENT_NODE_COUNT, @count
116
+ end
117
+
118
+ it "operate as bottom-up on a document" do
119
+ Loofah.scrub_document(DOCUMENT, @scrubber)
120
+ assert_equal DOCUMENT_NODE_COUNT, @count
121
+ end
122
+ end
123
+
124
+ context "invalid direction" do
125
+ it "raise an exception" do
126
+ assert_raises(ArgumentError) {
127
+ Loofah::Scrubber.new(:direction => :quux) { }
128
+ }
129
+ end
130
+ end
131
+
132
+ context "given a block taking zero arguments" do
133
+ before do
134
+ @scrubber = Loofah::Scrubber.new do
135
+ @count += 1
136
+ end
137
+ end
138
+
139
+ it "work anyway, shrug" do
140
+ Loofah.scrub_fragment(FRAGMENT, @scrubber)
141
+ assert_equal FRAGMENT_NODE_COUNT, @count
142
+ end
143
+ end
144
+ end
145
+
146
+ context "defining a new Scrubber class" do
147
+ before do
148
+ @klass = Class.new(Loofah::Scrubber) do
149
+ attr_accessor :count
150
+
151
+ def initialize(direction=nil)
152
+ @direction = direction
153
+ @count = 0
154
+ end
155
+
156
+ def scrub(node)
157
+ @count += 1
158
+ Loofah::Scrubber::STOP
159
+ end
160
+ end
161
+ end
162
+
163
+ context "when not specifying direction" do
164
+ before do
165
+ @scrubber = @klass.new
166
+ assert_nil @scrubber.direction
167
+ end
168
+
169
+ it "operate as top-down on a fragment" do
170
+ Loofah.scrub_fragment(FRAGMENT, @scrubber)
171
+ assert_equal FRAGMENT_NODE_STOP_TOP_DOWN, @scrubber.count
172
+ end
173
+
174
+ it "operate as top-down on a document" do
175
+ Loofah.scrub_document(DOCUMENT, @scrubber)
176
+ assert_equal DOCUMENT_NODE_STOP_TOP_DOWN, @scrubber.count
177
+ end
178
+ end
179
+
180
+ context "when direction is specified as top_down" do
181
+ before do
182
+ @scrubber = @klass.new(:top_down)
183
+ assert_equal :top_down, @scrubber.direction
184
+ end
185
+
186
+ it "operate as top-down on a fragment" do
187
+ Loofah.scrub_fragment(FRAGMENT, @scrubber)
188
+ assert_equal FRAGMENT_NODE_STOP_TOP_DOWN, @scrubber.count
189
+ end
190
+
191
+ it "operate as top-down on a document" do
192
+ Loofah.scrub_document(DOCUMENT, @scrubber)
193
+ assert_equal DOCUMENT_NODE_STOP_TOP_DOWN, @scrubber.count
194
+ end
195
+ end
196
+
197
+ context "when direction is specified as bottom_up" do
198
+ before do
199
+ @scrubber = @klass.new(:bottom_up)
200
+ assert_equal :bottom_up, @scrubber.direction
201
+ end
202
+
203
+ it "operate as bottom-up on a fragment" do
204
+ Loofah.scrub_fragment(FRAGMENT, @scrubber)
205
+ assert_equal FRAGMENT_NODE_COUNT, @scrubber.count
206
+ end
207
+
208
+ it "operate as bottom-up on a document" do
209
+ Loofah.scrub_document(DOCUMENT, @scrubber)
210
+ assert_equal DOCUMENT_NODE_COUNT, @scrubber.count
211
+ end
212
+ end
213
+ end
214
+
215
+ context "creating a new Scrubber class with no scrub method" do
216
+ before do
217
+ @klass = Class.new(Loofah::Scrubber) do
218
+ def initialize ; end
219
+ end
220
+ @scrubber = @klass.new
221
+ end
222
+
223
+ it "raise an exception" do
224
+ assert_raises(Loofah::ScrubberNotFound) {
225
+ Loofah.scrub_fragment(FRAGMENT, @scrubber)
226
+ }
227
+ end
228
+ end
229
+ end