safe_yaml 0.2.2 → 0.3
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 +1 -0
- data/Gemfile.lock +9 -1
- data/README.md +2 -2
- data/lib/safe_yaml/{handler.rb → psych_handler.rb} +2 -34
- data/lib/safe_yaml/syck_resolver.rb +49 -0
- data/lib/safe_yaml/transform.rb +34 -0
- data/lib/safe_yaml/version.rb +1 -1
- data/lib/safe_yaml.rb +17 -5
- data/safe_yaml.gemspec +3 -3
- data/spec/psych_handler_spec.rb +17 -0
- data/spec/safe_yaml_spec.rb +62 -16
- data/spec/shared_specs.rb +125 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/exploitable_back_door.rb +13 -7
- data/spec/syck_resolver_spec.rb +17 -0
- metadata +14 -9
- data/spec/handler_spec.rb +0 -172
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,13 +1,19 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
safe_yaml (0.
|
4
|
+
safe_yaml (0.2.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: http://rubygems.org/
|
8
8
|
specs:
|
9
|
+
coderay (1.0.8)
|
9
10
|
diff-lcs (1.1.3)
|
10
11
|
heredoc_unindent (1.1.2)
|
12
|
+
method_source (0.8.1)
|
13
|
+
pry (0.9.11.2)
|
14
|
+
coderay (~> 1.0.5)
|
15
|
+
method_source (~> 0.8)
|
16
|
+
slop (~> 3.4)
|
11
17
|
rake (10.0.3)
|
12
18
|
rspec (2.12.0)
|
13
19
|
rspec-core (~> 2.12.0)
|
@@ -17,12 +23,14 @@ GEM
|
|
17
23
|
rspec-expectations (2.12.1)
|
18
24
|
diff-lcs (~> 1.1.3)
|
19
25
|
rspec-mocks (2.12.1)
|
26
|
+
slop (3.4.3)
|
20
27
|
|
21
28
|
PLATFORMS
|
22
29
|
ruby
|
23
30
|
|
24
31
|
DEPENDENCIES
|
25
32
|
heredoc_unindent
|
33
|
+
pry
|
26
34
|
rake
|
27
35
|
rspec
|
28
36
|
safe_yaml!
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
SafeYAML
|
2
2
|
========
|
3
3
|
|
4
|
-
*Parse
|
4
|
+
*Parse YAML safely, without that pesky arbitrary code execution vulnerability.*
|
5
5
|
|
6
6
|
***
|
7
7
|
|
@@ -38,4 +38,4 @@ With `YAML.safe_load`, that attacker would be thwarted:
|
|
38
38
|
> YAML.safe_load(yaml)
|
39
39
|
=> {"foo; end; puts %(I'm in yr system!); def bar"=>"baz"}
|
40
40
|
|
41
|
-
SafeYAML requires Ruby 1.
|
41
|
+
SafeYAML requires Ruby 1.8.7 or newer and works with both [Syck](http://www.ruby-doc.org/stdlib-1.8.7/libdoc/yaml/rdoc/YAML.html) and [Psych](http://github.com/tenderlove/psych).
|
@@ -1,20 +1,7 @@
|
|
1
1
|
require "psych"
|
2
|
-
require "yaml"
|
3
2
|
|
4
3
|
module SafeYAML
|
5
|
-
class
|
6
|
-
PREDEFINED_VALUES = {
|
7
|
-
"" => nil,
|
8
|
-
"~" => nil,
|
9
|
-
"null" => nil,
|
10
|
-
"yes" => true,
|
11
|
-
"on" => true,
|
12
|
-
"true" => true,
|
13
|
-
"no" => false,
|
14
|
-
"off" => false,
|
15
|
-
"false" => false
|
16
|
-
}.freeze
|
17
|
-
|
4
|
+
class PsychHandler < Psych::Handler
|
18
5
|
def initialize
|
19
6
|
@anchors = {}
|
20
7
|
@stack = []
|
@@ -25,7 +12,7 @@ module SafeYAML
|
|
25
12
|
end
|
26
13
|
|
27
14
|
def add_to_current_structure(value, anchor=nil)
|
28
|
-
value =
|
15
|
+
value = Transform.to_proper_type(value)
|
29
16
|
|
30
17
|
@anchors[anchor] = value if anchor
|
31
18
|
|
@@ -58,25 +45,6 @@ module SafeYAML
|
|
58
45
|
end
|
59
46
|
end
|
60
47
|
|
61
|
-
def transform_value(value)
|
62
|
-
if value.is_a?(String)
|
63
|
-
if PREDEFINED_VALUES.include?(value.downcase)
|
64
|
-
return PREDEFINED_VALUES[value.downcase]
|
65
|
-
|
66
|
-
elsif value.match(/^:\w+$/)
|
67
|
-
return value[1..-1].to_sym
|
68
|
-
|
69
|
-
elsif value.match(/^\d+$/)
|
70
|
-
return value.to_i
|
71
|
-
|
72
|
-
elsif value.match(/^\d+(?:\.\d*)?$/) || value.match(/^\.\d+$/)
|
73
|
-
return value.to_f
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
value
|
78
|
-
end
|
79
|
-
|
80
48
|
def end_current_structure
|
81
49
|
@stack.pop
|
82
50
|
@current_structure = @stack.last
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module SafeYAML
|
2
|
+
class SyckResolver
|
3
|
+
def initialize
|
4
|
+
@anchors = {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def resolve_tree(tree)
|
8
|
+
case tree.kind
|
9
|
+
when :map
|
10
|
+
return resolve_map(tree.value)
|
11
|
+
when :seq
|
12
|
+
return resolve_seq(tree.value)
|
13
|
+
else
|
14
|
+
raise "Don't know how to resolve a #{tree.kind} tree!"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def resolve_node(node)
|
19
|
+
case node.kind
|
20
|
+
when :map
|
21
|
+
return resolve_map(node.value)
|
22
|
+
when :seq
|
23
|
+
return resolve_seq(node.value)
|
24
|
+
when :scalar
|
25
|
+
return resolve_scalar(node.value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def resolve_map(map)
|
30
|
+
hash = {}
|
31
|
+
map.each do |key_node, value_node|
|
32
|
+
if resolve_node(key_node) == "<<"
|
33
|
+
hash.merge!(resolve_node(value_node))
|
34
|
+
else
|
35
|
+
hash[resolve_node(key_node)] = resolve_node(value_node)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
return hash
|
39
|
+
end
|
40
|
+
|
41
|
+
def resolve_seq(seq)
|
42
|
+
seq.map { |node| resolve_node(node) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def resolve_scalar(scalar)
|
46
|
+
Transform.to_proper_type(scalar)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module SafeYAML
|
2
|
+
class Transform
|
3
|
+
PREDEFINED_VALUES = {
|
4
|
+
"" => nil,
|
5
|
+
"~" => nil,
|
6
|
+
"null" => nil,
|
7
|
+
"yes" => true,
|
8
|
+
"on" => true,
|
9
|
+
"true" => true,
|
10
|
+
"no" => false,
|
11
|
+
"off" => false,
|
12
|
+
"false" => false
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
def self.to_proper_type(value)
|
16
|
+
if value.is_a?(String)
|
17
|
+
if PREDEFINED_VALUES.include?(value.downcase)
|
18
|
+
return PREDEFINED_VALUES[value.downcase]
|
19
|
+
|
20
|
+
elsif value.match(/^:\w+$/)
|
21
|
+
return value[1..-1].to_sym
|
22
|
+
|
23
|
+
elsif value.match(/^\d+$/)
|
24
|
+
return value.to_i
|
25
|
+
|
26
|
+
elsif value.match(/^\d+(?:\.\d*)?$/) || value.match(/^\.\d+$/)
|
27
|
+
return value.to_f
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/safe_yaml/version.rb
CHANGED
data/lib/safe_yaml.rb
CHANGED
@@ -1,10 +1,22 @@
|
|
1
|
-
require "
|
1
|
+
require "yaml"
|
2
|
+
require "safe_yaml/transform"
|
2
3
|
require "safe_yaml/version"
|
3
4
|
|
4
5
|
module YAML
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
if RUBY_VERSION >= "1.9.2"
|
7
|
+
require "safe_yaml/psych_handler"
|
8
|
+
def self.safe_load(yaml)
|
9
|
+
safe_handler = SafeYAML::PsychHandler.new
|
10
|
+
Psych::Parser.new(safe_handler).parse(yaml)
|
11
|
+
return safe_handler.result
|
12
|
+
end
|
13
|
+
|
14
|
+
else
|
15
|
+
require "safe_yaml/syck_resolver"
|
16
|
+
def self.safe_load(yaml)
|
17
|
+
safe_resolver = SafeYAML::SyckResolver.new
|
18
|
+
tree = YAML.parse(yaml)
|
19
|
+
return safe_resolver.resolve_tree(tree)
|
20
|
+
end
|
9
21
|
end
|
10
22
|
end
|
data/safe_yaml.gemspec
CHANGED
@@ -6,13 +6,13 @@ Gem::Specification.new do |gem|
|
|
6
6
|
gem.version = SafeYAML::VERSION
|
7
7
|
gem.authors = "Dan Tao"
|
8
8
|
gem.email = "daniel.tao@gmail.com"
|
9
|
-
gem.description = %q{Parse
|
9
|
+
gem.description = %q{Parse YAML safely, without that pesky arbitrary code execution vulnerability.}
|
10
10
|
gem.summary = %q{SameYAML adds a ::safe_load method to Ruby's built-in YAML module to parse YAML data for only basic types (strings, symbols, numbers, arrays, and hashes).}
|
11
|
-
gem.homepage = "http://
|
11
|
+
gem.homepage = "http://github.com/dtao/safe_yaml"
|
12
12
|
|
13
13
|
gem.files = `git ls-files`.split($\)
|
14
14
|
gem.test_files = gem.files.grep(%r{^spec/})
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
|
17
|
-
gem.required_ruby_version = ">= 1.
|
17
|
+
gem.required_ruby_version = ">= 1.8.7"
|
18
18
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
if RUBY_VERSION >= "1.9.2"
|
4
|
+
require "safe_yaml/psych_handler"
|
5
|
+
|
6
|
+
describe SafeYAML::PsychHandler do
|
7
|
+
let(:handler) { SafeYAML::PsychHandler.new }
|
8
|
+
let(:parser) { Psych::Parser.new(handler) }
|
9
|
+
let(:result) { handler.result }
|
10
|
+
|
11
|
+
def parse(yaml)
|
12
|
+
parser.parse(yaml.unindent)
|
13
|
+
end
|
14
|
+
|
15
|
+
include SharedSpecs
|
16
|
+
end
|
17
|
+
end
|
data/spec/safe_yaml_spec.rb
CHANGED
@@ -4,33 +4,36 @@ require "safe_yaml"
|
|
4
4
|
require "exploitable_back_door"
|
5
5
|
|
6
6
|
describe YAML do
|
7
|
-
before :each do
|
8
|
-
ExploitableBackDoor.reset
|
9
|
-
end
|
10
|
-
|
11
7
|
describe "load" do
|
12
8
|
if RUBY_VERSION >= "1.9.3"
|
13
|
-
it "allows exploits through objects defined in YAML w/ !ruby/hash" do
|
14
|
-
YAML.load
|
15
|
-
|
9
|
+
it "allows exploits through objects defined in YAML w/ !ruby/hash through custom :[]= methods" do
|
10
|
+
backdoor = YAML.load("--- !ruby/hash:ExploitableBackDoor\nfoo: bar\n")
|
11
|
+
backdoor.should be_exploited_through_setter
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
if RUBY_VERSION >= "1.9.2"
|
16
|
+
it "allows exploits through objects defined in YAML w/ !ruby/object through" do
|
17
|
+
backdoor = YAML.load("--- !ruby/object:ExploitableBackDoor\nfoo: bar\n")
|
18
|
+
backdoor.should be_exploited_through_init_with
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
19
|
-
it "allows exploits through objects defined in YAML w/ !ruby/object" do
|
20
|
-
YAML.load
|
21
|
-
|
22
|
+
it "allows exploits through objects w/ sensitive instance variables defined in YAML w/ !ruby/object" do
|
23
|
+
backdoor = YAML.load("--- !ruby/object:ExploitableBackDoor\nfoo: bar\n")
|
24
|
+
backdoor.should be_exploited_through_ivars
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
25
28
|
describe "safe_load" do
|
26
|
-
it "does NOT allow exploits through objects defined in YAML w/ !ruby/
|
27
|
-
YAML.safe_load
|
28
|
-
|
29
|
+
it "does NOT allow exploits through objects defined in YAML w/ !ruby/hash" do
|
30
|
+
object = YAML.safe_load("--- !ruby/hash:ExploitableBackDoor\nfoo: bar\n")
|
31
|
+
object.should_not be_a(ExploitableBackDoor)
|
29
32
|
end
|
30
33
|
|
31
|
-
it "does NOT allow exploits through objects defined in YAML w/ !ruby/
|
32
|
-
YAML.safe_load
|
33
|
-
|
34
|
+
it "does NOT allow exploits through objects defined in YAML w/ !ruby/object" do
|
35
|
+
object = YAML.safe_load("--- !ruby/object:ExploitableBackDoor\nfoo: bar\n")
|
36
|
+
object.should_not be_a(ExploitableBackDoor)
|
34
37
|
end
|
35
38
|
|
36
39
|
it "loads a plain ol' YAML document just fine" do
|
@@ -53,5 +56,48 @@ describe YAML do
|
|
53
56
|
}
|
54
57
|
}
|
55
58
|
end
|
59
|
+
|
60
|
+
it "works for YAML documents with anchors and aliases" do
|
61
|
+
result = YAML.safe_load <<-YAML
|
62
|
+
- &id001 {}
|
63
|
+
- *id001
|
64
|
+
- *id001
|
65
|
+
YAML
|
66
|
+
|
67
|
+
result.should == [{}, {}, {}]
|
68
|
+
end
|
69
|
+
|
70
|
+
it "works for YAML documents with sections" do
|
71
|
+
result = YAML.safe_load <<-YAML
|
72
|
+
mysql: &foo
|
73
|
+
adapter: mysql
|
74
|
+
pool: 30
|
75
|
+
login: &login
|
76
|
+
username: dan
|
77
|
+
password: gobbledygook
|
78
|
+
local: &local
|
79
|
+
<<: *foo
|
80
|
+
<<: *login
|
81
|
+
host: localhost
|
82
|
+
YAML
|
83
|
+
|
84
|
+
result.should == {
|
85
|
+
"mysql" => {
|
86
|
+
"adapter" => "mysql",
|
87
|
+
"pool" => 30
|
88
|
+
},
|
89
|
+
"login" => {
|
90
|
+
"username" => "dan",
|
91
|
+
"password" => "gobbledygook"
|
92
|
+
},
|
93
|
+
"local" => {
|
94
|
+
"adapter" => "mysql",
|
95
|
+
"pool" => 30,
|
96
|
+
"username" => "dan",
|
97
|
+
"password" => "gobbledygook",
|
98
|
+
"host" => "localhost"
|
99
|
+
}
|
100
|
+
}
|
101
|
+
end
|
56
102
|
end
|
57
103
|
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
require "safe_yaml/transform"
|
4
|
+
|
5
|
+
module SharedSpecs
|
6
|
+
def self.included(base)
|
7
|
+
base.instance_eval do
|
8
|
+
it "translates most values to strings" do
|
9
|
+
parse "key: value"
|
10
|
+
result.should == { "key" => "value" }
|
11
|
+
end
|
12
|
+
|
13
|
+
it "translates values starting with ':' to symbols" do
|
14
|
+
parse ":key: value"
|
15
|
+
result.should == { :key => "value" }
|
16
|
+
end
|
17
|
+
|
18
|
+
it "translates valid integral numbers to integers" do
|
19
|
+
parse "integer: 1"
|
20
|
+
result.should == { "integer" => 1 }
|
21
|
+
end
|
22
|
+
|
23
|
+
it "translates valid decimal numbers to floats" do
|
24
|
+
parse "float: 3.14"
|
25
|
+
result.should == { "float" => 3.14 }
|
26
|
+
end
|
27
|
+
|
28
|
+
it "translates valid true/false values to booleans" do
|
29
|
+
parse <<-YAML
|
30
|
+
- yes
|
31
|
+
- true
|
32
|
+
- no
|
33
|
+
- false
|
34
|
+
YAML
|
35
|
+
|
36
|
+
result.should == [true, true, false, false]
|
37
|
+
end
|
38
|
+
|
39
|
+
it "translates valid nulls to nil" do
|
40
|
+
parse <<-YAML
|
41
|
+
-
|
42
|
+
- ~
|
43
|
+
- null
|
44
|
+
YAML
|
45
|
+
|
46
|
+
result.should == [nil] * 3
|
47
|
+
end
|
48
|
+
|
49
|
+
it "applies the same transformations to values as to keys" do
|
50
|
+
parse <<-YAML
|
51
|
+
string: value
|
52
|
+
symbol: :value
|
53
|
+
integer: 1
|
54
|
+
float: 3.14
|
55
|
+
YAML
|
56
|
+
|
57
|
+
result.should == {
|
58
|
+
"string" => "value",
|
59
|
+
"symbol" => :value,
|
60
|
+
"integer" => 1,
|
61
|
+
"float" => 3.14
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
it "translates sequences to arrays" do
|
66
|
+
parse <<-YAML
|
67
|
+
- foo
|
68
|
+
- bar
|
69
|
+
- baz
|
70
|
+
YAML
|
71
|
+
|
72
|
+
result.should == ["foo", "bar", "baz"]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "applies the same transformations to elements in sequences as to all values" do
|
76
|
+
parse <<-YAML
|
77
|
+
- string
|
78
|
+
- :symbol
|
79
|
+
- 1
|
80
|
+
- 3.14
|
81
|
+
YAML
|
82
|
+
|
83
|
+
result.should == ["string", :symbol, 1, 3.14]
|
84
|
+
end
|
85
|
+
|
86
|
+
it "translates maps to hashes" do
|
87
|
+
parse <<-YAML
|
88
|
+
foo: blah
|
89
|
+
bar: glah
|
90
|
+
baz: flah
|
91
|
+
YAML
|
92
|
+
|
93
|
+
result.should == {
|
94
|
+
"foo" => "blah",
|
95
|
+
"bar" => "glah",
|
96
|
+
"baz" => "flah"
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
it "applies the same transformations to values in hashes as to all values" do
|
101
|
+
parse <<-YAML
|
102
|
+
foo: :symbol
|
103
|
+
bar: 1
|
104
|
+
baz: 3.14
|
105
|
+
YAML
|
106
|
+
|
107
|
+
result.should == {
|
108
|
+
"foo" => :symbol,
|
109
|
+
"bar" => 1,
|
110
|
+
"baz" => 3.14
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
it "deals just fine with nested maps" do
|
115
|
+
parse <<-YAML
|
116
|
+
foo:
|
117
|
+
bar:
|
118
|
+
marco: polo
|
119
|
+
YAML
|
120
|
+
|
121
|
+
result.should == { "foo" => { "bar" => { "marco" => "polo" } } }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,23 +1,29 @@
|
|
1
1
|
class ExploitableBackDoor
|
2
|
-
|
2
|
+
def exploited?
|
3
|
+
@exploited_through_setter || @exploited_through_init_with || @exploited_through_ivars
|
4
|
+
end
|
5
|
+
|
6
|
+
def exploited_through_setter?
|
7
|
+
@exploited_through_setter
|
8
|
+
end
|
3
9
|
|
4
|
-
def
|
5
|
-
|
10
|
+
def exploited_through_init_with?
|
11
|
+
@exploited_through_init_with
|
6
12
|
end
|
7
13
|
|
8
|
-
def
|
9
|
-
|
14
|
+
def exploited_through_ivars?
|
15
|
+
self.instance_variables.any?
|
10
16
|
end
|
11
17
|
|
12
18
|
def init_with(command)
|
13
19
|
# Note: this is how bad this COULD be.
|
14
20
|
# system("#{command}")
|
15
|
-
|
21
|
+
@exploited_through_init_with = true
|
16
22
|
end
|
17
23
|
|
18
24
|
def []=(command, arguments)
|
19
25
|
# Note: this is how bad this COULD be.
|
20
26
|
# system("#{command} #{arguments}")
|
21
|
-
|
27
|
+
@exploited_through_setter = true
|
22
28
|
end
|
23
29
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
if RUBY_VERSION < "1.9.2"
|
4
|
+
require "safe_yaml/syck_resolver"
|
5
|
+
|
6
|
+
describe SafeYAML::SyckResolver do
|
7
|
+
let(:resolver) { SafeYAML::SyckResolver.new }
|
8
|
+
let(:result) { @result }
|
9
|
+
|
10
|
+
def parse(yaml)
|
11
|
+
tree = YAML.parse(yaml.unindent)
|
12
|
+
@result = resolver.resolve_tree(tree)
|
13
|
+
end
|
14
|
+
|
15
|
+
include SharedSpecs
|
16
|
+
end
|
17
|
+
end
|
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.
|
4
|
+
version: '0.3'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,10 +9,9 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-18 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
|
-
description: Parse
|
15
|
-
vulnerability.
|
14
|
+
description: Parse YAML safely, without that pesky arbitrary code execution vulnerability.
|
16
15
|
email: daniel.tao@gmail.com
|
17
16
|
executables: []
|
18
17
|
extensions: []
|
@@ -24,14 +23,18 @@ files:
|
|
24
23
|
- README.md
|
25
24
|
- Rakefile
|
26
25
|
- lib/safe_yaml.rb
|
27
|
-
- lib/safe_yaml/
|
26
|
+
- lib/safe_yaml/psych_handler.rb
|
27
|
+
- lib/safe_yaml/syck_resolver.rb
|
28
|
+
- lib/safe_yaml/transform.rb
|
28
29
|
- lib/safe_yaml/version.rb
|
29
30
|
- safe_yaml.gemspec
|
30
|
-
- spec/
|
31
|
+
- spec/psych_handler_spec.rb
|
31
32
|
- spec/safe_yaml_spec.rb
|
33
|
+
- spec/shared_specs.rb
|
32
34
|
- spec/spec_helper.rb
|
33
35
|
- spec/support/exploitable_back_door.rb
|
34
|
-
|
36
|
+
- spec/syck_resolver_spec.rb
|
37
|
+
homepage: http://github.com/dtao/safe_yaml
|
35
38
|
licenses: []
|
36
39
|
post_install_message:
|
37
40
|
rdoc_options: []
|
@@ -42,7 +45,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
42
45
|
requirements:
|
43
46
|
- - ! '>='
|
44
47
|
- !ruby/object:Gem::Version
|
45
|
-
version: 1.
|
48
|
+
version: 1.8.7
|
46
49
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
50
|
none: false
|
48
51
|
requirements:
|
@@ -57,7 +60,9 @@ specification_version: 3
|
|
57
60
|
summary: SameYAML adds a ::safe_load method to Ruby's built-in YAML module to parse
|
58
61
|
YAML data for only basic types (strings, symbols, numbers, arrays, and hashes).
|
59
62
|
test_files:
|
60
|
-
- spec/
|
63
|
+
- spec/psych_handler_spec.rb
|
61
64
|
- spec/safe_yaml_spec.rb
|
65
|
+
- spec/shared_specs.rb
|
62
66
|
- spec/spec_helper.rb
|
63
67
|
- spec/support/exploitable_back_door.rb
|
68
|
+
- spec/syck_resolver_spec.rb
|
data/spec/handler_spec.rb
DELETED
@@ -1,172 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
-
|
3
|
-
require "safe_yaml/handler"
|
4
|
-
|
5
|
-
describe SafeYAML::Handler do
|
6
|
-
let(:handler) { SafeYAML::Handler.new }
|
7
|
-
let(:parser) { Psych::Parser.new(handler) }
|
8
|
-
let(:result) { handler.result }
|
9
|
-
|
10
|
-
def parse(yaml)
|
11
|
-
parser.parse(yaml.unindent)
|
12
|
-
end
|
13
|
-
|
14
|
-
it "translates most values to strings" do
|
15
|
-
parser.parse "key: value"
|
16
|
-
result.should == { "key" => "value" }
|
17
|
-
end
|
18
|
-
|
19
|
-
it "translates values starting with ':' to symbols" do
|
20
|
-
parser.parse ":key: value"
|
21
|
-
result.should == { :key => "value" }
|
22
|
-
end
|
23
|
-
|
24
|
-
it "translates valid integral numbers to integers" do
|
25
|
-
parser.parse "integer: 1"
|
26
|
-
result.should == { "integer" => 1 }
|
27
|
-
end
|
28
|
-
|
29
|
-
it "translates valid decimal numbers to floats" do
|
30
|
-
parser.parse "float: 3.14"
|
31
|
-
result.should == { "float" => 3.14 }
|
32
|
-
end
|
33
|
-
|
34
|
-
it "translates valid true/false values to booleans" do
|
35
|
-
parser.parse <<-YAML
|
36
|
-
- yes
|
37
|
-
- true
|
38
|
-
- no
|
39
|
-
- false
|
40
|
-
YAML
|
41
|
-
|
42
|
-
result.should == [true, true, false, false]
|
43
|
-
end
|
44
|
-
|
45
|
-
it "translates valid nulls to nil" do
|
46
|
-
parser.parse <<-YAML
|
47
|
-
-
|
48
|
-
- ~
|
49
|
-
- null
|
50
|
-
YAML
|
51
|
-
|
52
|
-
result.should == [nil] * 3
|
53
|
-
end
|
54
|
-
|
55
|
-
it "applies the same transformations to values as to keys" do
|
56
|
-
parse <<-YAML
|
57
|
-
string: value
|
58
|
-
symbol: :value
|
59
|
-
integer: 1
|
60
|
-
float: 3.14
|
61
|
-
YAML
|
62
|
-
|
63
|
-
result.should == {
|
64
|
-
"string" => "value",
|
65
|
-
"symbol" => :value,
|
66
|
-
"integer" => 1,
|
67
|
-
"float" => 3.14
|
68
|
-
}
|
69
|
-
end
|
70
|
-
|
71
|
-
it "translates sequences to arrays" do
|
72
|
-
parse <<-YAML
|
73
|
-
- foo
|
74
|
-
- bar
|
75
|
-
- baz
|
76
|
-
YAML
|
77
|
-
|
78
|
-
result.should == ["foo", "bar", "baz"]
|
79
|
-
end
|
80
|
-
|
81
|
-
it "applies the same transformations to elements in sequences as to all values" do
|
82
|
-
parse <<-YAML
|
83
|
-
- string
|
84
|
-
- :symbol
|
85
|
-
- 1
|
86
|
-
- 3.14
|
87
|
-
YAML
|
88
|
-
|
89
|
-
result.should == ["string", :symbol, 1, 3.14]
|
90
|
-
end
|
91
|
-
|
92
|
-
it "translates maps to hashes" do
|
93
|
-
parse <<-YAML
|
94
|
-
foo: blah
|
95
|
-
bar: glah
|
96
|
-
baz: flah
|
97
|
-
YAML
|
98
|
-
|
99
|
-
result.should == {
|
100
|
-
"foo" => "blah",
|
101
|
-
"bar" => "glah",
|
102
|
-
"baz" => "flah"
|
103
|
-
}
|
104
|
-
end
|
105
|
-
|
106
|
-
it "applies the same transformations to values in hashes as to all values" do
|
107
|
-
parse <<-YAML
|
108
|
-
foo: :symbol
|
109
|
-
bar: 1
|
110
|
-
baz: 3.14
|
111
|
-
YAML
|
112
|
-
|
113
|
-
result.should == {
|
114
|
-
"foo" => :symbol,
|
115
|
-
"bar" => 1,
|
116
|
-
"baz" => 3.14
|
117
|
-
}
|
118
|
-
end
|
119
|
-
|
120
|
-
it "deals just fine with nested maps" do
|
121
|
-
parse <<-YAML
|
122
|
-
foo:
|
123
|
-
bar:
|
124
|
-
marco: polo
|
125
|
-
YAML
|
126
|
-
|
127
|
-
result.should == { "foo" => { "bar" => { "marco" => "polo" } } }
|
128
|
-
end
|
129
|
-
|
130
|
-
it "deals just fine with aliases and anchors" do
|
131
|
-
parse <<-YAML
|
132
|
-
- &id001 {}
|
133
|
-
- *id001
|
134
|
-
- *id001
|
135
|
-
YAML
|
136
|
-
|
137
|
-
result.should == [{}, {}, {}]
|
138
|
-
end
|
139
|
-
|
140
|
-
it "deals just fine with sections" do
|
141
|
-
parse <<-YAML
|
142
|
-
mysql: &mysql
|
143
|
-
adapter: mysql
|
144
|
-
pool: 30
|
145
|
-
login: &login
|
146
|
-
username: dan
|
147
|
-
password: gobbledygook
|
148
|
-
local: &local
|
149
|
-
<<: *mysql
|
150
|
-
<<: *login
|
151
|
-
host: localhost
|
152
|
-
YAML
|
153
|
-
|
154
|
-
result.should == {
|
155
|
-
"mysql" => {
|
156
|
-
"adapter" => "mysql",
|
157
|
-
"pool" => 30
|
158
|
-
},
|
159
|
-
"login" => {
|
160
|
-
"username" => "dan",
|
161
|
-
"password" => "gobbledygook"
|
162
|
-
},
|
163
|
-
"local" => {
|
164
|
-
"adapter" => "mysql",
|
165
|
-
"pool" => 30,
|
166
|
-
"username" => "dan",
|
167
|
-
"password" => "gobbledygook",
|
168
|
-
"host" => "localhost"
|
169
|
-
}
|
170
|
-
}
|
171
|
-
end
|
172
|
-
end
|