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