sanitize 6.1.3 → 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.
@@ -1,27 +1,28 @@
1
- # encoding: utf-8
2
- require_relative 'common'
1
+ # frozen_string_literal: true
3
2
 
4
- describe 'Sanitize::CSS' do
3
+ require_relative "common"
4
+
5
+ describe "Sanitize::CSS" do
5
6
  make_my_diffs_pretty!
6
7
  parallelize_me!
7
8
 
8
- describe 'instance methods' do
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 = Sanitize::CSS.new(:properties => %w[background color width])
13
+ @custom = Sanitize::CSS.new(properties: %w[background color width])
13
14
  end
14
15
 
15
- describe '#properties' do
16
- it 'should sanitize CSS properties' do
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 'background: #fff; '
21
- _(@custom.properties(css)).must_equal 'background: #fff; '
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 'should allow allowlisted URL protocols' do
25
+ it "should allow allowlisted URL protocols" do
25
26
  [
26
27
  "background: url(relative.jpg)",
27
28
  "background: url('relative.jpg')",
@@ -39,13 +40,13 @@ describe 'Sanitize::CSS' do
39
40
  "background: image('https://example.com/https.jpg');",
40
41
  "background: image(rtl 'https://example.com/https.jpg');"
41
42
  ].each do |css|
42
- _(@default.properties(css)).must_equal ''
43
+ _(@default.properties(css)).must_equal ""
43
44
  _(@relaxed.properties(css)).must_equal css
44
- _(@custom.properties(css)).must_equal ''
45
+ _(@custom.properties(css)).must_equal ""
45
46
  end
46
47
  end
47
48
 
48
- it 'should not allow non-allowlisted URL protocols' do
49
+ it "should not allow non-allowlisted URL protocols" do
49
50
  [
50
51
  "background: url(javascript:alert(0))",
51
52
  "background: url(ja\\56 ascript:alert(0))",
@@ -55,21 +56,21 @@ describe 'Sanitize::CSS' do
55
56
  "background: url('javas\\\ncript:alert(0)')",
56
57
  "background: url('java\\0script:foo')"
57
58
  ].each do |css|
58
- _(@default.properties(css)).must_equal ''
59
- _(@relaxed.properties(css)).must_equal ''
60
- _(@custom.properties(css)).must_equal ''
59
+ _(@default.properties(css)).must_equal ""
60
+ _(@relaxed.properties(css)).must_equal ""
61
+ _(@custom.properties(css)).must_equal ""
61
62
  end
62
63
  end
63
64
 
64
- it 'should not allow -moz-binding' do
65
+ it "should not allow -moz-binding" do
65
66
  css = "-moz-binding:url('http://ha.ckers.org/xssmoz.xml#xss')"
66
67
 
67
- _(@default.properties(css)).must_equal ''
68
- _(@relaxed.properties(css)).must_equal ''
69
- _(@custom.properties(css)).must_equal ''
68
+ _(@default.properties(css)).must_equal ""
69
+ _(@relaxed.properties(css)).must_equal ""
70
+ _(@custom.properties(css)).must_equal ""
70
71
  end
71
72
 
72
- it 'should not allow expressions' do
73
+ it "should not allow expressions" do
73
74
  [
74
75
  "width:expression(alert(1))",
75
76
  "width: /**/expression(alert(1)",
@@ -78,57 +79,57 @@ describe 'Sanitize::CSS' do
78
79
  "xss:expression(alert(1))",
79
80
  "height: foo(expression(alert(1)));"
80
81
  ].each do |css|
81
- _(@default.properties(css)).must_equal ''
82
- _(@relaxed.properties(css)).must_equal ''
83
- _(@custom.properties(css)).must_equal ''
82
+ _(@default.properties(css)).must_equal ""
83
+ _(@relaxed.properties(css)).must_equal ""
84
+ _(@custom.properties(css)).must_equal ""
84
85
  end
85
86
  end
86
87
 
87
- it 'should not allow behaviors' do
88
+ it "should not allow behaviors" do
88
89
  css = "behavior: url(xss.htc);"
89
90
 
90
- _(@default.properties(css)).must_equal ''
91
- _(@relaxed.properties(css)).must_equal ''
92
- _(@custom.properties(css)).must_equal ''
91
+ _(@default.properties(css)).must_equal ""
92
+ _(@relaxed.properties(css)).must_equal ""
93
+ _(@custom.properties(css)).must_equal ""
93
94
  end
