safe_yaml 0.5 → 0.5.1
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.
- 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
|