sanitize 6.0.2 → 7.0.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.
- checksums.yaml +4 -4
- data/{HISTORY.md → CHANGELOG.md} +64 -14
- data/LICENSE +3 -1
- data/README.md +120 -239
- data/lib/sanitize/config/basic.rb +15 -15
- data/lib/sanitize/config/default.rb +45 -45
- data/lib/sanitize/config/relaxed.rb +138 -32
- data/lib/sanitize/config/restricted.rb +2 -2
- data/lib/sanitize/config.rb +12 -14
- data/lib/sanitize/css.rb +317 -284
- data/lib/sanitize/transformers/clean_cdata.rb +9 -9
- data/lib/sanitize/transformers/clean_comment.rb +9 -9
- data/lib/sanitize/transformers/clean_css.rb +59 -55
- data/lib/sanitize/transformers/clean_doctype.rb +17 -13
- data/lib/sanitize/transformers/clean_element.rb +220 -237
- data/lib/sanitize/version.rb +3 -1
- data/lib/sanitize.rb +38 -38
- data/test/common.rb +4 -3
- data/test/test_clean_comment.rb +26 -25
- data/test/test_clean_css.rb +14 -13
- data/test/test_clean_doctype.rb +21 -20
- data/test/test_clean_element.rb +258 -273
- data/test/test_config.rb +22 -21
- data/test/test_malicious_css.rb +20 -19
- data/test/test_malicious_html.rb +100 -99
- data/test/test_parser.rb +26 -25
- data/test/test_sanitize.rb +70 -69
- data/test/test_sanitize_css.rb +158 -114
- data/test/test_transformers.rb +81 -83
- metadata +16 -43
data/test/test_sanitize_css.rb
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
|
-
#
|
|
2
|
-
require_relative 'common'
|
|
1
|
+
# frozen_string_literal: true
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
require_relative "common"
|
|
4
|
+
|
|
5
|
+
describe "Sanitize::CSS" do
|
|
5
6
|
make_my_diffs_pretty!
|
|
6
7
|
parallelize_me!
|
|
7
8
|
|
|
8
|
-
describe
|
|
9
|
+
describe "instance methods" do
|
|
9
10
|
before do
|
|
10
11
|
@default = Sanitize::CSS.new
|
|
11
12
|
@relaxed = Sanitize::CSS.new(Sanitize::Config::RELAXED[:css])
|
|
12
|
-
@custom
|
|
13
|
+
@custom = Sanitize::CSS.new(properties: %w[background color width])
|
|
13
14
|
end
|
|
14
15
|
|
|
15
|
-
describe
|
|
16
|
-
it
|
|
16
|
+
describe "#properties" do
|
|
17
|
+
it "should sanitize CSS properties" do
|
|
17
18
|
css = 'background: #fff; width: expression(alert("hi"));'
|
|
18
19
|
|
|
19
|
-
_(@default.properties(css)).must_equal
|
|
20
|
-
_(@relaxed.properties(css)).must_equal
|
|
21
|
-
_(@custom.properties(css)).must_equal
|
|
20
|
+
_(@default.properties(css)).must_equal " "
|
|
21
|
+
_(@relaxed.properties(css)).must_equal "background: #fff; "
|
|
22
|
+
_(@custom.properties(css)).must_equal "background: #fff; "
|
|
22
23
|
end
|
|
23
24
|
|
|
24
|
-
it
|
|
25
|
+
it "should allow allowlisted URL protocols" do
|
|
25
26
|
[
|
|
26
27
|
"background: url(relative.jpg)",
|
|
27
28
|
"background: url('relative.jpg')",
|
|
@@ -29,14 +30,23 @@ describe 'Sanitize::CSS' do
|
|
|
29
30
|
"background: url('ht\\tp://example.com/http.jpg')",
|
|
30
31
|
"background: url(https://example.com/https.jpg)",
|
|
31
32
|
"background: url('https://example.com/https.jpg')",
|
|
33
|
+
"background: image-set('relative.jpg' 1x, 'relative-2x.jpg' 2x)",
|
|
34
|
+
"background: image-set('https://example.com/https.jpg' 1x, 'https://example.com/https-2x.jpg' 2x)",
|
|
35
|
+
"background: image-set('https://example.com/https.jpg' type('image/jpeg'), 'https://example.com/https.avif' type('image/avif'))",
|
|
36
|
+
"background: -webkit-image-set('relative.jpg' 1x, 'relative-2x.jpg' 2x)",
|
|
37
|
+
"background: -webkit-image-set('https://example.com/https.jpg' 1x, 'https://example.com/https-2x.jpg' 2x)",
|
|
38
|
+
"background: -webkit-image-set('https://example.com/https.jpg' type('image/jpeg'), 'https://example.com/https.avif' type('image/avif'))",
|
|
39
|
+
"background: image('relative.jpg');",
|
|
40
|
+
"background: image('https://example.com/https.jpg');",
|
|
41
|
+
"background: image(rtl 'https://example.com/https.jpg');"
|
|
32
42
|
].each do |css|
|
|
33
|
-
_(@default.properties(css)).must_equal
|
|
43
|
+
_(@default.properties(css)).must_equal ""
|
|
34
44
|
_(@relaxed.properties(css)).must_equal css
|
|
35
|
-
_(@custom.properties(css)).must_equal
|
|
45
|
+
_(@custom.properties(css)).must_equal ""
|
|
36
46
|
end
|
|
37
47
|
end
|
|
38
48
|
|
|
39
|
-
it
|
|
49
|
+
it "should not allow non-allowlisted URL protocols" do
|
|
40
50
|
[
|
|
41
51
|
"background: url(javascript:alert(0))",
|
|
42
52
|
"background: url(ja\\56 ascript:alert(0))",
|
|
@@ -46,21 +56,21 @@ describe 'Sanitize::CSS' do
|
|
|
46
56
|
"background: url('javas\\\ncript:alert(0)')",
|
|
47
57
|
"background: url('java\\0script:foo')"
|
|
48
58
|
].each do |css|
|
|
49
|
-
_(@default.properties(css)).must_equal
|
|
50
|
-
_(@relaxed.properties(css)).must_equal
|
|
51
|
-
_(@custom.properties(css)).must_equal
|
|
59
|
+
_(@default.properties(css)).must_equal ""
|
|
60
|
+
_(@relaxed.properties(css)).must_equal ""
|
|
61
|
+
_(@custom.properties(css)).must_equal ""
|
|
52
62
|
end
|
|
53
63
|
end
|
|
54
64
|
|
|
55
|
-
it
|
|
65
|
+
it "should not allow -moz-binding" do
|
|
56
66
|
css = "-moz-binding:url('http://ha.ckers.org/xssmoz.xml#xss')"
|
|
57
67
|
|
|
58
|
-
_(@default.properties(css)).must_equal
|
|
59
|
-
_(@relaxed.properties(css)).must_equal
|
|
60
|
-
_(@custom.properties(css)).must_equal
|
|
68
|
+
_(@default.properties(css)).must_equal ""
|
|
69
|
+
_(@relaxed.properties(css)).must_equal ""
|
|
70
|
+
_(@custom.properties(css)).must_equal ""
|
|
61
71
|
end
|
|
62
72
|
|
|
63
|
-
it
|
|
73
|
+
it "should not allow expressions" do
|
|
64
74
|
[
|
|
65
75
|
"width:expression(alert(1))",
|
|
66
76
|
"width: /**/expression(alert(1)",
|
|
@@ -69,57 +79,57 @@ describe 'Sanitize::CSS' do
|
|
|
69
79
|
"xss:expression(alert(1))",
|
|
70
80
|
"height: foo(expression(alert(1)));"
|
|
71
81
|
].each do |css|
|
|
72
|
-
_(@default.properties(css)).must_equal
|
|
73
|
-
_(@relaxed.properties(css)).must_equal
|
|
74
|
-
_(@custom.properties(css)).must_equal
|
|
82
|
+
_(@default.properties(css)).must_equal ""
|
|
83
|
+
_(@relaxed.properties(css)).must_equal ""
|
|
84
|
+
_(@custom.properties(css)).must_equal ""
|
|
75
85
|
end
|
|
76
86
|
end
|
|
77
87
|
|
|
78
|
-
it
|
|
88
|
+
it "should not allow behaviors" do
|
|
79
89
|
css = "behavior: url(xss.htc);"
|
|
80
90
|
|
|
81
|
-
_(@default.properties(css)).must_equal
|
|
82
|
-
_(@relaxed.properties(css)).must_equal
|
|
83
|
-
_(@custom.properties(css)).must_equal
|
|
91
|
+
_(@default.properties(css)).must_equal ""
|
|
92
|
+
_(@relaxed.properties(css)).must_equal ""
|
|
93
|
+
_(@custom.properties(css)).must_equal ""
|
|
84
94
|
end
|
|
85
95
|
|
|
86
|
-
describe
|
|
87
|
-
it
|
|
88
|
-
_(@relaxed.properties(
|
|
89
|
-
.must_equal
|
|
96
|
+
describe "when :allow_comments is true" do
|
|
97
|
+
it "should preserve comments" do
|
|
98
|
+
_(@relaxed.properties("color: #fff; /* comment */ width: 100px;"))
|
|
99
|
+
.must_equal "color: #fff; /* comment */ width: 100px;"
|
|
90
100
|
|
|
91
101
|
_(@relaxed.properties("color: #fff; /* \n\ncomment */ width: 100px;"))
|
|
92
102
|
.must_equal "color: #fff; /* \n\ncomment */ width: 100px;"
|
|
93
103
|
end
|
|
94
104
|
end
|
|
95
105
|
|
|
96
|
-
describe
|
|
97
|
-
it
|
|
98
|
-
_(@custom.properties(
|
|
99
|
-
.must_equal
|
|
106
|
+
describe "when :allow_comments is false" do
|
|
107
|
+
it "should strip comments" do
|
|
108
|
+
_(@custom.properties("color: #fff; /* comment */ width: 100px;"))
|
|
109
|
+
.must_equal "color: #fff; width: 100px;"
|
|
100
110
|
|
|
101
111
|
_(@custom.properties("color: #fff; /* \n\ncomment */ width: 100px;"))
|
|
102
|
-
.must_equal
|
|
112
|
+
.must_equal "color: #fff; width: 100px;"
|
|
103
113
|
end
|
|
104
114
|
end
|
|
105
115
|
|
|
106
|
-
describe
|
|
107
|
-
it
|
|
108
|
-
_(@relaxed.properties(
|
|
109
|
-
.must_equal
|
|
116
|
+
describe "when :allow_hacks is true" do
|
|
117
|
+
it "should allow common CSS hacks" do
|
|
118
|
+
_(@relaxed.properties("_border: 1px solid #fff; *width: 10px"))
|
|
119
|
+
.must_equal "_border: 1px solid #fff; *width: 10px"
|
|
110
120
|
end
|
|
111
121
|
end
|
|
112
122
|
|
|
113
|
-
describe
|
|
114
|
-
it
|
|
115
|
-
_(@custom.properties(
|
|
116
|
-
.must_equal
|
|
123
|
+
describe "when :allow_hacks is false" do
|
|
124
|
+
it "should not allow common CSS hacks" do
|
|
125
|
+
_(@custom.properties("_border: 1px solid #fff; *width: 10px"))
|
|
126
|
+
.must_equal " "
|
|
117
127
|
end
|
|
118
128
|
end
|
|
119
129
|
end
|
|
120
130
|
|
|
121
|
-
describe
|
|
122
|
-
it
|
|
131
|
+
describe "#stylesheet" do
|
|
132
|
+
it "should sanitize a CSS stylesheet" do
|
|
123
133
|
css = %[
|
|
124
134
|
/* Yay CSS! */
|
|
125
135
|
.foo { color: #fff; }
|
|
@@ -131,82 +141,82 @@ describe 'Sanitize::CSS' do
|
|
|
131
141
|
}
|
|
132
142
|
].strip
|
|
133
143
|
|
|
134
|
-
_(@default.stylesheet(css).strip).must_equal %
|
|
144
|
+
_(@default.stylesheet(css).strip).must_equal %(
|
|
135
145
|
.foo { }
|
|
136
146
|
#bar { }
|
|
137
|
-
|
|
147
|
+
).strip
|
|
138
148
|
|
|
139
149
|
_(@relaxed.stylesheet(css)).must_equal css
|
|
140
150
|
|
|
141
|
-
_(@custom.stylesheet(css).strip).must_equal %
|
|
151
|
+
_(@custom.stylesheet(css).strip).must_equal %(
|
|
142
152
|
.foo { color: #fff; }
|
|
143
153
|
#bar { }
|
|
144
|
-
|
|
154
|
+
).strip
|
|
145
155
|
end
|
|
146
156
|
|
|
147
|
-
describe
|
|
148
|
-
it
|
|
149
|
-
_(@relaxed.stylesheet(
|
|
150
|
-
.must_equal
|
|
157
|
+
describe "when :allow_comments is true" do
|
|
158
|
+
it "should preserve comments" do
|
|
159
|
+
_(@relaxed.stylesheet(".foo { color: #fff; /* comment */ width: 100px; }"))
|
|
160
|
+
.must_equal ".foo { color: #fff; /* comment */ width: 100px; }"
|
|
151
161
|
|
|
152
162
|
_(@relaxed.stylesheet(".foo { color: #fff; /* \n\ncomment */ width: 100px; }"))
|
|
153
163
|
.must_equal ".foo { color: #fff; /* \n\ncomment */ width: 100px; }"
|
|
154
164
|
end
|
|
155
165
|
end
|
|
156
166
|
|
|
157
|
-
describe
|
|
158
|
-
it
|
|
159
|
-
_(@custom.stylesheet(
|
|
160
|
-
.must_equal
|
|
167
|
+
describe "when :allow_comments is false" do
|
|
168
|
+
it "should strip comments" do
|
|
169
|
+
_(@custom.stylesheet(".foo { color: #fff; /* comment */ width: 100px; }"))
|
|
170
|
+
.must_equal ".foo { color: #fff; width: 100px; }"
|
|
161
171
|
|
|
162
172
|
_(@custom.stylesheet(".foo { color: #fff; /* \n\ncomment */ width: 100px; }"))
|
|
163
|
-
.must_equal
|
|
173
|
+
.must_equal ".foo { color: #fff; width: 100px; }"
|
|
164
174
|
end
|
|
165
175
|
end
|
|
166
176
|
|
|
167
|
-
describe
|
|
168
|
-
it
|
|
169
|
-
_(@relaxed.stylesheet(
|
|
170
|
-
.must_equal
|
|
177
|
+
describe "when :allow_hacks is true" do
|
|
178
|
+
it "should allow common CSS hacks" do
|
|
179
|
+
_(@relaxed.stylesheet(".foo { _border: 1px solid #fff; *width: 10px }"))
|
|
180
|
+
.must_equal ".foo { _border: 1px solid #fff; *width: 10px }"
|
|
171
181
|
end
|
|
172
182
|
end
|
|
173
183
|
|
|
174
|
-
describe
|
|
175
|
-
it
|
|
176
|
-
_(@custom.stylesheet(
|
|
177
|
-
.must_equal
|
|
184
|
+
describe "when :allow_hacks is false" do
|
|
185
|
+
it "should not allow common CSS hacks" do
|
|
186
|
+
_(@custom.stylesheet(".foo { _border: 1px solid #fff; *width: 10px }"))
|
|
187
|
+
.must_equal ".foo { }"
|
|
178
188
|
end
|
|
179
189
|
end
|
|
180
190
|
end
|
|
181
191
|
|
|
182
|
-
describe
|
|
183
|
-
it
|
|
184
|
-
tree = Crass.parse(
|
|
185
|
-
".foo { background: #fff; font: 16pt 'Comic Sans MS'; }\n"
|
|
192
|
+
describe "#tree!" do
|
|
193
|
+
it "should sanitize a Crass CSS parse tree" do
|
|
194
|
+
tree = Crass.parse("@import url(foo.css);\n" \
|
|
195
|
+
".foo { background: #fff; font: 16pt 'Comic Sans MS'; }\n" \
|
|
186
196
|
"#bar { top: 125px; background: green; }")
|
|
187
197
|
|
|
188
198
|
_(@custom.tree!(tree)).must_be_same_as tree
|
|
189
199
|
|
|
190
|
-
_(Crass::Parser.stringify(tree)).must_equal
|
|
191
|
-
|
|
192
|
-
|
|
200
|
+
_(Crass::Parser.stringify(tree)).must_equal "\n" \
|
|
201
|
+
".foo { background: #fff; }\n" \
|
|
202
|
+
"#bar { background: green; }"
|
|
193
203
|
end
|
|
194
204
|
end
|
|
195
205
|
end
|
|
196
206
|
|
|
197
|
-
describe
|
|
198
|
-
describe
|
|
199
|
-
it
|
|
207
|
+
describe "class methods" do
|
|
208
|
+
describe ".properties" do
|
|
209
|
+
it "should sanitize CSS properties with the given config" do
|
|
200
210
|
css = 'background: #fff; width: expression(alert("hi"));'
|
|
201
211
|
|
|
202
|
-
_(Sanitize::CSS.properties(css)).must_equal
|
|
203
|
-
_(Sanitize::CSS.properties(css, Sanitize::Config::RELAXED[:css])).must_equal
|
|
204
|
-
_(Sanitize::CSS.properties(css, :
|
|
212
|
+
_(Sanitize::CSS.properties(css)).must_equal " "
|
|
213
|
+
_(Sanitize::CSS.properties(css, Sanitize::Config::RELAXED[:css])).must_equal "background: #fff; "
|
|
214
|
+
_(Sanitize::CSS.properties(css, properties: %w[background color width])).must_equal "background: #fff; "
|
|
205
215
|
end
|
|
206
216
|
end
|
|
207
217
|
|
|
208
|
-
describe
|
|
209
|
-
it
|
|
218
|
+
describe ".stylesheet" do
|
|
219
|
+
it "should sanitize a CSS stylesheet with the given config" do
|
|
210
220
|
css = %[
|
|
211
221
|
/* Yay CSS! */
|
|
212
222
|
.foo { color: #fff; }
|
|
@@ -218,43 +228,43 @@ describe 'Sanitize::CSS' do
|
|
|
218
228
|
}
|
|
219
229
|
].strip
|
|
220
230
|
|
|
221
|
-
_(Sanitize::CSS.stylesheet(css).strip).must_equal %
|
|
231
|
+
_(Sanitize::CSS.stylesheet(css).strip).must_equal %(
|
|
222
232
|
.foo { }
|
|
223
233
|
#bar { }
|
|
224
|
-
|
|
234
|
+
).strip
|
|
225
235
|
|
|
226
236
|
_(Sanitize::CSS.stylesheet(css, Sanitize::Config::RELAXED[:css])).must_equal css
|
|
227
237
|
|
|
228
|
-
_(Sanitize::CSS.stylesheet(css, :
|
|
238
|
+
_(Sanitize::CSS.stylesheet(css, properties: %w[background color width]).strip).must_equal %(
|
|
229
239
|
.foo { color: #fff; }
|
|
230
240
|
#bar { }
|
|
231
|
-
|
|
241
|
+
).strip
|
|
232
242
|
end
|
|
233
243
|
end
|
|
234
244
|
|
|
235
|
-
describe
|
|
236
|
-
it
|
|
237
|
-
tree = Crass.parse(
|
|
238
|
-
".foo { background: #fff; font: 16pt 'Comic Sans MS'; }\n"
|
|
245
|
+
describe ".tree!" do
|
|
246
|
+
it "should sanitize a Crass CSS parse tree with the given config" do
|
|
247
|
+
tree = Crass.parse("@import url(foo.css);\n" \
|
|
248
|
+
".foo { background: #fff; font: 16pt 'Comic Sans MS'; }\n" \
|
|
239
249
|
"#bar { top: 125px; background: green; }")
|
|
240
250
|
|
|
241
|
-
_(Sanitize::CSS.tree!(tree, :
|
|
251
|
+
_(Sanitize::CSS.tree!(tree, properties: %w[background color width])).must_be_same_as tree
|
|
242
252
|
|
|
243
|
-
_(Crass::Parser.stringify(tree)).must_equal
|
|
244
|
-
|
|
245
|
-
|
|
253
|
+
_(Crass::Parser.stringify(tree)).must_equal "\n" \
|
|
254
|
+
".foo { background: #fff; }\n" \
|
|
255
|
+
"#bar { background: green; }"
|
|
246
256
|
end
|
|
247
257
|
end
|
|
248
258
|
end
|
|
249
259
|
|
|
250
|
-
describe
|
|
260
|
+
describe "functionality" do
|
|
251
261
|
before do
|
|
252
262
|
@default = Sanitize::CSS.new
|
|
253
263
|
@relaxed = Sanitize::CSS.new(Sanitize::Config::RELAXED[:css])
|
|
254
264
|
end
|
|
255
265
|
|
|
256
266
|
# https://github.com/rgrove/sanitize/issues/121
|
|
257
|
-
it
|
|
267
|
+
it "should parse the contents of @media rules properly" do
|
|
258
268
|
css = '@media { p[class="center"] { text-align: center; }}'
|
|
259
269
|
_(@relaxed.stylesheet(css)).must_equal css
|
|
260
270
|
|
|
@@ -281,7 +291,7 @@ describe 'Sanitize::CSS' do
|
|
|
281
291
|
].strip
|
|
282
292
|
end
|
|
283
293
|
|
|
284
|
-
it
|
|
294
|
+
it "should parse @page rules properly" do
|
|
285
295
|
css = %[
|
|
286
296
|
@page { margin: 2cm } /* All margins set to 2cm */
|
|
287
297
|
|
|
@@ -314,15 +324,50 @@ describe 'Sanitize::CSS' do
|
|
|
314
324
|
.foo { color: green; }
|
|
315
325
|
].strip
|
|
316
326
|
|
|
317
|
-
_(@relaxed.stylesheet(css).strip).must_equal %
|
|
327
|
+
_(@relaxed.stylesheet(css).strip).must_equal %(
|
|
318
328
|
.foo { color: green; }
|
|
319
|
-
|
|
329
|
+
).strip
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
it "preserves allowlisted @container at-rules" do
|
|
333
|
+
# Sample code courtesy of MDN:
|
|
334
|
+
# https://developer.mozilla.org/en-US/docs/Web/CSS/@container
|
|
335
|
+
css = %(
|
|
336
|
+
@container (width > 400px) {
|
|
337
|
+
h2 {
|
|
338
|
+
font-size: 1.5em;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/* with an optional <container-name> */
|
|
343
|
+
@container tall (height > 30rem) {
|
|
344
|
+
h2 {
|
|
345
|
+
line-height: 1.6;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/* multiple queries in a single condition */
|
|
350
|
+
@container (width > 400px) and style(--responsive: true) {
|
|
351
|
+
h2 {
|
|
352
|
+
font-size: 1.5em;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/* condition list */
|
|
357
|
+
@container card (width > 400px), style(--responsive: true) {
|
|
358
|
+
h2 {
|
|
359
|
+
font-size: 1.5em;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
).strip
|
|
363
|
+
|
|
364
|
+
_(@relaxed.stylesheet(css).strip).must_equal css
|
|
320
365
|
end
|
|
321
366
|
|
|
322
367
|
describe "when blockless at-rules are allowlisted" do
|
|
323
368
|
before do
|
|
324
369
|
@scss = Sanitize::CSS.new(Sanitize::Config.merge(Sanitize::Config::RELAXED[:css], {
|
|
325
|
-
:
|
|
370
|
+
at_rules: ["charset", "import"]
|
|
326
371
|
}))
|
|
327
372
|
end
|
|
328
373
|
|
|
@@ -341,24 +386,23 @@ describe 'Sanitize::CSS' do
|
|
|
341
386
|
end
|
|
342
387
|
|
|
343
388
|
it "should remove them if they have invalid blocks" do
|
|
344
|
-
css = %
|
|
389
|
+
css = %(
|
|
345
390
|
@charset { color: green }
|
|
346
391
|
@import { color: green }
|
|
347
392
|
.foo { color: green; }
|
|
348
|
-
|
|
393
|
+
).strip
|
|
349
394
|
|
|
350
|
-
_(@scss.stylesheet(css).strip).must_equal %
|
|
395
|
+
_(@scss.stylesheet(css).strip).must_equal %(
|
|
351
396
|
.foo { color: green; }
|
|
352
|
-
|
|
397
|
+
).strip
|
|
353
398
|
end
|
|
354
399
|
end
|
|
355
400
|
|
|
356
401
|
describe "when validating @import rules" do
|
|
357
|
-
|
|
358
402
|
describe "with no validation proc specified" do
|
|
359
403
|
before do
|
|
360
404
|
@scss = Sanitize::CSS.new(Sanitize::Config.merge(Sanitize::Config::RELAXED[:css], {
|
|
361
|
-
:
|
|
405
|
+
at_rules: ["import"]
|
|
362
406
|
}))
|
|
363
407
|
end
|
|
364
408
|
|
|
@@ -375,10 +419,10 @@ describe 'Sanitize::CSS' do
|
|
|
375
419
|
|
|
376
420
|
describe "with a validation proc specified" do
|
|
377
421
|
before do
|
|
378
|
-
google_font_validator =
|
|
422
|
+
google_font_validator = proc { |url| url.start_with?("https://fonts.googleapis.com") }
|
|
379
423
|
|
|
380
424
|
@scss = Sanitize::CSS.new(Sanitize::Config.merge(Sanitize::Config::RELAXED[:css], {
|
|
381
|
-
:
|
|
425
|
+
at_rules: ["import"], import_url_validator: google_font_validator
|
|
382
426
|
}))
|
|
383
427
|
end
|
|
384
428
|
|
|
@@ -401,9 +445,9 @@ describe 'Sanitize::CSS' do
|
|
|
401
445
|
@import url('https://nastysite.com/nasty_hax0r.css');
|
|
402
446
|
].strip
|
|
403
447
|
|
|
404
|
-
_(@scss.stylesheet(css).strip).must_equal %
|
|
448
|
+
_(@scss.stylesheet(css).strip).must_equal %(
|
|
405
449
|
@import 'https://fonts.googleapis.com/css?family=Indie+Flower';
|
|
406
|
-
|
|
450
|
+
).strip
|
|
407
451
|
end
|
|
408
452
|
|
|
409
453
|
it "should not allow a blank url" do
|
|
@@ -413,9 +457,9 @@ describe 'Sanitize::CSS' do
|
|
|
413
457
|
@import url('');
|
|
414
458
|
].strip
|
|
415
459
|
|
|
416
|
-
_(@scss.stylesheet(css).strip).must_equal %
|
|
460
|
+
_(@scss.stylesheet(css).strip).must_equal %(
|
|
417
461
|
@import 'https://fonts.googleapis.com/css?family=Indie+Flower';
|
|
418
|
-
|
|
462
|
+
).strip
|
|
419
463
|
end
|
|
420
464
|
end
|
|
421
465
|
end
|