loofah-activerecord 1.0.0 → 1.1.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.
- data/.gemtest +0 -0
- data/CHANGELOG.rdoc +8 -1
- data/Gemfile +19 -1
- data/Manifest.txt +3 -3
- data/README.rdoc +24 -21
- data/Rakefile +7 -8
- data/lib/loofah-activerecord.rb +6 -6
- data/lib/{loofah-activerecord → loofah/activerecord}/active_record.rb +0 -0
- data/lib/{loofah-activerecord → loofah/activerecord}/railtie.rb +2 -2
- data/lib/{loofah-activerecord → loofah/activerecord}/xss_foliate.rb +28 -4
- data/rails_test/Rakefile +102 -47
- data/rails_test/generate_test_directory +1 -1
- data/test/helper.rb +13 -3
- data/test/unit/test_active_record.rb +34 -38
- data/test/unit/test_xss_foliate.rb +66 -66
- metadata +178 -144
data/test/helper.rb
CHANGED
@@ -1,9 +1,19 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require '
|
3
|
-
require '
|
4
|
-
require '
|
2
|
+
require 'rr'
|
3
|
+
require 'minitest/unit'
|
4
|
+
require 'minitest/spec'
|
5
|
+
require 'minitest/autorun'
|
5
6
|
require 'acts_as_fu'
|
7
|
+
|
6
8
|
require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "loofah-activerecord"))
|
7
9
|
|
8
10
|
puts "=> testing with Nokogiri #{Nokogiri::VERSION_INFO.inspect}"
|
9
11
|
puts "=> testing with Loofah #{Loofah::VERSION}"
|
12
|
+
|
13
|
+
class Loofah::ActiveRecord::TestCase < MiniTest::Spec
|
14
|
+
include RR::Adapters::TestUnit
|
15
|
+
|
16
|
+
class << self
|
17
|
+
alias_method :context, :describe
|
18
|
+
end
|
19
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
|
-
require
|
1
|
+
require "helper"
|
2
2
|
|
3
|
-
class TestActiveRecord <
|
3
|
+
class TestActiveRecord < Loofah::ActiveRecord::TestCase
|
4
4
|
|
5
5
|
HTML_STRING = "<div>omgwtfbbq</div>"
|
6
6
|
PLAIN_TEXT = "vanilla text"
|
7
7
|
|
8
8
|
context "with a Post model" do
|
9
|
-
|
9
|
+
before do
|
10
10
|
ActsAsFu.build_model(:posts) do
|
11
11
|
string :plain_text
|
12
12
|
string :html_string
|
@@ -15,24 +15,24 @@ class TestActiveRecord < Test::Unit::TestCase
|
|
15
15
|
|
16
16
|
context "scrubbing a single field as a fragment" do
|
17
17
|
context "using a symbol to indicate the attribute" do
|
18
|
-
|
18
|
+
before do
|
19
19
|
Post.html_fragment :html_string, :scrub => :prune
|
20
20
|
assert ! Post.xss_foliated?
|
21
21
|
@post = Post.new :html_string => HTML_STRING, :plain_text => PLAIN_TEXT
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
Loofah.
|
26
|
-
Loofah.
|
24
|
+
it "scrub the specified field" do
|
25
|
+
mock(Loofah).scrub_fragment(HTML_STRING, :prune).once
|
26
|
+
mock(Loofah).scrub_fragment(PLAIN_TEXT, :prune).never
|
27
27
|
@post.valid?
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
Loofah.
|
30
|
+
it "only call scrub_fragment once" do
|
31
|
+
mock(Loofah).scrub_fragment(anything, anything).once
|
32
32
|
@post.valid?
|
33
33
|
end
|
34
34
|
|
35
|
-
|
35
|
+
it "generate strings" do
|
36
36
|
@post.valid?
|
37
37
|
assert_equal String, @post.html_string.class
|
38
38
|
assert_equal HTML_STRING, @post.html_string
|
@@ -40,15 +40,15 @@ class TestActiveRecord < Test::Unit::TestCase
|
|
40
40
|
end
|
41
41
|
|
42
42
|
context "using a string to indicate the attribute" do
|
43
|
-
|
43
|
+
before do
|
44
44
|
Post.html_fragment 'html_string', :scrub => :prune
|
45
45
|
assert ! Post.xss_foliated?
|
46
46
|
@post = Post.new :html_string => HTML_STRING, :plain_text => PLAIN_TEXT
|
47
47
|
end
|
48
48
|
|
49
|
-
|
50
|
-
Loofah.
|
51
|
-
Loofah.
|
49
|
+
it "scrub the specified field" do
|
50
|
+
mock(Loofah).scrub_fragment(HTML_STRING, :prune).once
|
51
|
+
mock(Loofah).scrub_fragment(PLAIN_TEXT, :prune).never
|
52
52
|
@post.valid?
|
53
53
|
end
|
54
54
|
end
|
@@ -56,44 +56,44 @@ class TestActiveRecord < Test::Unit::TestCase
|
|
56
56
|
|
57
57
|
context "scrubbing a single field as a document" do
|
58
58
|
context "using a symbol to indicate the attribute" do
|
59
|
-
|
59
|
+
before do
|
60
60
|
Post.html_document :html_string, :scrub => :strip
|
61
61
|
@post = Post.new :html_string => HTML_STRING, :plain_text => PLAIN_TEXT
|
62
62
|
end
|
63
63
|
|
64
|
-
|
65
|
-
Loofah.
|
66
|
-
Loofah.
|
64
|
+
it "scrub the specified field, but not other fields" do
|
65
|
+
mock(Loofah).scrub_document(HTML_STRING, :strip).once
|
66
|
+
mock(Loofah).scrub_document(PLAIN_TEXT, :strip).never
|
67
67
|
@post.valid?
|
68
68
|
end
|
69
69
|
|
70
|
-
|
71
|
-
Loofah.
|
70
|
+
it "only call scrub_document once" do
|
71
|
+
mock(Loofah).scrub_document(anything, anything).once
|
72
72
|
@post.valid?
|
73
73
|
end
|
74
74
|
|
75
|
-
|
75
|
+
it "generate strings" do
|
76
76
|
@post.valid?
|
77
77
|
assert_equal String, @post.html_string.class
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
81
|
context "using a string to indicate the attribute" do
|
82
|
-
|
82
|
+
before do
|
83
83
|
Post.html_document 'html_string', :scrub => :strip
|
84
84
|
@post = Post.new :html_string => HTML_STRING, :plain_text => PLAIN_TEXT
|
85
85
|
end
|
86
86
|
|
87
|
-
|
88
|
-
Loofah.
|
89
|
-
Loofah.
|
87
|
+
it "scrubs the specified field, but not other fields" do
|
88
|
+
mock(Loofah).scrub_document(HTML_STRING, :strip).once
|
89
|
+
mock(Loofah).scrub_document(PLAIN_TEXT, :strip).never
|
90
90
|
@post.valid?
|
91
91
|
end
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
95
|
context "not passing any options" do
|
96
|
-
|
96
|
+
it "raises ArgumentError" do
|
97
97
|
assert_raises(ArgumentError) {
|
98
98
|
Post.html_fragment :foo
|
99
99
|
}
|
@@ -101,36 +101,32 @@ class TestActiveRecord < Test::Unit::TestCase
|
|
101
101
|
end
|
102
102
|
|
103
103
|
context "not passing :scrub option" do
|
104
|
-
|
105
|
-
|
104
|
+
it "raises ArgumentError" do
|
105
|
+
assert_raises(ArgumentError) {
|
106
106
|
Post.html_fragment :foo, :bar => :quux
|
107
107
|
}
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
111
|
context "passing a :scrub option" do
|
112
|
-
|
113
|
-
|
114
|
-
Post.html_fragment :foo, :scrub => :quux
|
115
|
-
}
|
112
|
+
it "does not raise ArgumentError" do
|
113
|
+
Post.html_fragment :foo, :scrub => :quux
|
116
114
|
end
|
117
115
|
end
|
118
116
|
|
119
117
|
context "passing a Scrubber" do
|
120
|
-
|
118
|
+
before do
|
121
119
|
@called = false
|
122
120
|
@scrubber = Loofah::Scrubber.new do |node|
|
123
121
|
@called = true
|
124
122
|
end
|
125
123
|
end
|
126
124
|
|
127
|
-
|
128
|
-
|
129
|
-
Post.html_fragment :html_string, :scrub => @scrubber
|
130
|
-
}
|
125
|
+
it "does not raise ArgumentError" do
|
126
|
+
Post.html_fragment :html_string, :scrub => @scrubber
|
131
127
|
end
|
132
128
|
|
133
|
-
|
129
|
+
it "scrubs properly" do
|
134
130
|
Post.html_fragment :html_string, :scrub => @scrubber
|
135
131
|
post = Post.new :html_string => HTML_STRING, :plain_text => PLAIN_TEXT
|
136
132
|
post.valid?
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
1
|
+
require "helper"
|
2
2
|
|
3
|
-
class TestXssFoliate <
|
3
|
+
class TestXssFoliate < Loofah::ActiveRecord::TestCase
|
4
4
|
|
5
5
|
HTML_STRING = "<div>omgwtfbbq</div>"
|
6
6
|
PLAIN_TEXT = "vanilla text"
|
@@ -12,7 +12,7 @@ class TestXssFoliate < Test::Unit::TestCase
|
|
12
12
|
end
|
13
13
|
|
14
14
|
context "with a Post model" do
|
15
|
-
|
15
|
+
before do
|
16
16
|
ActsAsFu.build_model(:posts) do
|
17
17
|
string :plain_text
|
18
18
|
string :html_string
|
@@ -22,27 +22,27 @@ class TestXssFoliate < Test::Unit::TestCase
|
|
22
22
|
|
23
23
|
context "#xss_foliated?" do
|
24
24
|
context "when xss_foliate has not been called" do
|
25
|
-
|
25
|
+
it "return false" do
|
26
26
|
assert ! Post.xss_foliated?
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
context "when xss_foliate has been called with no options" do
|
31
|
-
|
31
|
+
before do
|
32
32
|
Post.xss_foliate
|
33
33
|
end
|
34
34
|
|
35
|
-
|
35
|
+
it "return true" do
|
36
36
|
assert Post.xss_foliated?
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
context "when xss_foliate has been called with options" do
|
41
|
-
|
41
|
+
before do
|
42
42
|
Post.xss_foliate :prune => :plain_text
|
43
43
|
end
|
44
44
|
|
45
|
-
|
45
|
+
it "return true" do
|
46
46
|
assert Post.xss_foliated?
|
47
47
|
end
|
48
48
|
end
|
@@ -50,47 +50,43 @@ class TestXssFoliate < Test::Unit::TestCase
|
|
50
50
|
|
51
51
|
context "#xss_foliate" do
|
52
52
|
context "when passed invalid option" do
|
53
|
-
|
54
|
-
|
53
|
+
it "raise ArgumentError" do
|
54
|
+
assert_raises(ArgumentError) { Post.xss_foliate :quux => [:foo] }
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
58
|
context "when passed a symbol" do
|
59
|
-
|
60
|
-
|
61
|
-
Loofah.
|
62
|
-
Loofah.
|
59
|
+
it "calls the right scrubber" do
|
60
|
+
Post.xss_foliate :prune => :plain_text
|
61
|
+
mock(Loofah).scrub_fragment(HTML_STRING, :strip).once
|
62
|
+
mock(Loofah).scrub_fragment(PLAIN_TEXT, :prune).once
|
63
63
|
new_post.valid?
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
67
|
context "when passed an array of symbols" do
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
Loofah.expects(:scrub_fragment).with(HTML_STRING, :prune).once
|
73
|
-
Loofah.expects(:scrub_fragment).with(PLAIN_TEXT, :prune).once
|
68
|
+
it "calls the right scrubbers" do
|
69
|
+
Post.xss_foliate :prune => [:plain_text, :html_string]
|
70
|
+
mock(Loofah).scrub_fragment(HTML_STRING, :prune).once
|
71
|
+
mock(Loofah).scrub_fragment(PLAIN_TEXT, :prune).once
|
74
72
|
new_post.valid?
|
75
73
|
end
|
76
74
|
end
|
77
75
|
|
78
76
|
context "when passed a string" do
|
79
|
-
|
80
|
-
|
81
|
-
Loofah.
|
82
|
-
Loofah.
|
77
|
+
it "calls the right scrubber" do
|
78
|
+
Post.xss_foliate :prune => 'plain_text'
|
79
|
+
mock(Loofah).scrub_fragment(HTML_STRING, :strip).once
|
80
|
+
mock(Loofah).scrub_fragment(PLAIN_TEXT, :prune).once
|
83
81
|
new_post.valid?
|
84
82
|
end
|
85
83
|
end
|
86
84
|
|
87
85
|
context "when passed an array of strings" do
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
Loofah.expects(:scrub_fragment).with(HTML_STRING, :prune).once
|
93
|
-
Loofah.expects(:scrub_fragment).with(PLAIN_TEXT, :prune).once
|
86
|
+
it "calls the right scrubbers" do
|
87
|
+
Post.xss_foliate :prune => ['plain_text', 'html_string']
|
88
|
+
mock(Loofah).scrub_fragment(HTML_STRING, :prune).once
|
89
|
+
mock(Loofah).scrub_fragment(PLAIN_TEXT, :prune).once
|
94
90
|
new_post.valid?
|
95
91
|
end
|
96
92
|
end
|
@@ -98,85 +94,85 @@ class TestXssFoliate < Test::Unit::TestCase
|
|
98
94
|
|
99
95
|
context "declaring scrubbed fields" do
|
100
96
|
context "on all fields" do
|
101
|
-
|
97
|
+
before do
|
102
98
|
Post.xss_foliate
|
103
99
|
end
|
104
100
|
|
105
|
-
|
106
|
-
mock_doc =
|
107
|
-
Loofah.
|
108
|
-
Loofah.
|
109
|
-
Loofah.
|
110
|
-
mock_doc.
|
101
|
+
it "scrub all fields" do
|
102
|
+
mock_doc = Object.new
|
103
|
+
mock(Loofah).scrub_fragment(HTML_STRING, :strip).once.returns(mock_doc)
|
104
|
+
mock(Loofah).scrub_fragment(PLAIN_TEXT, :strip).once.returns(mock_doc)
|
105
|
+
mock(Loofah).scrub_fragment(INTEGER_VALUE, :strip).never
|
106
|
+
mock(mock_doc).text.times(2)
|
111
107
|
assert new_post.valid?
|
112
108
|
end
|
113
109
|
end
|
114
110
|
|
115
111
|
context "omitting one field" do
|
116
|
-
|
112
|
+
before do
|
117
113
|
Post.xss_foliate :except => [:plain_text]
|
118
114
|
end
|
119
115
|
|
120
|
-
|
121
|
-
mock_doc =
|
122
|
-
Loofah.
|
123
|
-
Loofah.
|
124
|
-
Loofah.
|
125
|
-
mock_doc.
|
116
|
+
it "not scrub omitted field" do
|
117
|
+
mock_doc = Object.new
|
118
|
+
mock(Loofah).scrub_fragment(HTML_STRING, :strip).once.returns(mock_doc)
|
119
|
+
mock(Loofah).scrub_fragment(PLAIN_TEXT, :strip).never
|
120
|
+
mock(Loofah).scrub_fragment(INTEGER_VALUE, :strip).never
|
121
|
+
mock(mock_doc).text.once
|
126
122
|
new_post.valid?
|
127
123
|
end
|
128
124
|
end
|
129
125
|
|
130
126
|
Loofah::Scrubbers.scrubber_symbols.each do |method|
|
131
127
|
context "declaring one field to be scrubbed with #{method}" do
|
132
|
-
|
128
|
+
before do
|
133
129
|
Post.xss_foliate method => [:plain_text]
|
134
130
|
end
|
135
131
|
|
136
|
-
|
137
|
-
mock_doc =
|
138
|
-
Loofah.
|
139
|
-
Loofah.
|
140
|
-
Loofah.
|
141
|
-
mock_doc.
|
132
|
+
it "scrub that field appropriately" do
|
133
|
+
mock_doc = Object.new
|
134
|
+
mock(Loofah).scrub_fragment(HTML_STRING, :strip).once
|
135
|
+
mock(Loofah).scrub_fragment(PLAIN_TEXT, method).once.returns(mock_doc)
|
136
|
+
mock(Loofah).scrub_fragment(INTEGER_VALUE, :strip).never
|
137
|
+
mock(mock_doc).to_s
|
142
138
|
new_post.valid?
|
143
139
|
end
|
144
140
|
end
|
145
141
|
end
|
146
142
|
|
147
143
|
context "declaring one field to be scrubbed with html5lib_sanitize" do
|
148
|
-
|
144
|
+
before do
|
149
145
|
Post.xss_foliate :html5lib_sanitize => [:plain_text]
|
150
146
|
end
|
151
147
|
|
152
|
-
|
153
|
-
Loofah.
|
154
|
-
Loofah.
|
155
|
-
Loofah.
|
148
|
+
it "not that field appropriately" do
|
149
|
+
mock(Loofah).scrub_fragment(HTML_STRING, :strip) .once
|
150
|
+
mock(Loofah).scrub_fragment(PLAIN_TEXT, :escape).once
|
151
|
+
mock(Loofah).scrub_fragment(INTEGER_VALUE, :strip) .never
|
156
152
|
new_post.valid?
|
157
153
|
end
|
158
154
|
end
|
159
155
|
end
|
160
156
|
|
161
157
|
context "invalid model data" do
|
162
|
-
|
158
|
+
before do
|
163
159
|
Post.validates_presence_of :html_string
|
164
160
|
Post.xss_foliate
|
165
161
|
end
|
166
162
|
|
167
|
-
|
168
|
-
Loofah.
|
169
|
-
Loofah.
|
163
|
+
it "not be valid after sanitizing" do
|
164
|
+
mock(Loofah).scrub_fragment(WHITESPACEY, :strip).once
|
165
|
+
mock(Loofah).scrub_fragment(PLAIN_TEXT, :strip).once
|
170
166
|
assert ! new_post(:html_string => WHITESPACEY).valid?
|
171
167
|
end
|
172
168
|
end
|
173
169
|
|
174
170
|
context "given an XSS attempt" do
|
175
|
-
|
171
|
+
before do
|
176
172
|
Post.xss_foliate :strip => :html_string
|
177
173
|
end
|
178
174
|
|
179
|
-
|
175
|
+
it "escape html entities" do
|
180
176
|
hackattack = "<div><script>alert('evil')</script></div>"
|
181
177
|
post = new_post :html_string => hackattack, :plain_text => hackattack
|
182
178
|
post.valid?
|
@@ -186,25 +182,29 @@ class TestXssFoliate < Test::Unit::TestCase
|
|
186
182
|
end
|
187
183
|
|
188
184
|
context "these tests should pass for libxml 2.7.5 and later" do
|
189
|
-
|
185
|
+
before do
|
186
|
+
Post.xss_foliate
|
187
|
+
end
|
188
|
+
|
189
|
+
it "not scrub double quotes into html entities" do
|
190
190
|
answer = new_post(:plain_text => "\"something\"")
|
191
191
|
answer.valid?
|
192
192
|
assert_equal "\"something\"", answer.plain_text
|
193
193
|
end
|
194
194
|
|
195
|
-
|
195
|
+
it "not scrub ampersands into html entities" do
|
196
196
|
answer = new_post(:plain_text => "& Something")
|
197
197
|
answer.valid?
|
198
198
|
assert_equal "& Something", answer.plain_text
|
199
199
|
end
|
200
200
|
|
201
|
-
|
201
|
+
it "not scrub \\r html entities" do
|
202
202
|
answer = new_post(:plain_text => "Another \r Something")
|
203
203
|
answer.valid?
|
204
204
|
assert_equal "Another \r Something", answer.plain_text
|
205
205
|
end
|
206
206
|
|
207
|
-
|
207
|
+
it "not scrub \\n html entities" do
|
208
208
|
answer = new_post(:plain_text => "Another \n Something")
|
209
209
|
answer.valid?
|
210
210
|
assert_equal "Another \n Something", answer.plain_text
|