safe_yaml 1.0.1 → 1.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5a072651152f97592749563e45a793b71928ed80
4
- data.tar.gz: 0de35cc4fefc6f0f98d81c5ef1284382e47c8e3c
3
+ metadata.gz: 6cf9f3e405ec65c54f30eaec331423a67877dc34
4
+ data.tar.gz: 0cf7116a88485be0057ff010ab330569391a9e2e
5
5
  SHA512:
6
- metadata.gz: 4b3b766d2e7b1d211d8645a57ab3dfefd253cebd29fb7981f792e7194fd66b61d8fc21213088b67420481d1baeb12aad35b024f0d19cf3164c2c756151b45b75
7
- data.tar.gz: 457535a8deac214dd3e898d2f38ed654c2c854d76572644d2255ef4fa2040fdd4c1d509c9c197983e84e687dd77f6ac0bcd5686032a4067cf72161fdcd998cbf
6
+ metadata.gz: 63cb08bcc97ac6e4bf25e1da93f047f0edf1726ea404864e7e47fc920dd3c8f8df988b7e532efbb31ef6d611c24cf43577978eee12817e273e8ea254b2f55203
7
+ data.tar.gz: 89be3d3d4be1c8f9dc54f7d41842a443b6d8fe71586c7d79a3002fc87a71db83809d59679f431221877fdd2fc8da3a0e88ed7b79a534b1d0cc75d2218c12f4c6
data/.gitignore CHANGED
@@ -1,2 +1 @@
1
1
  Gemfile.lock
2
- dist/
data/CHANGES.md CHANGED
@@ -1,3 +1,22 @@
1
+ 1.0.2
2
+ -----
3
+
4
+ - added warning when using Psych + an older version of libyaml
5
+
6
+ 1.0.1
7
+ -----
8
+
9
+ - fixed handling for strings that look like (invalid) dates
10
+
11
+ 1.0.0
12
+ -----
13
+
14
+ - updated date parsing to use local timezone
15
+ - **now requiring "safe_yaml/load" provides `SafeYAML.load` without clobbering `YAML`**
16
+ - fixed handling of empty files
17
+ - fixed some (edge case) integer parsing bugs
18
+ - fixed some JRuby-specific issues
19
+
1
20
  0.9.7
2
21
  -----
3
22
 
@@ -33,21 +33,19 @@ module YAML
33
33
  SafeYAML.load_file(*args)
34
34
  end
35
35
 
36
- def self.unsafe_load_file(filename)
37
- if SafeYAML::MULTI_ARGUMENT_YAML_LOAD
36
+ if SafeYAML::MULTI_ARGUMENT_YAML_LOAD
37
+ def self.unsafe_load_file(filename)
38
38
  # https://github.com/tenderlove/psych/blob/v1.3.2/lib/psych.rb#L296-298
39
39
  File.open(filename, 'r:bom|utf-8') { |f| self.unsafe_load(f, filename) }
40
- else
40
+ end
41
+
42
+ else
43
+ def self.unsafe_load_file(filename)
41
44
  # https://github.com/tenderlove/psych/blob/v1.2.2/lib/psych.rb#L231-233
42
45
  self.unsafe_load File.open(filename)
43
46
  end
44
47
  end
45
48
 
46
- def self.unsafe_load_file(filename)
47
- # https://github.com/indeyets/syck/blob/master/ext/ruby/lib/yaml.rb#L133-135
48
- File.open(filename) { |f| self.unsafe_load(f) }
49
- end
50
-
51
49
  class << self
52
50
  alias_method :unsafe_load, :load
53
51
  alias_method :load, :load_with_options
@@ -4,8 +4,34 @@ require "yaml"
4
4
  # their behavior off of this.
5
5
  module SafeYAML
6
6
  YAML_ENGINE = defined?(YAML::ENGINE) ? YAML::ENGINE.yamler : "syck"
