safe_yaml 0.5 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +2 -1
- data/lib/safe_yaml.rb +7 -0
- data/lib/safe_yaml/transform.rb +12 -34
- data/lib/safe_yaml/transform/to_boolean.rb +19 -0
- data/lib/safe_yaml/transform/to_date.rb +13 -0
- data/lib/safe_yaml/transform/to_float.rb +12 -0
- data/lib/safe_yaml/transform/to_integer.rb +12 -0
- data/lib/safe_yaml/transform/to_nil.rb +16 -0
- data/lib/safe_yaml/transform/to_symbol.rb +12 -0
- data/lib/safe_yaml/transform/to_time.rb +15 -0
- data/lib/safe_yaml/version.rb +1 -1
- data/spec/safe_yaml_spec.rb +0 -1
- data/spec/shared_specs.rb +39 -30
- data/spec/spec_helper.rb +1 -0
- metadata +9 -2
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -55,7 +55,7 @@ Observe:
|
|
55
55
|
I'm in yr system!
|
56
56
|
=> #<ExploitableClassBuilder:0x007fdbbe2e25d8 @class=#<Class:0x007fdbbe2e2510>>
|
57
57
|
|
58
|
-
With
|
58
|
+
With SafeYAML, that attacker would be thwarted:
|
59
59
|
|
60
60
|
> require "safe_yaml"
|
61
61
|
=> true
|
@@ -72,6 +72,7 @@ The way that SafeYAML works is by restricting the kinds of objects that can be d
|
|
72
72
|
- Strings
|
73
73
|
- Numbers
|
74
74
|
- Dates
|
75
|
+
- Times
|
75
76
|
- Booleans
|
76
77
|
- Nils
|
77
78
|
|
data/lib/safe_yaml.rb
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
require "yaml"
|
2
|
+
require "safe_yaml/transform/to_boolean"
|
3
|
+
require "safe_yaml/transform/to_date"
|
4
|
+
require "safe_yaml/transform/to_float"
|
5
|
+
require "safe_yaml/transform/to_integer"
|
6
|
+
require "safe_yaml/transform/to_nil"
|
7
|
+
require "safe_yaml/transform/to_symbol"
|
8
|
+
require "safe_yaml/transform/to_time"
|
2
9
|
require "safe_yaml/transform"
|
3
10
|
require "safe_yaml/version"
|
4
11
|
|
data/lib/safe_yaml/transform.rb
CHANGED
@@ -4,43 +4,21 @@ module SafeYAML
|
|
4
4
|
:enable_symbol_parsing => false
|
5
5
|
}
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
"false" => false
|
17
|
-
}.freeze
|
18
|
-
|
19
|
-
SYMBOL_MATCHER = /^:\w+$/.freeze
|
20
|
-
|
21
|
-
INTEGER_MATCHER = /^\d+$/.freeze
|
22
|
-
|
23
|
-
FLOAT_MATCHER = /^(?:\d+(?:\.\d*)?$)|(?:^\.\d+$)/.freeze
|
24
|
-
|
25
|
-
DATE_MATCHER = /^\d{4}\-\d{2}\-\d{2}$/.freeze
|
7
|
+
TRANSFORMERS = [
|
8
|
+
Transform::ToSymbol.new,
|
9
|
+
Transform::ToInteger.new,
|
10
|
+
Transform::ToFloat.new,
|
11
|
+
Transform::ToNil.new,
|
12
|
+
Transform::ToBoolean.new,
|
13
|
+
Transform::ToDate.new,
|
14
|
+
Transform::ToTime.new
|
15
|
+
]
|
26
16
|
|
27
17
|
def self.to_proper_type(value)
|
28
18
|
if value.is_a?(String)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
elsif OPTIONS[:enable_symbol_parsing] && value.match(SYMBOL_MATCHER)
|
33
|
-
return value[1..-1].to_sym
|
34
|
-
|
35
|
-
elsif value.match(INTEGER_MATCHER)
|
36
|
-
return value.to_i
|
37
|
-
|
38
|
-
elsif value.match(FLOAT_MATCHER)
|
39
|
-
return value.to_f
|
40
|
-
|
41
|
-
elsif value.match(DATE_MATCHER)
|
42
|
-
date = Date.parse(value) rescue nil
|
43
|
-
return date if date
|
19
|
+
TRANSFORMERS.each do |transformer|
|
20
|
+
success, transformed_value = transformer.transform?(value)
|
21
|
+
return transformed_value if success
|
44
22
|
end
|
45
23
|
end
|
46
24
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SafeYAML
|
2
|
+
class Transform
|
3
|
+
class ToBoolean
|
4
|
+
PREDEFINED_VALUES = {
|
5
|
+
"yes" => true,
|
6
|
+
"on" => true,
|
7
|
+
"true" => true,
|
8
|
+
"no" => false,
|
9
|
+
"off" => false,
|
10
|
+
"false" => false
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
def transform?(value)
|
14
|
+
key = value.downcase
|
15
|
+
return PREDEFINED_VALUES.include?(key), PREDEFINED_VALUES[key]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SafeYAML
|
2
|
+
class Transform
|
3
|
+
class ToNil
|
4
|
+
PREDEFINED_VALUES = {
|
5
|
+
"" => nil,
|
6
|
+
"~" => nil,
|
7
|
+
"null" => nil,
|
8
|
+
}.freeze
|
9
|
+
|
10
|
+
def transform?(value)
|
11
|
+
key = value.downcase
|
12
|
+
return PREDEFINED_VALUES.include?(key), PREDEFINED_VALUES[key]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SafeYAML
|
2
|
+
class Transform
|
3
|
+
class ToTime
|
4
|
+
# There isn't a missing '$' there; YAML itself seems to ignore everything at the end of a
|
5
|
+
# string that otherwise resembles a time.
|
6
|
+
MATCHER = /^\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d{1,5})?/.freeze
|
7
|
+
|
8
|
+
def transform?(value)
|
9
|
+
return false unless MATCHER.match(value)
|
10
|
+
datetime = DateTime.parse(value) rescue nil
|
11
|
+
return !!datetime, datetime.to_time
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/safe_yaml/version.rb
CHANGED
data/spec/safe_yaml_spec.rb
CHANGED
data/spec/shared_specs.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
2
|
|
3
|
-
require "safe_yaml/transform"
|
4
|
-
|
5
3
|
module SharedSpecs
|
6
4
|
def self.included(base)
|
7
5
|
base.instance_eval do
|
@@ -53,6 +51,11 @@ module SharedSpecs
|
|
53
51
|
result.should == { "date" => Date.parse("2013-01-24") }
|
54
52
|
end
|
55
53
|
|
54
|
+
it "translates valid time values" do
|
55
|
+
parse "time: 2013-01-29 05:58:00 -0800"
|
56
|
+
result.should == { "time" => Time.new(2013, 1, 29, 5, 58, 0, "-08:00") }
|
57
|
+
end
|
58
|
+
|
56
59
|
it "translates valid true/false values to booleans" do
|
57
60
|
parse <<-YAML
|
58
61
|
- yes
|
@@ -74,6 +77,30 @@ module SharedSpecs
|
|
74
77
|
result.should == [nil] * 3
|
75
78
|
end
|
76
79
|
|
80
|
+
it "deals just fine with nested maps" do
|
81
|
+
parse <<-YAML
|
82
|
+
foo:
|
83
|
+
bar:
|
84
|
+
marco: polo
|
85
|
+
YAML
|
86
|
+
|
87
|
+
result.should == { "foo" => { "bar" => { "marco" => "polo" } } }
|
88
|
+
end
|
89
|
+
|
90
|
+
it "deals just fine with nested sequences" do
|
91
|
+
parse <<-YAML
|
92
|
+
- foo
|
93
|
+
-
|
94
|
+
- bar1
|
95
|
+
- bar2
|
96
|
+
-
|
97
|
+
- baz1
|
98
|
+
- baz2
|
99
|
+
YAML
|
100
|
+
|
101
|
+
result.should == ["foo", ["bar1", "bar2", ["baz1", "baz2"]]]
|
102
|
+
end
|
103
|
+
|
77
104
|
it "applies the same transformations to keys as to values" do
|
78
105
|
parse <<-YAML
|
79
106
|
foo: string
|
@@ -81,6 +108,7 @@ module SharedSpecs
|
|
81
108
|
1: integer
|
82
109
|
3.14: float
|
83
110
|
2013-01-24: date
|
111
|
+
2013-01-29 05:58:00 -0800: time
|
84
112
|
YAML
|
85
113
|
|
86
114
|
result.should == {
|
@@ -88,7 +116,8 @@ module SharedSpecs
|
|
88
116
|
":bar" => "symbol",
|
89
117
|
1 => "integer",
|
90
118
|
3.14 => "float",
|
91
|
-
Date.parse("2013-01-24") => "date"
|
119
|
+
Date.parse("2013-01-24") => "date",
|
120
|
+
Time.new(2013, 1, 29, 5, 58, 0, "-08:00") => "time"
|
92
121
|
}
|
93
122
|
end
|
94
123
|
|
@@ -99,33 +128,10 @@ module SharedSpecs
|
|
99
128
|
- 1
|
100
129
|
- 3.14
|
101
130
|
- 2013-01-24
|
131
|
+
- 2013-01-29 05:58:00 -0800
|
102
132
|
YAML
|
103
133
|
|
104
|
-
result.should == ["foo", ":bar", 1, 3.14, Date.parse("2013-01-24")]
|
105
|
-
end
|
106
|
-
|
107
|
-
it "deals just fine with nested maps" do
|
108
|
-
parse <<-YAML
|
109
|
-
foo:
|
110
|
-
bar:
|
111
|
-
marco: polo
|
112
|
-
YAML
|
113
|
-
|
114
|
-
result.should == { "foo" => { "bar" => { "marco" => "polo" } } }
|
115
|
-
end
|
116
|
-
|
117
|
-
it "deals just fine with nested sequences" do
|
118
|
-
parse <<-YAML
|
119
|
-
- foo
|
120
|
-
-
|
121
|
-
- bar1
|
122
|
-
- bar2
|
123
|
-
-
|
124
|
-
- baz1
|
125
|
-
- baz2
|
126
|
-
YAML
|
127
|
-
|
128
|
-
result.should == ["foo", ["bar1", "bar2", ["baz1", "baz2"]]]
|
134
|
+
result.should == ["foo", ":bar", 1, 3.14, Date.parse("2013-01-24"), Time.new(2013, 1, 29, 5, 58, 0, "-08:00")]
|
129
135
|
end
|
130
136
|
end
|
131
137
|
|
@@ -146,6 +152,7 @@ module SharedSpecs
|
|
146
152
|
1: integer
|
147
153
|
3.14: float
|
148
154
|
2013-01-24: date
|
155
|
+
2013-01-29 05:58:00 -0800: time
|
149
156
|
YAML
|
150
157
|
|
151
158
|
result.should == {
|
@@ -153,7 +160,8 @@ module SharedSpecs
|
|
153
160
|
:bar => "symbol",
|
154
161
|
1 => "integer",
|
155
162
|
3.14 => "float",
|
156
|
-
Date.parse("2013-01-24") => "date"
|
163
|
+
Date.parse("2013-01-24") => "date",
|
164
|
+
Time.new(2013, 1, 29, 5, 58, 0, "-08:00") => "time"
|
157
165
|
}
|
158
166
|
end
|
159
167
|
|
@@ -164,9 +172,10 @@ module SharedSpecs
|
|
164
172
|
- 1
|
165
173
|
- 3.14
|
166
174
|
- 2013-01-24
|
175
|
+
- 2013-01-29 05:58:00 -0800
|
167
176
|
YAML
|
168
177
|
|
169
|
-
result.should == ["foo", :bar, 1, 3.14, Date.parse("2013-01-24")]
|
178
|
+
result.should == ["foo", :bar, 1, 3.14, Date.parse("2013-01-24"), Time.new(2013, 1, 29, 5, 58, 0, "-08:00")]
|
170
179
|
end
|
171
180
|
end
|
172
181
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: safe_yaml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.5.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-29 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Parse YAML safely, without that pesky arbitrary code execution vulnerability
|
15
15
|
email: daniel.tao@gmail.com
|
@@ -26,6 +26,13 @@ files:
|
|
26
26
|
- lib/safe_yaml/psych_handler.rb
|
27
27
|
- lib/safe_yaml/syck_resolver.rb
|
28
28
|
- lib/safe_yaml/transform.rb
|
29
|
+
- lib/safe_yaml/transform/to_boolean.rb
|
30
|
+
- lib/safe_yaml/transform/to_date.rb
|
31
|
+
- lib/safe_yaml/transform/to_float.rb
|
32
|
+
- lib/safe_yaml/transform/to_integer.rb
|
33
|
+
- lib/safe_yaml/transform/to_nil.rb
|
34
|
+
- lib/safe_yaml/transform/to_symbol.rb
|
35
|
+
- lib/safe_yaml/transform/to_time.rb
|
29
36
|
- lib/safe_yaml/version.rb
|
30
37
|
- run_specs_all_ruby_versions.sh
|
31
38
|
- safe_yaml.gemspec
|