safe_yaml 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ dist/
data/lib/safe_yaml.rb CHANGED
@@ -1,5 +1,5 @@
1
- require "yaml"
2
- require "handler"
1
+ require "safe_yaml/handler"
2
+ require "safe_yaml/version"
3
3
 
4
4
  module YAML
5
5
  def self.safe_load(yaml)
@@ -2,7 +2,20 @@ require "yaml"
2
2
 
3
3
  module SafeYAML
4
4
  class Handler < Psych::Handler
5
+ PREDEFINED_VALUES = {
6
+ "" => nil,
7
+ "~" => nil,
8
+ "null" => nil,
9
+ "yes" => true,
10
+ "on" => true,
11
+ "true" => true,
12
+ "no" => false,
13
+ "off" => false,
14
+ "false" => false
15
+ }.freeze
16
+
5
17
  def initialize
18
+ @anchors = {}
6
19
  @stack = []
7
20
  end
8
21
 
@@ -10,7 +23,11 @@ module SafeYAML
10
23
  @result
11
24
  end
12
25
 
13
- def add_to_current_structure(value)
26
+ def add_to_current_structure(value, anchor=nil)
27
+ value = transform_value(value)
28
+
29
+ @anchors[anchor] = value if anchor
30
+
14
31
  if @result.nil?
15
32
  @result = value
16
33
  @current_structure = @result
@@ -19,13 +36,19 @@ module SafeYAML
19
36
 
20
37
  case @current_structure
21
38
  when Array
22
- @current_structure.push(transform_value(value))
39
+ @current_structure.push(value)
23
40
 
24
41
  when Hash
25
42
  if @current_key.nil?
26
- @current_key = transform_value(value)
43
+ @current_key = value
44
+
27
45
  else
28
- @current_structure[@current_key] = transform_value(value)
46
+ if @current_key == "<<"
47
+ @current_structure.merge!(value)
48
+ else
49
+ @current_structure[@current_key] = value
50
+ end
51
+
29
52
  @current_key = nil
30
53
  end
31
54
 
@@ -36,7 +59,10 @@ module SafeYAML
36
59
 
37
60
  def transform_value(value)
38
61
  if value.is_a?(String)
39
- if value.match(/^:\w+$/)
62
+ if PREDEFINED_VALUES.include?(value.downcase)
63
+ return PREDEFINED_VALUES[value.downcase]
64
+
65
+ elsif value.match(/^:\w+$/)
40
66
  return value[1..-1].to_sym
41
67
 
42
68
  elsif value.match(/^\d+$/)
@@ -50,37 +76,44 @@ module SafeYAML
50
76
  value
51
77
  end
52
78
 
79
+ def end_current_structure
80
+ @stack.pop
81
+ @current_structure = @stack.last
82
+ end
83
+
53
84
  def streaming?
54
85
  false
55
86
  end
56
87
 
57
88
  # event handlers
89
+ def alias(anchor)
90
+ add_to_current_structure(@anchors[anchor])
91
+ end
92
+
58
93
  def scalar(value, anchor, tag, plain, quoted, style)
59
- add_to_current_structure(value)
94
+ add_to_current_structure(value, anchor)
60
95
  end
61
96
 
62
- def start_mapping(*args) # anchor, tag, implicit, style
97
+ def start_mapping(anchor, tag, implicit, style)
63
98
  map = {}
64
- self.add_to_current_structure(map)
99
+ self.add_to_current_structure(map, anchor)
65
100
  @current_structure = map
66
101
  @stack.push(map)
67
102
  end
68
103
 
69
104
  def end_mapping
70
- @stack.pop
71
- @current_structure = @stack.last
105
+ self.end_current_structure()
72
106
  end
73
107
 
74
- def start_sequence(*args) # anchor, tag, implicit, style
108
+ def start_sequence(anchor, tag, implicit, style)
75
109
  seq = []
76
- self.add_to_current_structure(seq)
110
+ self.add_to_current_structure(seq, anchor)
77
111
  @current_structure = seq
78
112
  @stack.push(seq)
79
113
  end
80
114
 
81
115
  def end_sequence
82
- @stack.pop
83
- @current_structure = @stack.last
116
+ self.end_current_structure()
84
117
  end
85
118
  end
86
119
  end
@@ -1,3 +1,3 @@
1
1
  module SafeYAML
2
- VERSION = "0.1"
2
+ VERSION = "0.2"
3
3
  end
data/safe_yaml.gemspec CHANGED
@@ -1,10 +1,11 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require File.expand_path("../lib/version", __FILE__)
2
+ require File.join(File.dirname(__FILE__), "lib", "safe_yaml", "version")
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.name = "safe_yaml"
6
- gem.authors = ["Dan Tao"]
7
- gem.email = ["daniel.tao@gmail.com"]
6
+ gem.version = SafeYAML::VERSION
7
+ gem.authors = "Dan Tao"
8
+ gem.email = "daniel.tao@gmail.com"
8
9
  gem.description = %q{Parse (simple) YAML safely, without that pesky arbitrary code execution vulnerability.}
9
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).}
10
11
  gem.homepage = "http://dtao.github.com/safe_yaml/"
@@ -12,5 +13,6 @@ Gem::Specification.new do |gem|
12
13
  gem.files = `git ls-files`.split($\)
13
14
  gem.test_files = gem.files.grep(%r{^spec/})
14
15
  gem.require_paths = ["lib"]
15
- gem.version = SafeYAML::VERSION
16
+
17
+ gem.add_dependency("psych")
16
18
  end
data/spec/handler_spec.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(__FILE__), "spec_helper")
2
2
 
3
- require "handler"
3
+ require "safe_yaml/handler"
4
4
 
5
5
  describe SafeYAML::Handler do
6
6
  let(:handler) { SafeYAML::Handler.new }
@@ -31,6 +31,27 @@ describe SafeYAML::Handler do
31
31
  result.should == { "float" => 3.14 }
32
32
  end
33
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
+
34
55
  it "applies the same transformations to values as to keys" do
35
56
  parse <<-YAML
36
57
  string: value
@@ -105,4 +126,47 @@ describe SafeYAML::Handler do
105
126
 
106
127
  result.should == { "foo" => { "bar" => { "marco" => "polo" } } }
107
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
108
172
  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.1'
4
+ version: '0.2'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,21 +10,37 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
  date: 2013-01-17 00:00:00.000000000 Z
13
- dependencies: []
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: psych
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  description: Parse (simple) YAML safely, without that pesky arbitrary code execution
15
31
  vulnerability.
16
- email:
17
- - daniel.tao@gmail.com
32
+ email: daniel.tao@gmail.com
18
33
  executables: []
19
34
  extensions: []
20
35
  extra_rdoc_files: []
21
36
  files:
37
+ - .gitignore
22
38
  - Gemfile
23
39
  - Gemfile.lock
24
40
  - Rakefile
25
- - lib/handler.rb
26
41
  - lib/safe_yaml.rb
27
- - lib/version.rb
42
+ - lib/safe_yaml/handler.rb
43
+ - lib/safe_yaml/version.rb
28
44
  - safe_yaml.gemspec
29
45
  - spec/handler_spec.rb
30
46
  - spec/safe_yaml_spec.rb