7
+ LIBYAML_VERSION = YAML_ENGINE == "psych" && Psych.const_defined?("LIBYAML_VERSION", false) ? Psych::LIBYAML_VERSION : nil
8
+
9
+ def self.check_libyaml_version
10
+ if YAML_ENGINE == "psych" && (LIBYAML_VERSION.nil? || LIBYAML_VERSION < "0.1.6")
11
+ Kernel.warn <<-EOWARNING.gsub(/^ +/, ' ')
12
+
13
+ \e[33mSafeYAML Warning\e[39m
14
+ \e[33m----------------\e[39m
15
+
16
+ \e[31mYou appear to have an outdated version of libyaml (#{LIBYAML_VERSION}) installed on your system.\e[39m
17
+
18
+ Prior to 0.1.6, libyaml is vulnerable to a heap overflow exploit from malicious YAML payloads.
19
+
20
+ For more info, see:
21
+ https://www.ruby-lang.org/en/news/2014/03/29/heap-overflow-in-yaml-uri-escape-parsing-cve-2014-2525/
22
+
23
+ The easiest thing to do right now is probably to update Psych to the latest version and enable
24
+ the 'bundled-libyaml' option, which will install a vendored libyaml with the vulnerability patched:
25
+
26
+ \e[32mgem install psych -- --enable-bundled-libyaml\e[39m
27
+
28
+ EOWARNING
29
+ end
30
+ end
7
31
  end
8
32
 
33
+ SafeYAML.check_libyaml_version
34
+
9
35
  require "set"
10
36
  require "safe_yaml/deep"
11
37
  require "safe_yaml/parse/hexadecimal"
@@ -36,7 +62,28 @@ module SafeYAML
36
62
 
37
63
  OPTIONS = Deep.copy(DEFAULT_OPTIONS)
38
64
 
65
+ PREDEFINED_TAGS = {}
66
+
67
+ if YAML_ENGINE == "syck"
68
+ YAML.tagged_classes.each do |tag, klass|
69
+ PREDEFINED_TAGS[klass] = tag
70
+ end
71
+
72
+ else
73
+ # Special tags appear to be hard-coded in Psych:
74
+ # https://github.com/tenderlove/psych/blob/v1.3.4/lib/psych/visitors/to_ruby.rb
75
+ # Fortunately, there aren't many that SafeYAML doesn't already support.
76
+ PREDEFINED_TAGS.merge!({
77
+ Exception => "!ruby/exception",
78
+ Range => "!ruby/range",
79
+ Regexp => "!ruby/regexp",
80
+ })
81
+ end
82
+
83
+ Deep.freeze(PREDEFINED_TAGS)
84
+
39
85
  module_function
86
+
40
87
  def restore_defaults!
41
88
  OPTIONS.clear.merge!(Deep.copy(DEFAULT_OPTIONS))
42
89
  end
@@ -61,7 +108,7 @@ module SafeYAML
61
108
  raise "#{klass} cannot be anonymous" if klass_name.nil? || klass_name.empty?
62
109
 
63
110
  # Whitelist any built-in YAML tags supplied by Syck or Psych.
64
- predefined_tag = predefined_tags[klass]
111
+ predefined_tag = PREDEFINED_TAGS[klass]
65
112
  if predefined_tag
66
113
  OPTIONS[:whitelisted_tags] << predefined_tag
67
114
  return
@@ -78,30 +125,6 @@ module SafeYAML
78
125
  OPTIONS[:whitelisted_tags] << "#{tag_prefix}:#{klass_name}"
79
126
  end
80
127
 
81
- def predefined_tags
82
- if @predefined_tags.nil?
83
- @predefined_tags = {}
84
-
85
- if YAML_ENGINE == "syck"
86
- YAML.tagged_classes.each do |tag, klass|
87
- @predefined_tags[klass] = tag
88
- end
89
-
90
- else
91
- # Special tags appear to be hard-coded in Psych:
92
- # https://github.com/tenderlove/psych/blob/v1.3.4/lib/psych/visitors/to_ruby.rb
93
- # Fortunately, there aren't many that SafeYAML doesn't already support.
94
- @predefined_tags.merge!({
95
- Exception => "!ruby/exception",
96
- Range => "!ruby/range",
97
- Regexp => "!ruby/regexp",
98
- })
99
- end
100
- end
101
-
102
- @predefined_tags
103
- end
104
-
105
128
  if YAML_ENGINE == "psych"
106
129
  def tag_is_explicitly_trusted?(tag)
107
130
  false
@@ -19,7 +19,7 @@ module SafeYAML
19
19
 
20
20
  # The DateTime class has a #to_time method in Ruby 1.9+;
21
21
  # Before that we'll just need to convert DateTime to Time ourselves.
22
- TO_TIME_AVAILABLE = DateTime.new.respond_to?(:to_time)
22
+ TO_TIME_AVAILABLE = DateTime.instance_methods.include?(:to_time)
23
23
 
24
24
  def self.value(value)
25
25
  d = DateTime.parse(value)
@@ -1,3 +1,3 @@
1
1
  module SafeYAML
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require "spec_helper"
2
2
 
3
3
  if SafeYAML::YAML_ENGINE == "psych"
4
4
  require "safe_yaml/psych_resolver"
@@ -16,8 +16,31 @@ module ResolverSpecs
16
16
 
17
17
  # Isn't this how I should've been doing it all along?
18
18
  def parse_and_test(yaml)
19
- parse(yaml)
20
- @result.should == YAML.unsafe_load(yaml)
19
+ safe_result = parse(yaml)
20
+
21
+ exception_thrown = nil
22
+
23
+ unsafe_result = begin
24
+ YAML.unsafe_load(yaml)
25
+ rescue Exception => e
26
+ exception_thrown = e
27
+ end
28
+
29
+ if exception_thrown
30
+ # If the underlying YAML parser (e.g. Psych) threw an exception, I'm
31
+ # honestly not sure what the right thing to do is. For now I'll just
32
+ # print a warning. Should SafeYAML fail when Psych fails?
33
+ Kernel.warn "\n"
34
+ Kernel.warn "Discrepancy between SafeYAML and #{SafeYAML::YAML_ENGINE} on input:\n"
35
+ Kernel.warn "#{yaml.unindent}\n"
36
+ Kernel.warn "SafeYAML result:"
37
+ Kernel.warn "#{safe_result.inspect}\n"
38
+ Kernel.warn "#{SafeYAML::YAML_ENGINE} result:"
39
+ Kernel.warn "#{exception_thrown.inspect}\n"
40
+
41
+ else
42
+ safe_result.should == unsafe_result
43
+ end
21
44
  end
22
45
 
23
46
  context "by default" do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require "spec_helper"
2
2
 
3
3
  describe YAML do
4
4
  # Essentially stolen from:
@@ -32,6 +32,47 @@ describe YAML do
32
32
  SafeYAML.restore_defaults!
33
33
  end
34
34
 
35
+ describe "check_libyaml_version" do
36
+ REAL_YAML_ENGINE = SafeYAML::YAML_ENGINE
37
+ REAL_LIBYAML_VERSION = SafeYAML::LIBYAML_VERSION
38
+
39
+ after :each do
40
+ silence_warnings do
41
+ SafeYAML::YAML_ENGINE = REAL_YAML_ENGINE
42
+ SafeYAML::LIBYAML_VERSION = REAL_LIBYAML_VERSION
43
+ end
44
+ end
45
+
46
+ def test_check_libyaml_version(warning_expected, yaml_engine, libyaml_version=nil)
47
+ silence_warnings do
48
+ SafeYAML.const_set("YAML_ENGINE", yaml_engine)
49
+ SafeYAML.const_set("LIBYAML_VERSION", libyaml_version)
50
+ Kernel.send(warning_expected ? :should_receive : :should_not_receive, :warn)
51
+ SafeYAML.check_libyaml_version
52
+ end
53
+ end
54
+
55
+ it "issues no warnings when 'Syck' is the YAML engine" do
56
+ test_check_libyaml_version(false, "syck")
57
+ end
58
+
59
+ it "issues a warning if Psych::LIBYAML_VERSION is not defined" do
60
+ test_check_libyaml_version(true, "psych")
61
+ end
62
+
63
+ it "issues a warning if Psych::LIBYAML_VERSION is < 0.1.6" do
64
+ test_check_libyaml_version(true, "psych", "0.1.5")
65
+ end
66
+
67
+ it "issues no warning if Psych::LIBYAML_VERSION is == 0.1.6" do
68
+ test_check_libyaml_version(false, "psych", "0.1.6")
69
+ end
70
+
71
+ it "issues no warning if Psych::LIBYAML_VERSION is > 0.1.6" do
72
+ test_check_libyaml_version(false, "psych", "1.0.0")
73
+ end
74
+ end
75
+
35
76
  describe "unsafe_load" do
36
77
  if SafeYAML::YAML_ENGINE == "psych" && RUBY_VERSION >= "1.9.3"
37
78
  it "allows exploits through objects defined in YAML w/ !ruby/hash via custom :[]= methods" do
@@ -7,12 +7,19 @@ $LOAD_PATH << File.join(HERE, "support")
7
7
  require "yaml"
8
8
  if ENV["YAMLER"] && defined?(YAML::ENGINE)
9
9
  YAML::ENGINE.yamler = ENV["YAMLER"]
10
- puts "Running specs in Ruby #{RUBY_VERSION} with '#{YAML::ENGINE.yamler}' YAML engine."
11
10
  end
12
11
 
13
- if defined?(JRUBY_VERSION) && ENV["JRUBY_OPTS"]
14
- puts "Running JRuby in #{RUBY_VERSION} mode."
15
- end
12
+ ruby_version = defined?(JRUBY_VERSION) ? "JRuby #{JRUBY_VERSION} in #{RUBY_VERSION} mode" : "Ruby #{RUBY_VERSION}"
13
+ yaml_engine = defined?(YAML::ENGINE) ? YAML::ENGINE.yamler : "syck"
14
+ libyaml_version = yaml_engine == "psych" && Psych.const_defined?("LIBYAML_VERSION", false) ? Psych::LIBYAML_VERSION : "N/A"
15
+
16
+ puts <<-EOM
17
+
18
+ Running #{ruby_version} with '#{yaml_engine}' YAML engine.
19
+ YAML engine version: #{YAML::VERSION}
20
+ libyaml version: #{libyaml_version}
21
+
22
+ EOM
16
23
 
17
24
  # Caching references to these methods before loading safe_yaml in order to test
18
25
  # that they aren't touched unless you actually require safe_yaml (see yaml_spec.rb).
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require "spec_helper"
2
2
 
3
3
  if SafeYAML::YAML_ENGINE == "syck"
4
4
  require "safe_yaml/syck_resolver"
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "..", "spec_helper")
1
+ require "spec_helper"
2
2
 
3
3
  describe SafeYAML::Transform do
4
4
  it "should return the same encoding when decoding Base64" do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "..", "spec_helper")
1
+ require "spec_helper"
2
2
 
3
3
  describe SafeYAML::Transform::ToDate do
4
4
  it "returns true when the value matches a valid Date" do
@@ -36,7 +36,7 @@ describe SafeYAML::Transform::ToDate do
36
36
  success, result = subject.transform?("2012-12-01 10:33:45 +11:00")
37
37
  success.should be_true
38
38
  result.should == Time.utc(2012, 11, 30, 23, 33, 45)
39
- result.gmt_offset.should == Time.now.gmt_offset
39
+ result.gmt_offset.should == Time.local(2012, 11, 30).gmt_offset
40
40
  end
41
41
 
42
42
  it "returns strings for invalid dates" do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "..", "spec_helper")
1
+ require "spec_helper"
2
2
 
3
3
  describe SafeYAML::Transform::ToFloat do
4
4
  it "returns true when the value matches a valid Float" do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "..", "spec_helper")
1
+ require "spec_helper"
2
2
 
3
3
  describe SafeYAML::Transform::ToInteger do
4
4
  it "returns true when the value matches a valid Integer" do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "..", "spec_helper")
1
+ require "spec_helper"
2
2
 
3
3
  describe SafeYAML::Transform::ToSymbol do
4
4
  def with_symbol_deserialization_value(value)
@@ -1,6 +1,6 @@
1
1
  # See https://github.com/dtao/safe_yaml/issues/47
2
2
 
3
- require File.join(File.dirname(__FILE__), "spec_helper")
3
+ require "spec_helper"
4
4
 
5
5
  describe YAML do
6
6
  context "when you've only required safe_yaml/load", :libraries => true do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safe_yaml
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Tao
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-10 00:00:00.000000000 Z
11
+ date: 2014-04-04 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Parse YAML safely
14
14
  email: daniel.tao@gmail.com
@@ -16,8 +16,8 @@ executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
- - .gitignore
20
- - .travis.yml
19
+ - ".gitignore"
20
+ - ".travis.yml"
21
21
  - CHANGES.md
22
22
  - Gemfile
23
23
  - LICENSE.txt
@@ -74,12 +74,12 @@ require_paths:
74
74
  - lib
75
75
  required_ruby_version: !ruby/object:Gem::Requirement
76
76
  requirements:
77
- - - '>='
77
+ - - ">="
78
78
  - !ruby/object:Gem::Version
79
79
  version: 1.8.7
80
80
  required_rubygems_version: !ruby/object:Gem::Requirement
81
81
  requirements:
82
- - - '>='
82
+ - - ">="
83
83
  - !ruby/object:Gem::Version
84
84
  version: '0'
85
85
  requirements: []