94
95
 
95
- describe 'when :allow_comments is true' do
96
- it 'should preserve comments' do
97
- _(@relaxed.properties('color: #fff; /* comment */ width: 100px;'))
98
- .must_equal 'color: #fff; /* comment */ width: 100px;'
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;"
99
100
 
100
101
  _(@relaxed.properties("color: #fff; /* \n\ncomment */ width: 100px;"))
101
102
  .must_equal "color: #fff; /* \n\ncomment */ width: 100px;"
102
103
  end
103
104
  end
104
105
 
105
- describe 'when :allow_comments is false' do
106
- it 'should strip comments' do
107
- _(@custom.properties('color: #fff; /* comment */ width: 100px;'))
108
- .must_equal 'color: #fff; width: 100px;'
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;"
109
110
 
110
111
  _(@custom.properties("color: #fff; /* \n\ncomment */ width: 100px;"))
111
- .must_equal 'color: #fff; width: 100px;'
112
+ .must_equal "color: #fff; width: 100px;"
112
113
  end
113
114
  end
114
115
 
115
- describe 'when :allow_hacks is true' do
116
- it 'should allow common CSS hacks' do
117
- _(@relaxed.properties('_border: 1px solid #fff; *width: 10px'))
118
- .must_equal '_border: 1px solid #fff; *width: 10px'
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"
119
120
  end
120
121
  end
121
122
 
122
- describe 'when :allow_hacks is false' do
123
- it 'should not allow common CSS hacks' do
124
- _(@custom.properties('_border: 1px solid #fff; *width: 10px'))
125
- .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 " "
126
127
  end
127
128
  end
128
129
  end
129
130
 
130
- describe '#stylesheet' do
131
- it 'should sanitize a CSS stylesheet' do
131
+ describe "#stylesheet" do
132
+ it "should sanitize a CSS stylesheet" do
132
133
  css = %[
133
134
  /* Yay CSS! */
134
135
  .foo { color: #fff; }
@@ -140,82 +141,82 @@ describe 'Sanitize::CSS' do
140
141
  }
141
142
  ].strip
142
143
 
143
- _(@default.stylesheet(css).strip).must_equal %[
144
+ _(@default.stylesheet(css).strip).must_equal %(
144
145
  .foo { }
145
146
  #bar { }
146
- ].strip
147
+ ).strip
147
148
 
148
149
  _(@relaxed.stylesheet(css)).must_equal css
149
150
 
150
- _(@custom.stylesheet(css).strip).must_equal %[
151
+ _(@custom.stylesheet(css).strip).must_equal %(
151
152
  .foo { color: #fff; }
152
153
  #bar { }
153
- ].strip
154
+ ).strip
154
155
  end
155
156
 
156
- describe 'when :allow_comments is true' do
157
- it 'should preserve comments' do
158
- _(@relaxed.stylesheet('.foo { color: #fff; /* comment */ width: 100px; }'))
159
- .must_equal '.foo { color: #fff; /* comment */ width: 100px; }'
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; }"
160
161
 
161
162
  _(@relaxed.stylesheet(".foo { color: #fff; /* \n\ncomment */ width: 100px; }"))
162
163
  .must_equal ".foo { color: #fff; /* \n\ncomment */ width: 100px; }"
163
164
  end
164
165
  end
165
166
 
166
- describe 'when :allow_comments is false' do
167
- it 'should strip comments' do
168
- _(@custom.stylesheet('.foo { color: #fff; /* comment */ width: 100px; }'))
169
- .must_equal '.foo { color: #fff; width: 100px; }'
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; }"
170
171
 
171
172
  _(@custom.stylesheet(".foo { color: #fff; /* \n\ncomment */ width: 100px; }"))
172
- .must_equal '.foo { color: #fff; width: 100px; }'
173
+ .must_equal ".foo { color: #fff; width: 100px; }"
173
174
  end
174
175
  end
175
176
 
176
- describe 'when :allow_hacks is true' do
177
- it 'should allow common CSS hacks' do
178
- _(@relaxed.stylesheet('.foo { _border: 1px solid #fff; *width: 10px }'))
179
- .must_equal '.foo { _border: 1px solid #fff; *width: 10px }'
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 }"
180
181
  end
