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/lib/sanitize/css.rb
CHANGED
@@ -1,325 +1,333 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
|
6
|
-
class Sanitize
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
self.
|
23
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "crass"
|
4
|
+
require "set"
|
5
|
+
|
6
|
+
class Sanitize
|
7
|
+
class CSS
|
8
|
+
attr_reader :config
|
9
|
+
|
10
|
+
# -- Class Methods ---------------------------------------------------------
|
11
|
+
|
12
|
+
# Sanitizes inline CSS style properties.
|
13
|
+
#
|
14
|
+
# This is most useful for sanitizing non-stylesheet fragments of CSS like
|
15
|
+
# you would find in the `style` attribute of an HTML element. To sanitize a
|
16
|
+
# full CSS stylesheet, use {.stylesheet}.
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# Sanitize::CSS.properties("background: url(foo.png); color: #fff;")
|
20
|
+
#
|
21
|
+
# @return [String] Sanitized CSS properties.
|
22
|
+
def self.properties(css, config = {})
|
23
|
+
new(config).properties(css)
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
26
|
+
# Sanitizes a full CSS stylesheet.
|
27
|
+
#
|
28
|
+
# A stylesheet may include selectors, at-rules, and comments. To sanitize
|
29
|
+
# only inline style properties such as the contents of an HTML `style`
|
30
|
+
# attribute, use {.properties}.
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# css = %[
|
34
|
+
# .foo {
|
35
|
+
# background: url(foo.png);
|
36
|
+
# color: #fff;
|
37
|
+
# }
|
38
|
+
#
|
39
|
+
# #bar {
|
40
|
+
# font: 42pt 'Comic Sans MS';
|
41
|
+
# }
|
42
|
+
# ]
|
43
|
+
#
|
44
|
+
# Sanitize::CSS.stylesheet(css, Sanitize::Config::RELAXED)
|
45
|
+
#
|
46
|
+
# @return [String] Sanitized CSS stylesheet.
|
47
|
+
def self.stylesheet(css, config = {})
|
48
|
+
new(config).stylesheet(css)
|
49
|
+
end
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
51
|
+
# Sanitizes the given Crass CSS parse tree and all its children, modifying
|
52
|
+
# it in place.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# css = %[
|
56
|
+
# .foo {
|
57
|
+
# background: url(foo.png);
|
58
|
+
# color: #fff;
|
59
|
+
# }
|
60
|
+
#
|
61
|
+
# #bar {
|
62
|
+
# font: 42pt 'Comic Sans MS';
|
63
|
+
# }
|
64
|
+
# ]
|
65
|
+
#
|
66
|
+
# tree = Crass.parse(css)
|
67
|
+
# Sanitize::CSS.tree!(tree, Sanitize::Config::RELAXED)
|
68
|
+
#
|
69
|
+
# @return [Array] Sanitized Crass CSS parse tree.
|
70
|
+
def self.tree!(tree, config = {})
|
71
|
+
new(config).tree!(tree)
|
72
|
+
end
|
72
73
|
|
73
|
-
|
74
|
+
# -- Instance Methods ------------------------------------------------------
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
76
|
+
# Returns a new Sanitize::CSS object initialized with the settings in
|
77
|
+
# _config_.
|
78
|
+
def initialize(config = {})
|
79
|
+
@config = Config.merge(Config::DEFAULT[:css], config[:css] || config)
|
79
80
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
81
|
+
@at_rules = Set.new(@config[:at_rules])
|
82
|
+
@at_rules_with_properties = Set.new(@config[:at_rules_with_properties])
|
83
|
+
@at_rules_with_styles = Set.new(@config[:at_rules_with_styles])
|
84
|
+
@import_url_validator = @config[:import_url_validator]
|
85
|
+
end
|
85
86
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
87
|
+
# Sanitizes inline CSS style properties.
|
88
|
+
#
|
89
|
+
# This is most useful for sanitizing non-stylesheet fragments of CSS like
|
90
|
+
# you would find in the `style` attribute of an HTML element. To sanitize a
|
91
|
+
# full CSS stylesheet, use {#stylesheet}.
|
92
|
+
#
|
93
|
+
# @example
|
94
|
+
# scss = Sanitize::CSS.new(Sanitize::Config::RELAXED)
|
95
|
+
# scss.properties("background: url(foo.png); color: #fff;")
|
96
|
+
#
|
97
|
+
# @return [String] Sanitized CSS properties.
|
98
|
+
def properties(css)
|
99
|
+
tree = Crass.parse_properties(css,
|
100
|
+
preserve_comments: @config[:allow_comments],
|
101
|
+
preserve_hacks: @config[:allow_hacks])
|
102
|
+
|
103
|
+
tree!(tree)
|
104
|
+
Crass::Parser.stringify(tree)
|
105
|
+
end
|
105
106
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
107
|
+
# Sanitizes a full CSS stylesheet.
|
108
|
+
#
|
109
|
+
# A stylesheet may include selectors, at-rules, and comments. To sanitize
|
110
|
+
# only inline style properties such as the contents of an HTML `style`
|
111
|
+
# attribute, use {#properties}.
|
112
|
+
#
|
113
|
+
# @example
|
114
|
+
# css = %[
|
115
|
+
# .foo {
|
116
|
+
# background: url(foo.png);
|
117
|
+
# color: #fff;
|
118
|
+
# }
|
119
|
+
#
|
120
|
+
# #bar {
|
121
|
+
# font: 42pt 'Comic Sans MS';
|
122
|
+
# }
|
123
|
+
# ]
|
124
|
+
#
|
125
|
+
# scss = Sanitize::CSS.new(Sanitize::Config::RELAXED)
|
126
|
+
# scss.stylesheet(css)
|
127
|
+
#
|
128
|
+
# @return [String] Sanitized CSS stylesheet.
|
129
|
+
def stylesheet(css)
|
130
|
+
tree = Crass.parse(css,
|
131
|
+
preserve_comments: @config[:allow_comments],
|
132
|
+
preserve_hacks: @config[:allow_hacks])
|
133
|
+
|
134
|
+
tree!(tree)
|
135
|
+
Crass::Parser.stringify(tree)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Sanitizes the given Crass CSS parse tree and all its children, modifying
|
139
|
+
# it in place.
|
140
|
+
#
|
141
|
+
# @example
|
142
|
+
# css = %[
|
143
|
+
# .foo {
|
144
|
+
# background: url(foo.png);
|
145
|
+
# color: #fff;
|
146
|
+
# }
|
147
|
+
#
|
148
|
+
# #bar {
|
149
|
+
# font: 42pt 'Comic Sans MS';
|
150
|
+
# }
|
151
|
+
# ]
|
152
|
+
#
|
153
|
+
# scss = Sanitize::CSS.new(Sanitize::Config::RELAXED)
|
154
|
+
# tree = Crass.parse(css)
|
155
|
+
#
|
156
|
+
# scss.tree!(tree)
|
157
|
+
#
|
158
|
+
# @return [Array] Sanitized Crass CSS parse tree.
|
159
|
+
def tree!(tree)
|
160
|
+
preceded_by_property = false
|
161
|
+
|
162
|
+
tree.map! do |node|
|
163
|
+
next nil if node.nil?
|
164
|
+
|
165
|
+
case node[:node]
|
166
|
+
when :at_rule
|
167
|
+
preceded_by_property = false
|
168
|
+
next at_rule!(node)
|
169
|
+
|
170
|
+
when :comment
|
171
|
+
next node if @config[:allow_comments]
|
172
|
+
|
173
|
+
when :property
|
174
|
+
prop = property!(node)
|
175
|
+
preceded_by_property = !prop.nil?
|
176
|
+
next prop
|
177
|
+
|
178
|
+
when :semicolon
|
179
|
+
# Only preserve the semicolon if it was preceded by an allowlisted
|
180
|
+
# property. Otherwise, omit it in order to prevent redundant
|
181
|
+
# semicolons.
|
182
|
+
if preceded_by_property
|
183
|
+
preceded_by_property = false
|
184
|
+
next node
|
185
|
+
end
|
136
186
|
|
137
|
-
|
138
|
-
# in place.
|
139
|
-
#
|
140
|
-
# @example
|
141
|
-
# css = %[
|
142
|
-
# .foo {
|
143
|
-
# background: url(foo.png);
|
144
|
-
# color: #fff;
|
145
|
-
# }
|
146
|
-
#
|
147
|
-
# #bar {
|
148
|
-
# font: 42pt 'Comic Sans MS';
|
149
|
-
# }
|
150
|
-
# ]
|
151
|
-
#
|
152
|
-
# scss = Sanitize::CSS.new(Sanitize::Config::RELAXED)
|
153
|
-
# tree = Crass.parse(css)
|
154
|
-
#
|
155
|
-
# scss.tree!(tree)
|
156
|
-
#
|
157
|
-
# @return [Array] Sanitized Crass CSS parse tree.
|
158
|
-
def tree!(tree)
|
159
|
-
preceded_by_property = false
|
160
|
-
|
161
|
-
tree.map! do |node|
|
162
|
-
next nil if node.nil?
|
163
|
-
|
164
|
-
case node[:node]
|
165
|
-
when :at_rule
|
166
|
-
preceded_by_property = false
|
167
|
-
next at_rule!(node)
|
168
|
-
|
169
|
-
when :comment
|
170
|
-
next node if @config[:allow_comments]
|
171
|
-
|
172
|
-
when :property
|
173
|
-
prop = property!(node)
|
174
|
-
preceded_by_property = !prop.nil?
|
175
|
-
next prop
|
176
|
-
|
177
|
-
when :semicolon
|
178
|
-
# Only preserve the semicolon if it was preceded by an allowlisted
|
179
|
-
# property. Otherwise, omit it in order to prevent redundant semicolons.
|
180
|
-
if preceded_by_property
|
187
|
+
when :style_rule
|
181
188
|
preceded_by_property = false
|
189
|
+
tree!(node[:children])
|
182
190
|
next node
|
183
|
-
end
|
184
191
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
next node
|
192
|
+
when :whitespace
|
193
|
+
next node
|
194
|
+
end
|
189
195
|
|
190
|
-
|
191
|
-
next node
|
196
|
+
nil
|
192
197
|
end
|
193
198
|
|
194
|
-
|
199
|
+
tree
|
195
200
|
end
|
196
201
|
|
197
|
-
|
198
|
-
|
202
|
+
# -- Protected Instance Methods --------------------------------------------
|
203
|
+
protected
|
199
204
|
|
200
|
-
|
201
|
-
|
205
|
+
# Sanitizes a CSS at-rule node. Returns the sanitized node, or `nil` if the
|
206
|
+
# current config doesn't allow this at-rule.
|
207
|
+
def at_rule!(rule)
|
208
|
+
name = rule[:name].downcase
|
202
209
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
210
|
+
if @at_rules_with_styles.include?(name)
|
211
|
+
styles = Crass::Parser.parse_rules(rule[:block],
|
212
|
+
preserve_comments: @config[:allow_comments],
|
213
|
+
preserve_hacks: @config[:allow_hacks])
|
207
214
|
|
208
|
-
|
209
|
-
styles = Crass::Parser.parse_rules(rule[:block],
|
210
|
-
:preserve_comments => @config[:allow_comments],
|
211
|
-
:preserve_hacks => @config[:allow_hacks])
|
215
|
+
rule[:block] = tree!(styles)
|
212
216
|
|
213
|
-
|
217
|
+
elsif @at_rules_with_properties.include?(name)
|
218
|
+
props = Crass::Parser.parse_properties(rule[:block],
|
219
|
+
preserve_comments: @config[:allow_comments],
|
220
|
+
preserve_hacks: @config[:allow_hacks])
|
214
221
|
|
215
|
-
|
216
|
-
props = Crass::Parser.parse_properties(rule[:block],
|
217
|
-
:preserve_comments => @config[:allow_comments],
|
218
|
-
:preserve_hacks => @config[:allow_hacks])
|
222
|
+
rule[:block] = tree!(props)
|
219
223
|
|
220
|
-
|
224
|
+
elsif @at_rules.include?(name)
|
225
|
+
return nil if name == "import" && !import_url_allowed?(rule)
|
226
|
+
return nil if rule.has_key?(:block)
|
227
|
+
else
|
228
|
+
return nil
|
229
|
+
end
|
221
230
|
|
222
|
-
|
223
|
-
return nil if name == "import" && !import_url_allowed?(rule)
|
224
|
-
return nil if rule.has_key?(:block)
|
225
|
-
else
|
226
|
-
return nil
|
231
|
+
rule
|
227
232
|
end
|
228
233
|
|
229
|
-
|
230
|
-
|
234
|
+
# Returns `true` if the given CSS function name is an image-related function
|
235
|
+
# that may contain image URLs that need to be validated.
|
236
|
+
def image_function?(name)
|
237
|
+
["image", "image-set", "-webkit-image-set"].include?(name)
|
238
|
+
end
|
231
239
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
240
|
+
# Passes the URL value of an @import rule to a block to ensure
|
241
|
+
# it's an allowed URL
|
242
|
+
def import_url_allowed?(rule)
|
243
|
+
return true unless @import_url_validator
|
236
244
|
|
237
|
-
|
245
|
+
url_token = rule[:tokens].detect { |t| t[:node] == :url || t[:node] == :string }
|
238
246
|
|
239
|
-
|
240
|
-
|
247
|
+
# don't allow @imports with no URL value
|
248
|
+
return false unless url_token && (import_url = url_token[:value])
|
241
249
|
|
242
|
-
|
243
|
-
|
250
|
+
@import_url_validator.call(import_url)
|
251
|
+
end
|
244
252
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
253
|
+
# Sanitizes a CSS property node. Returns the sanitized node, or `nil` if the
|
254
|
+
# current config doesn't allow this property.
|
255
|
+
def property!(prop)
|
256
|
+
name = prop[:name].downcase
|
249
257
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
258
|
+
# Preserve IE * and _ hacks if desired.
|
259
|
+
if @config[:allow_hacks]
|
260
|
+
name.slice!(0) if /\A[*_]/.match?(name)
|
261
|
+
end
|
262
|
+
|
263
|
+
return nil unless @config[:properties].include?(name)
|
254
264
|
|
255
|
-
|
265
|
+
nodes = prop[:children].dup
|
266
|
+
combined_value = +""
|
256
267
|
|
257
|
-
|
258
|
-
|
268
|
+
nodes.each do |child|
|
269
|
+
value = child[:value]
|
259
270
|
|
260
|
-
|
261
|
-
|
271
|
+
case child[:node]
|
272
|
+
when :ident
|
273
|
+
combined_value << value.downcase if String === value
|
262
274
|
|
263
|
-
|
264
|
-
|
265
|
-
|
275
|
+
when :function
|
276
|
+
if child.key?(:name)
|
277
|
+
name = child[:name].downcase
|
266
278
|
|
267
|
-
|
268
|
-
|
269
|
-
|
279
|
+
if name == "url"
|
280
|
+
return nil unless valid_url?(child)
|
281
|
+
end
|
270
282
|
|
271
|
-
|
272
|
-
|
283
|
+
if image_function?(name)
|
284
|
+
return nil unless valid_image?(child)
|
285
|
+
end
|
286
|
+
|
287
|
+
combined_value << name
|
288
|
+
return nil if name == "expression" || combined_value == "expression"
|
273
289
|
end
|
274
290
|
|
275
|
-
if
|
276
|
-
|
291
|
+
if Array === value
|
292
|
+
nodes.concat(value)
|
293
|
+
elsif String === value
|
294
|
+
lowercase_value = value.downcase
|
295
|
+
combined_value << lowercase_value
|
296
|
+
return nil if lowercase_value == "expression" || combined_value == "expression"
|
277
297
|
end
|
278
298
|
|
279
|
-
|
280
|
-
return nil
|
281
|
-
end
|
299
|
+
when :url
|
300
|
+
return nil unless valid_url?(child)
|
282
301
|
|
283
|
-
|
284
|
-
|
285
|
-
elsif String === value
|
286
|
-
lowercase_value = value.downcase
|
287
|
-
combined_value << lowercase_value
|
288
|
-
return nil if lowercase_value == 'expression' || combined_value == 'expression'
|
302
|
+
when :bad_url
|
303
|
+
return nil
|
289
304
|
end
|
290
|
-
|
291
|
-
when :url
|
292
|
-
return nil unless valid_url?(child)
|
293
|
-
|
294
|
-
when :bad_url
|
295
|
-
return nil
|
296
305
|
end
|
297
|
-
end
|
298
306
|
|
299
|
-
|
300
|
-
|
307
|
+
prop
|
308
|
+
end
|
301
309
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
310
|
+
# Returns `true` if the given node (which may be of type `:url` or
|
311
|
+
# `:function`, since the CSS syntax can produce both) uses an allowlisted
|
312
|
+
# protocol.
|
313
|
+
def valid_url?(node)
|
314
|
+
type = node[:node]
|
307
315
|
|
308
|
-
|
309
|
-
|
310
|
-
|
316
|
+
if type == :function
|
317
|
+
return false unless node.key?(:name) && node[:name].downcase == "url"
|
318
|
+
return false unless Array === node[:value]
|
311
319
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
320
|
+
# A URL function's `:value` should be an array containing no more than
|
321
|
+
# one `:string` node and any number of `:whitespace` nodes.
|
322
|
+
#
|
323
|
+
# If it contains more than one `:string` node, or if it contains any
|
324
|
+
# other nodes except `:whitespace` nodes, it's not valid.
|
325
|
+
url_string_node = nil
|
318
326
|
|
319
|
-
|
320
|
-
|
327
|
+
node[:value].each do |token|
|
328
|
+
return false unless Hash === token
|
321
329
|
|
322
|
-
|
330
|
+
case token[:node]
|
323
331
|
when :string
|
324
332
|
return false unless url_string_node.nil?
|
325
333
|
url_string_node = token
|
@@ -329,47 +337,45 @@ class Sanitize; class CSS
|
|
329
337
|
|
330
338
|
else
|
331
339
|
return false
|
340
|
+
end
|
332
341
|
end
|
333
|
-
end
|
334
342
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
343
|
+
return false if url_string_node.nil?
|
344
|
+
url = url_string_node[:value]
|
345
|
+
elsif type == :url
|
346
|
+
url = node[:value]
|
347
|
+
else
|
348
|
+
return false
|
349
|
+
end
|
342
350
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
351
|
+
if url =~ Sanitize::REGEX_PROTOCOL
|
352
|
+
@config[:protocols].include?($1.downcase)
|
353
|
+
else
|
354
|
+
@config[:protocols].include?(:relative)
|
355
|
+
end
|
347
356
|
end
|
348
357
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
return false unless node[:node] == :function
|
356
|
-
return false unless node.key?(:name) && ['image', 'image-set'].include?(node[:name].downcase)
|
357
|
-
return false unless Array === node[:value]
|
358
|
+
# Returns `true` if the given node is an image-related function and contains
|
359
|
+
# only strings that use an allowlisted protocol.
|
360
|
+
def valid_image?(node)
|
361
|
+
return false unless node[:node] == :function
|
362
|
+
return false unless node.key?(:name) && image_function?(node[:name].downcase)
|
363
|
+
return false unless Array === node[:value]
|
358
364
|
|
359
|
-
|
365
|
+
node[:value].each do |token|
|
360
366
|
return false unless Hash === token
|
361
367
|
|
362
368
|
case token[:node]
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
else
|
367
|
-
return false unless @config[:protocols].include?(:relative)
|
368
|
-
end
|
369
|
+
when :string
|
370
|
+
if token[:value] =~ Sanitize::REGEX_PROTOCOL
|
371
|
+
return false unless @config[:protocols].include?($1.downcase)
|
369
372
|
else
|
370
|
-
|
373
|
+
return false unless @config[:protocols].include?(:relative)
|
374
|
+
end
|
375
|
+
else
|
376
|
+
next
|
371
377
|
end
|
372
378
|
end
|
379
|
+
end
|
373
380
|
end
|
374
|
-
|
375
|
-
end; end
|
381
|
+
end
|