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 CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- safe_yaml (0.4)
4
+ safe_yaml (0.5.1)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
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 `YAML.safe_load`, that attacker would be thwarted:
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
 
@@ -4,43 +4,21 @@ module SafeYAML
4
4
  :enable_symbol_parsing => false
5
5
  }
6
6
 
7
- PREDEFINED_VALUES = {
8
- "" => nil,
9
- "~" => nil,
10
- "null" => nil,
11
- "yes" => true,
12
- "on" => true,
13
- "true" => true,
14
- "no" => false,
15
- "off" => false,
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
- if PREDEFINED_VALUES.include?(value.downcase)
30
- return PREDEFINED_VALUES[value.downcase]
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,13 @@
1
+ module SafeYAML
2
+ class Transform
3
+ class ToDate
4
+ MATCHER = /^\d{4}\-\d{2}\-\d{2}$/.freeze
5
+
6
+ def transform?(value)
7
+ return false unless MATCHER.match(value)
8
+ date = Date.parse(value) rescue nil
9
+ return !!date, date
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module SafeYAML
2
+ class Transform
3
+ class ToFloat
4
+ MATCHER = /^(?:\d+(?:\.\d*)?$)|(?:^\.\d+$)/.freeze
5
+
6
+ def transform?(value)
7
+ return false unless MATCHER.match(value)
8
+ return true, value.to_f
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module SafeYAML
2
+ class Transform
3
+ class ToInteger
4
+ MATCHER = /^\d+$/.freeze
5
+
6
+ def transform?(value)
7
+ return false unless MATCHER.match(value)
8
+ return true, value.to_i
9
+ end
10
+ end
11
+ end
12
+ 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,12 @@
1
+ module SafeYAML
2
+ class Transform
3
+ class ToSymbol
4
+ MATCHER = /^:\w+$/.freeze
5
+
6
+ def transform?(value)
7
+ return false if !Transform::OPTIONS[:enable_symbol_parsing] || !MATCHER.match(value)
8
+ return true, value[1..-1].to_sym
9
+ end
10
+ end
11
+ end
12
+ 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
@@ -1,3 +1,3 @@
1
1
  module SafeYAML
2
- VERSION = "0.5"
2
+ VERSION = "0.5.1"
3
3
  end
@@ -1,6 +1,5 @@
1
1
  require File.join(File.dirname(__FILE__), "spec_helper")
2
2
 
3
- require "safe_yaml"
4
3
  require "exploitable_back_door"
5
4
 
6
5
  describe YAML do
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
@@ -4,6 +4,7 @@ ROOT = File.join(HERE, "..")
4
4
  $LOAD_PATH << File.join(ROOT, "lib")
5
5
  $LOAD_PATH << File.join(HERE, "support")
6
6
 
7
+ require "safe_yaml"
7
8
  require "heredoc_unindent"
8
9
 
9
10
  require File.join(HERE, "shared_specs")
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: '0.5'
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-24 00:00:00.000000000 Z
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