rails-html-sanitizer 1.5.0 → 1.6.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +125 -0
- data/MIT-LICENSE +1 -1
- data/README.md +124 -72
- data/lib/rails/html/sanitizer/version.rb +4 -2
- data/lib/rails/html/sanitizer.rb +372 -104
- data/lib/rails/html/scrubbers.rb +98 -73
- data/lib/rails-html-sanitizer.rb +7 -23
- data/test/rails_api_test.rb +88 -0
- data/test/sanitizer_test.rb +1095 -584
- data/test/scrubbers_test.rb +129 -38
- metadata +68 -58
data/test/scrubbers_test.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "minitest/autorun"
|
2
4
|
require "rails-html-sanitizer"
|
3
5
|
|
4
6
|
class ScrubberTest < Minitest::Test
|
5
7
|
protected
|
8
|
+
def scrub_fragment(html)
|
9
|
+
Loofah.scrub_fragment(html, @scrubber).to_s
|
10
|
+
end
|
6
11
|
|
7
12
|
def assert_scrubbed(html, expected = html)
|
8
|
-
output =
|
13
|
+
output = scrub_fragment(html)
|
9
14
|
assert_equal expected, output
|
10
15
|
end
|
11
16
|
|
@@ -28,9 +33,8 @@ class ScrubberTest < Minitest::Test
|
|
28
33
|
end
|
29
34
|
|
30
35
|
class PermitScrubberTest < ScrubberTest
|
31
|
-
|
32
36
|
def setup
|
33
|
-
@scrubber = Rails::
|
37
|
+
@scrubber = Rails::HTML::PermitScrubber.new
|
34
38
|
end
|
35
39
|
|
36
40
|
def test_responds_to_scrub
|
@@ -38,51 +42,60 @@ class PermitScrubberTest < ScrubberTest
|
|
38
42
|
end
|
39
43
|
|
40
44
|
def test_default_scrub_behavior
|
41
|
-
assert_scrubbed
|
45
|
+
assert_scrubbed "<tag>hello</tag>", "hello"
|
42
46
|
end
|
43
47
|
|
44
48
|
def test_default_scrub_removes_comments
|
45
|
-
assert_scrubbed(
|
46
|
-
|
49
|
+
assert_scrubbed("<div>one</div><!-- two --><span>three</span>",
|
50
|
+
"<div>one</div><span>three</span>")
|
47
51
|
end
|
48
52
|
|
49
53
|
def test_default_scrub_removes_processing_instructions
|
50
|
-
|
51
|
-
|
54
|
+
input = "<div>one</div><?div two><span>three</span>"
|
55
|
+
result = scrub_fragment(input)
|
56
|
+
|
57
|
+
acceptable_results = [
|
58
|
+
# jruby cyberneko (nokogiri < 1.14.0)
|
59
|
+
"<div>one</div>",
|
60
|
+
# everything else
|
61
|
+
"<div>one</div><span>three</span>",
|
62
|
+
]
|
63
|
+
|
64
|
+
assert_includes(acceptable_results, result)
|
52
65
|
end
|
53
66
|
|
54
67
|
def test_default_attributes_removal_behavior
|
55
|
-
assert_scrubbed '<p cooler="hello">hello</p>',
|
68
|
+
assert_scrubbed '<p cooler="hello">hello</p>', "<p>hello</p>"
|
56
69
|
end
|
57
70
|
|
58
71
|
def test_leaves_supplied_tags
|
59
72
|
@scrubber.tags = %w(a)
|
60
|
-
assert_scrubbed
|
73
|
+
assert_scrubbed "<a>hello</a>"
|
61
74
|
end
|
62
75
|
|
63
76
|
def test_leaves_only_supplied_tags
|
64
|
-
html =
|
77
|
+
html = "<tag>leave me <span>now</span></tag>"
|
65
78
|
@scrubber.tags = %w(tag)
|
66
|
-
assert_scrubbed html,
|
79
|
+
assert_scrubbed html, "<tag>leave me now</tag>"
|
67
80
|
end
|
68
81
|
|
69
82
|
def test_prunes_tags
|
70
|
-
@scrubber = Rails::
|
83
|
+
@scrubber = Rails::HTML::PermitScrubber.new(prune: true)
|
71
84
|
@scrubber.tags = %w(tag)
|
72
|
-
html =
|
73
|
-
assert_scrubbed html,
|
85
|
+
html = "<tag>leave me <span>now</span></tag>"
|
86
|
+
assert_scrubbed html, "<tag>leave me </tag>"
|
74
87
|
end
|
75
88
|
|
76
89
|
def test_leaves_comments_when_supplied_as_tag
|
77
90
|
@scrubber.tags = %w(div comment)
|
78
|
-
assert_scrubbed(
|
79
|
-
|
91
|
+
assert_scrubbed("<div>one</div><!-- two --><span>three</span>",
|
92
|
+
"<div>one</div><!-- two -->three")
|
80
93
|
end
|
81
94
|
|
82
95
|
def test_leaves_only_supplied_tags_nested
|
83
|
-
html =
|
96
|
+
html = "<tag>leave <em>me <span>now</span></em></tag>"
|
84
97
|
@scrubber.tags = %w(tag)
|
85
|
-
assert_scrubbed html,
|
98
|
+
assert_scrubbed html, "<tag>leave me now</tag>"
|
86
99
|
end
|
87
100
|
|
88
101
|
def test_leaves_supplied_attributes
|
@@ -108,17 +121,41 @@ class PermitScrubberTest < ScrubberTest
|
|
108
121
|
assert_scrubbed html, '<tag></tag><tag cooler=""></tag>'
|
109
122
|
end
|
110
123
|
|
124
|
+
def test_does_not_allow_safelisted_mglyph
|
125
|
+
# https://hackerone.com/reports/2519936
|
126
|
+
assert_output(nil, /WARNING: 'mglyph' tags cannot be allowed by the PermitScrubber/) do
|
127
|
+
@scrubber.tags = ["div", "mglyph", "span"]
|
128
|
+
end
|
129
|
+
assert_equal(["div", "span"], @scrubber.tags)
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_does_not_allow_safelisted_malignmark
|
133
|
+
# https://hackerone.com/reports/2519936
|
134
|
+
assert_output(nil, /WARNING: 'malignmark' tags cannot be allowed by the PermitScrubber/) do
|
135
|
+
@scrubber.tags = ["div", "malignmark", "span"]
|
136
|
+
end
|
137
|
+
assert_equal(["div", "span"], @scrubber.tags)
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_does_not_allow_safelisted_noscript
|
141
|
+
# https://hackerone.com/reports/2509647
|
142
|
+
assert_output(nil, /WARNING: 'noscript' tags cannot be allowed by the PermitScrubber/) do
|
143
|
+
@scrubber.tags = ["div", "noscript", "span"]
|
144
|
+
end
|
145
|
+
assert_equal(["div", "span"], @scrubber.tags)
|
146
|
+
end
|
147
|
+
|
111
148
|
def test_leaves_text
|
112
|
-
assert_scrubbed(
|
149
|
+
assert_scrubbed("some text")
|
113
150
|
end
|
114
151
|
|
115
152
|
def test_skips_text_nodes
|
116
|
-
assert_node_skipped(
|
153
|
+
assert_node_skipped("some text")
|
117
154
|
end
|
118
155
|
|
119
156
|
def test_tags_accessor_validation
|
120
157
|
e = assert_raises(ArgumentError) do
|
121
|
-
@scrubber.tags =
|
158
|
+
@scrubber.tags = "tag"
|
122
159
|
end
|
123
160
|
|
124
161
|
assert_equal "You should pass :tags as an Enumerable", e.message
|
@@ -127,7 +164,7 @@ class PermitScrubberTest < ScrubberTest
|
|
127
164
|
|
128
165
|
def test_attributes_accessor_validation
|
129
166
|
e = assert_raises(ArgumentError) do
|
130
|
-
@scrubber.attributes =
|
167
|
+
@scrubber.attributes = "cooler"
|
131
168
|
end
|
132
169
|
|
133
170
|
assert_equal "You should pass :attributes as an Enumerable", e.message
|
@@ -137,19 +174,19 @@ end
|
|
137
174
|
|
138
175
|
class TargetScrubberTest < ScrubberTest
|
139
176
|
def setup
|
140
|
-
@scrubber = Rails::
|
177
|
+
@scrubber = Rails::HTML::TargetScrubber.new
|
141
178
|
end
|
142
179
|
|
143
180
|
def test_targeting_tags_removes_only_them
|
144
181
|
@scrubber.tags = %w(a h1)
|
145
|
-
html =
|
146
|
-
assert_scrubbed html,
|
182
|
+
html = "<script></script><a></a><h1></h1>"
|
183
|
+
assert_scrubbed html, "<script></script>"
|
147
184
|
end
|
148
185
|
|
149
186
|
def test_targeting_tags_removes_only_them_nested
|
150
187
|
@scrubber.tags = %w(a)
|
151
|
-
html =
|
152
|
-
assert_scrubbed html,
|
188
|
+
html = "<tag><a><tag><a></a></tag></a></tag>"
|
189
|
+
assert_scrubbed html, "<tag><tag></tag></tag>"
|
153
190
|
end
|
154
191
|
|
155
192
|
def test_targeting_attributes_removes_only_them
|
@@ -166,39 +203,93 @@ class TargetScrubberTest < ScrubberTest
|
|
166
203
|
end
|
167
204
|
|
168
205
|
def test_prunes_tags
|
169
|
-
@scrubber = Rails::
|
206
|
+
@scrubber = Rails::HTML::TargetScrubber.new(prune: true)
|
170
207
|
@scrubber.tags = %w(span)
|
171
|
-
html =
|
172
|
-
assert_scrubbed html,
|
208
|
+
html = "<tag>leave me <span>now</span></tag>"
|
209
|
+
assert_scrubbed html, "<tag>leave me </tag>"
|
173
210
|
end
|
174
211
|
end
|
175
212
|
|
176
213
|
class TextOnlyScrubberTest < ScrubberTest
|
177
214
|
def setup
|
178
|
-
@scrubber = Rails::
|
215
|
+
@scrubber = Rails::HTML::TextOnlyScrubber.new
|
179
216
|
end
|
180
217
|
|
181
218
|
def test_removes_all_tags_and_keep_the_content
|
182
|
-
assert_scrubbed
|
219
|
+
assert_scrubbed "<tag>hello</tag>", "hello"
|
183
220
|
end
|
184
221
|
|
185
222
|
def test_skips_text_nodes
|
186
|
-
assert_node_skipped(
|
223
|
+
assert_node_skipped("some text")
|
187
224
|
end
|
188
225
|
end
|
189
226
|
|
190
227
|
class ReturningStopFromScrubNodeTest < ScrubberTest
|
191
|
-
class ScrubStopper < Rails::
|
228
|
+
class ScrubStopper < Rails::HTML::PermitScrubber
|
192
229
|
def scrub_node(node)
|
193
230
|
Loofah::Scrubber::STOP
|
194
231
|
end
|
195
232
|
end
|
196
233
|
|
197
|
-
|
198
|
-
|
234
|
+
class ScrubContinuer < Rails::HTML::PermitScrubber
|
235
|
+
def scrub_node(node)
|
236
|
+
Loofah::Scrubber::CONTINUE
|
237
|
+
end
|
199
238
|
end
|
200
239
|
|
201
240
|
def test_returns_stop_from_scrub_if_scrub_node_does
|
202
|
-
|
241
|
+
@scrubber = ScrubStopper.new
|
242
|
+
assert_scrub_stopped "<script>remove me</script>"
|
243
|
+
end
|
244
|
+
|
245
|
+
def test_returns_continue_from_scrub_if_scrub_node_does
|
246
|
+
@scrubber = ScrubContinuer.new
|
247
|
+
assert_node_skipped "<script>keep me</script>"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
class PermitScrubberMinimalOperationsTest < ScrubberTest
|
252
|
+
class TestPermitScrubber < Rails::HTML::PermitScrubber
|
253
|
+
def initialize
|
254
|
+
@scrub_attribute_args = []
|
255
|
+
@scrub_attributes_args = []
|
256
|
+
|
257
|
+
super
|
258
|
+
|
259
|
+
self.tags = ["div"]
|
260
|
+
self.attributes = ["class"]
|
261
|
+
end
|
262
|
+
|
263
|
+
def scrub_attributes(node)
|
264
|
+
@scrub_attributes_args << node.name
|
265
|
+
|
266
|
+
super
|
267
|
+
end
|
268
|
+
|
269
|
+
def scrub_attribute(node, attr)
|
270
|
+
@scrub_attribute_args << [node.name, attr.name]
|
271
|
+
|
272
|
+
super
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def test_does_not_scrub_removed_attributes
|
277
|
+
@scrubber = TestPermitScrubber.new
|
278
|
+
|
279
|
+
input = "<div class='foo' href='bar'></div>"
|
280
|
+
frag = scrub_fragment(input)
|
281
|
+
assert_equal("<div class=\"foo\"></div>", frag)
|
282
|
+
|
283
|
+
assert_equal([["div", "class"]], @scrubber.instance_variable_get(:@scrub_attribute_args))
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_does_not_scrub_attributes_of_a_removed_node
|
287
|
+
@scrubber = TestPermitScrubber.new
|
288
|
+
|
289
|
+
input = "<div class='foo' href='bar'><svg xlink:href='asdf'><set></set></svg></div>"
|
290
|
+
frag = scrub_fragment(input)
|
291
|
+
assert_equal("<div class=\"foo\"></div>", frag)
|
292
|
+
|
293
|
+
assert_equal(["div"], @scrubber.instance_variable_get(:@scrub_attributes_args))
|
203
294
|
end
|
204
295
|
end
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-html-sanitizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rafael Mendonça França
|
8
8
|
- Kasper Timm Hansen
|
9
|
-
|
9
|
+
- Mike Dalessio
|
10
|
+
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date:
|
13
|
+
date: 2024-12-12 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: loofah
|
@@ -17,80 +18,87 @@ dependencies:
|
|
17
18
|
requirements:
|
18
19
|
- - "~>"
|
19
20
|
- !ruby/object:Gem::Version
|
20
|
-
version: '2.
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 2.19.1
|
21
|
+
version: '2.21'
|
24
22
|
type: :runtime
|
25
23
|
prerelease: false
|
26
24
|
version_requirements: !ruby/object:Gem::Requirement
|
27
25
|
requirements:
|
28
26
|
- - "~>"
|
29
27
|
- !ruby/object:Gem::Version
|
30
|
-
version: '2.
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 2.19.1
|
28
|
+
version: '2.21'
|
34
29
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
30
|
+
name: nokogiri
|
36
31
|
requirement: !ruby/object:Gem::Requirement
|
37
32
|
requirements:
|
38
33
|
- - ">="
|
39
34
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
41
|
-
|
42
|
-
prerelease: false
|
43
|
-
version_requirements: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
35
|
+
version: 1.15.7
|
36
|
+
- - "!="
|
46
37
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
48
|
-
-
|
49
|
-
name: rake
|
50
|
-
requirement: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
38
|
+
version: 1.16.0
|
39
|
+
- - "!="
|
53
40
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
55
|
-
|
56
|
-
prerelease: false
|
57
|
-
version_requirements: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
41
|
+
version: 1.16.0.rc1
|
42
|
+
- - "!="
|
60
43
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
62
|
-
-
|
63
|
-
name: minitest
|
64
|
-
requirement: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
44
|
+
version: 1.16.1
|
45
|
+
- - "!="
|
67
46
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
69
|
-
|
70
|
-
prerelease: false
|
71
|
-
version_requirements: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
47
|
+
version: 1.16.2
|
48
|
+
- - "!="
|
74
49
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
76
|
-
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
50
|
+
version: 1.16.3
|
51
|
+
- - "!="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.16.4
|
54
|
+
- - "!="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 1.16.5
|
57
|
+
- - "!="
|
81
58
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
83
|
-
|
59
|
+
version: 1.16.6
|
60
|
+
- - "!="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 1.16.7
|
63
|
+
type: :runtime
|
84
64
|
prerelease: false
|
85
65
|
version_requirements: !ruby/object:Gem::Requirement
|
86
66
|
requirements:
|
87
67
|
- - ">="
|
88
68
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
69
|
+
version: 1.15.7
|
70
|
+
- - "!="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 1.16.0
|
73
|
+
- - "!="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.16.0.rc1
|
76
|
+
- - "!="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 1.16.1
|
79
|
+
- - "!="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 1.16.2
|
82
|
+
- - "!="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 1.16.3
|
85
|
+
- - "!="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 1.16.4
|
88
|
+
- - "!="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 1.16.5
|
91
|
+
- - "!="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.16.6
|
94
|
+
- - "!="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.16.7
|
90
97
|
description: HTML sanitization for Rails applications
|
91
98
|
email:
|
92
99
|
- rafaelmfranca@gmail.com
|
93
100
|
- kaspth@gmail.com
|
101
|
+
- mike.dalessio@gmail.com
|
94
102
|
executables: []
|
95
103
|
extensions: []
|
96
104
|
extra_rdoc_files: []
|
@@ -102,6 +110,7 @@ files:
|
|
102
110
|
- lib/rails/html/sanitizer.rb
|
103
111
|
- lib/rails/html/sanitizer/version.rb
|
104
112
|
- lib/rails/html/scrubbers.rb
|
113
|
+
- test/rails_api_test.rb
|
105
114
|
- test/sanitizer_test.rb
|
106
115
|
- test/scrubbers_test.rb
|
107
116
|
homepage: https://github.com/rails/rails-html-sanitizer
|
@@ -109,10 +118,10 @@ licenses:
|
|
109
118
|
- MIT
|
110
119
|
metadata:
|
111
120
|
bug_tracker_uri: https://github.com/rails/rails-html-sanitizer/issues
|
112
|
-
changelog_uri: https://github.com/rails/rails-html-sanitizer/blob/v1.
|
113
|
-
documentation_uri: https://www.rubydoc.info/gems/rails-html-sanitizer/1.
|
114
|
-
source_code_uri: https://github.com/rails/rails-html-sanitizer/tree/v1.
|
115
|
-
post_install_message:
|
121
|
+
changelog_uri: https://github.com/rails/rails-html-sanitizer/blob/v1.6.2/CHANGELOG.md
|
122
|
+
documentation_uri: https://www.rubydoc.info/gems/rails-html-sanitizer/1.6.2
|
123
|
+
source_code_uri: https://github.com/rails/rails-html-sanitizer/tree/v1.6.2
|
124
|
+
post_install_message:
|
116
125
|
rdoc_options: []
|
117
126
|
require_paths:
|
118
127
|
- lib
|
@@ -120,17 +129,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
120
129
|
requirements:
|
121
130
|
- - ">="
|
122
131
|
- !ruby/object:Gem::Version
|
123
|
-
version:
|
132
|
+
version: 2.7.0
|
124
133
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
134
|
requirements:
|
126
135
|
- - ">="
|
127
136
|
- !ruby/object:Gem::Version
|
128
137
|
version: '0'
|
129
138
|
requirements: []
|
130
|
-
rubygems_version: 3.
|
131
|
-
signing_key:
|
139
|
+
rubygems_version: 3.3.22
|
140
|
+
signing_key:
|
132
141
|
specification_version: 4
|
133
142
|
summary: This gem is responsible to sanitize HTML fragments in Rails applications.
|
134
143
|
test_files:
|
144
|
+
- test/rails_api_test.rb
|
135
145
|
- test/sanitizer_test.rb
|
136
146
|
- test/scrubbers_test.rb
|