181
182
  end
182
183
 
183
- describe 'when :allow_hacks is false' do
184
- it 'should not allow common CSS hacks' do
185
- _(@custom.stylesheet('.foo { _border: 1px solid #fff; *width: 10px }'))
186
- .must_equal '.foo { }'
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 { }"
187
188
  end
188
189
  end
189
190
  end
190
191
 
191
- describe '#tree!' do
192
- it 'should sanitize a Crass CSS parse tree' do
193
- tree = Crass.parse(String.new("@import url(foo.css);\n") <<
194
- ".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" \
195
196
  "#bar { top: 125px; background: green; }")
196
197
 
197
198
  _(@custom.tree!(tree)).must_be_same_as tree
198
199
 
199
- _(Crass::Parser.stringify(tree)).must_equal String.new("\n") <<
200
- ".foo { background: #fff; }\n" <<
201
- "#bar { background: green; }"
200
+ _(Crass::Parser.stringify(tree)).must_equal "\n" \
201
+ ".foo { background: #fff; }\n" \
202
+ "#bar { background: green; }"
202
203
  end
203
204
  end
204
205
  end
205
206
 
206
- describe 'class methods' do
207
- describe '.properties' do
208
- it 'should sanitize CSS properties with the given config' do
207
+ describe "class methods" do
208
+ describe ".properties" do
209
+ it "should sanitize CSS properties with the given config" do
209
210
  css = 'background: #fff; width: expression(alert("hi"));'
210
211
 
211
- _(Sanitize::CSS.properties(css)).must_equal ' '
212
- _(Sanitize::CSS.properties(css, Sanitize::Config::RELAXED[:css])).must_equal 'background: #fff; '
213
- _(Sanitize::CSS.properties(css, :properties => %w[background color width])).must_equal 'background: #fff; '
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; "
214
215
  end
215
216
  end
216
217
 
217
- describe '.stylesheet' do
218
- it 'should sanitize a CSS stylesheet with the given config' do
218
+ describe ".stylesheet" do
219
+ it "should sanitize a CSS stylesheet with the given config" do
219
220
  css = %[
220
221
  /* Yay CSS! */
221
222
  .foo { color: #fff; }
@@ -227,43 +228,43 @@ describe 'Sanitize::CSS' do
227
228
  }
228
229
  ].strip
229
230
 
230
- _(Sanitize::CSS.stylesheet(css).strip).must_equal %[
231
+ _(Sanitize::CSS.stylesheet(css).strip).must_equal %(
231
232
  .foo { }
232
233
  #bar { }
233
- ].strip
234
+ ).strip
234
235
 
235
236
  _(Sanitize::CSS.stylesheet(css, Sanitize::Config::RELAXED[:css])).must_equal css
236
237
 
237
- _(Sanitize::CSS.stylesheet(css, :properties => %w[background color width]).strip).must_equal %[
238
+ _(Sanitize::CSS.stylesheet(css, properties: %w[background color width]).strip).must_equal %(
238
239
  .foo { color: #fff; }
239
240
  #bar { }
240
- ].strip
241
+ ).strip
241
242
  end
242
243
  end
243
244
 
244
- describe '.tree!' do
245
- it 'should sanitize a Crass CSS parse tree with the given config' do
246
- tree = Crass.parse(String.new("@import url(foo.css);\n") <<
247
- ".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" \
248
249
  "#bar { top: 125px; background: green; }")
249
250
 
250
- _(Sanitize::CSS.tree!(tree, :properties => %w[background color width])).must_be_same_as tree
251
+ _(Sanitize::CSS.tree!(tree, properties: %w[background color width])).must_be_same_as tree
251
252
 
252
- _(Crass::Parser.stringify(tree)).must_equal String.new("\n") <<
253
- ".foo { background: #fff; }\n" <<
254
- "#bar { background: green; }"
253
+ _(Crass::Parser.stringify(tree)).must_equal "\n" \
254
+ ".foo { background: #fff; }\n" \
255
+ "#bar { background: green; }"
255
256
  end
256
257
  end
257
258
  end
258
259
 
259
- describe 'functionality' do
260
+ describe "functionality" do
260
261
  before do
261
262
  @default = Sanitize::CSS.new
262
263
  @relaxed = Sanitize::CSS.new(Sanitize::Config::RELAXED[:css])
263
264
  end
264
265
 
265
266
  # https://github.com/rgrove/sanitize/issues/121
266
- it 'should parse the contents of @media rules properly' do
267
+ it "should parse the contents of @media rules properly" do
267
268
  css = '@media { p[class="center"] { text-align: center; }}'
268
269
  _(@relaxed.stylesheet(css)).must_equal css
269
270
 
@@ -290,7 +291,7 @@ describe 'Sanitize::CSS' do
290
291
  ].strip
291
292
  end
292
293
 
293
- it 'should parse @page rules properly' do
294
+ it "should parse @page rules properly" do
294
295
  css = %[
295
296
  @page { margin: 2cm } /* All margins set to 2cm */
296
297
 
@@ -323,15 +324,50 @@ describe 'Sanitize::CSS' do
323
324
  .foo { color: green; }
324
325
  ].strip
325
326
 
326
- _(@relaxed.stylesheet(css).strip).must_equal %[
327
+ _(@relaxed.stylesheet(css).strip).must_equal %(
327
328
  .foo { color: green; }
328
- ].strip
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
329
365
  end
330
366
 
331
367
  describe "when blockless at-rules are allowlisted" do
332
368
  before do
333
369
  @scss = Sanitize::CSS.new(Sanitize::Config.merge(Sanitize::Config::RELAXED[:css], {
334
- :at_rules => ['charset', 'import']
370
+ at_rules: ["charset", "import"]
335
371
  }))
336
372
  end
337
373
 
@@ -350,24 +386,23 @@ describe 'Sanitize::CSS' do
350
386
  end
351
387
 
352
388
  it "should remove them if they have invalid blocks" do
353
- css = %[
389
+ css = %(
354
390
  @charset { color: green }
355
391
  @import { color: green }
356
392
  .foo { color: green; }
357
- ].strip
393
+ ).strip
358
394
 
359
- _(@scss.stylesheet(css).strip).must_equal %[
395
+ _(@scss.stylesheet(css).strip).must_equal %(
360
396
  .foo { color: green; }
361
- ].strip
397
+ ).strip
362
398
  end
363
399
  end
364
400
 
365
401
  describe "when validating @import rules" do
366
-
367
402
  describe "with no validation proc specified" do
368
403
  before do
369
404
  @scss = Sanitize::CSS.new(Sanitize::Config.merge(Sanitize::Config::RELAXED[:css], {
370
- :at_rules => ['import']
405
+ at_rules: ["import"]
371
406
  }))
372
407
  end
373
408
 
@@ -384,10 +419,10 @@ describe 'Sanitize::CSS' do
384
419
 
385
420
  describe "with a validation proc specified" do
386
421
  before do
387
- google_font_validator = Proc.new { |url| url.start_with?("https://fonts.googleapis.com") }
422
+ google_font_validator = proc { |url| url.start_with?("https://fonts.googleapis.com") }
388
423
 
389
424
  @scss = Sanitize::CSS.new(Sanitize::Config.merge(Sanitize::Config::RELAXED[:css], {
390
- :at_rules => ['import'], :import_url_validator => google_font_validator
425
+ at_rules: ["import"], import_url_validator: google_font_validator
391
426
  }))
392
427
  end
393
428
 
@@ -410,9 +445,9 @@ describe 'Sanitize::CSS' do
410
445
  @import url('https://nastysite.com/nasty_hax0r.css');
411
446
  ].strip
412
447
 
413
- _(@scss.stylesheet(css).strip).must_equal %[
448
+ _(@scss.stylesheet(css).strip).must_equal %(
414
449
  @import 'https://fonts.googleapis.com/css?family=Indie+Flower';
415
- ].strip
450
+ ).strip
416
451
  end
417
452
 
418
453
  it "should not allow a blank url" do
@@ -422,9 +457,9 @@ describe 'Sanitize::CSS' do
422
457
  @import url('');
423
458
  ].strip
424
459
 
425
- _(@scss.stylesheet(css).strip).must_equal %[
460
+ _(@scss.stylesheet(css).strip).must_equal %(
426
461
  @import 'https://fonts.googleapis.com/css?family=Indie+Flower';
427
- ].strip
462
+ ).strip
428
463
  end
429
464
  end
430
465
  end