Denial of Service and Unsafe Object Creation Vulnerability in JSON
There is a denial of service and unsafe object creation vulnerability in the json gem. This vulnerability has been
assigned the CVE identifier CVE-2013-0269.
Versions Affected: All. This includes JSON that ships with Ruby 1.9.X-pXXX.
Not affected: NONE
Fixed Versions: 1.7.7, 1.6.8, 1.5.5
Impact
------
When parsing certain JSON documents, the JSON gem can be coerced in to creating Ruby symbols in a target system. Since
Ruby symbols are not garbage collected, this can result in a denial of service attack.
The same technique can be used to create objects in a target system that act like internal objects. These "act alike"
objects can be used to bypass certain security mechanisms and can be used as a spring board for SQL injection attacks
in Ruby on Rails.
Impacted code looks like this:
JSON.parse(user_input)
Where the `user_input` variable will have a JSON document like this:
{"json_class":"foo"}
The JSON gem will attempt to look up the constant "foo". Looking up this constant will create a symbol.
In JSON version 1.7.x, objects with arbitrary attributes can be created using JSON documents like this:
{"json_class":"JSON::GenericObject","foo":"bar"}
This document will result in an instance of JSON::GenericObject, with the attribute "foo" that has the value "bar".
Instantiating these objects will result in arbitrary symbol creation and in some cases can be used to bypass security
measures.
PLEASE NOTE: this behavior *does not change* when using `JSON.load`. `JSON.load` should *never* be given input from
unknown sources. If you are processing JSON from an unknown source, *always* use `JSON.parse`.
All users running an affected release should either upgrade or use one of the work arounds immediately.
Releases
--------
The FIXED releases are available at the normal locations.
Workarounds
-----------
For users that cannot upgrade, please use the attached patches. If you cannot use the attached patches, change your
code from this:
JSON.parse(json)
To this:
JSON.parse(json, :create_additions => false)
If you cannot change the usage of `JSON.parse` (for example you're using a gem which depends on `JSON.parse` like
multi_json), then apply this monkey patch:
module JSON
class << self
alias :old_parse :parse
def parse(json, args = {})
args[:create_additions] = false
old_parse(json, args)
end
end
end
Patches
-------
To aid users who aren't able to upgrade immediately we have provided patches for the three supported release series.
They are in git-am format and consist of a single changeset.
* 1-7-VULN.patch - Patch for the 1.7 series
* 1-6-VULN.patch - Patch for the 1.6 series
* 1-5-VULN.patch - Patch for the 1.5 series
Credits
-------
A huge thanks goes to the following people for responsibly disclosing this issue and working with the Rails team to get
it fixed:
* Thomas Hollstegge of Zweitag (www.zweitag.de)
* Ben Murphy
--
Aaron Patterson
http://tenderlovemaking.com/
1-5-denial-of-service.patch
Description:
From 79fa7f352bae842017c885101a556875600fb468 Mon Sep 17 00:00:00 2001
From: Florian Frank <flori () ping de>
Date: Mon, 4 Feb 2013 23:28:30 +0100
Subject: [PATCH] Security fix create_additons problem 1.5.5
---
CHANGES | 7 ++++++
Gemfile | 4 +++
VERSION | 2 +-
ext/json/ext/parser/parser.c | 36 +++++++++++++--------------
ext/json/ext/parser/parser.rl | 5 +++-
java/src/json/ext/Parser.java | 2 +-
java/src/json/ext/Parser.rl | 2 +-
json.gemspec | 10 ++++----
json_pure.gemspec | 8 +++---
lib/json/add/core.rb | 9 ++++---
lib/json/common.rb | 17 +++++++++----
lib/json/pure/parser.rb | 8 +++---
lib/json/version.rb | 2 +-
tests/test_json.rb | 24 ++++++++++++++++--
tests/test_json_addition.rb | 50 ++++++++++++++++++++++----------------
tests/test_json_string_matching.rb | 11 ++++-----
16 files changed, 124 insertions(+), 73 deletions(-)
diff --git a/CHANGES b/CHANGES
index 8e751be..42328b7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,10 @@
+2013-02-04 (1.5.5)
+ * Security fix for JSON create_additions default value. It should not be
+ possible to create additions unless
+ explicitely requested by setting the create_additions argument to true or
+ using the JSON.load/dump interface.
+ * Backport change that corrects Time serialisation/deserialisation on some
+ platforms.
2011-08-31 (1.5.4)
* Fix memory leak when used from multiple JRuby. (Patch by
jfirebaugh () github).
diff --git a/Gemfile b/Gemfile
index eb44418..e405da2 100644
--- a/Gemfile
+++ b/Gemfile
@@ -5,3 +5,7 @@ source :rubygems
gemspec :name => 'json'
gemspec :name => 'json_pure'
gemspec :name => 'json-java'
+
+gem 'utils'
+gem 'test-unit'
+gem 'debugger', :platform => :mri_19
diff --git a/VERSION b/VERSION
index 94fe62c..9075be4 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.5.4
+1.5.5
diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c
index d1d14c7..21457c7 100644
--- a/ext/json/ext/parser/parser.c
+++ b/ext/json/ext/parser/parser.c
@@ -1671,7 +1671,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
if (option_given_p(opts, tmp)) {
json->create_additions = RTEST(rb_hash_aref(opts, tmp));
} else {
- json->create_additions = 1;
+ json->create_additions = 0;
}
tmp = ID2SYM(i_create_id);
if (option_given_p(opts, tmp)) {
@@ -1718,7 +1718,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
}
-#line 1719 "parser.c"
+#line 1722 "parser.c"
static const int JSON_start = 1;
static const int JSON_first_final = 10;
static const int JSON_error = 0;
@@ -1726,7 +1726,7 @@ static const int JSON_error = 0;
static const int JSON_en_main = 1;
-#line 726 "parser.rl"
+#line 729 "parser.rl"
static VALUE cParser_parse_strict(VALUE self)
@@ -1737,16 +1737,16 @@ static VALUE cParser_parse_strict(VALUE self)
GET_PARSER;
-#line 1738 "parser.c"
+#line 1741 "parser.c"
{
cs = JSON_start;
}
-#line 736 "parser.rl"
+#line 739 "parser.rl"
p = json->source;
pe = p + json->len;
-#line 1747 "parser.c"
+#line 1750 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -1802,7 +1802,7 @@ case 5:
goto st1;
goto st5;
tr3:
-#line 715 "parser.rl"
+#line 718 "parser.rl"
{
char *np;
json->current_nesting = 1;
@@ -1811,7 +1811,7 @@ tr3:
}
goto st10;
tr4:
-#line 708 "parser.rl"
+#line 711 "parser.rl"
{
char *np;
json->current_nesting = 1;
@@ -1823,7 +1823,7 @@ st10:
if ( ++p == pe )
goto _test_eof10;
case 10:
-#line 1824 "parser.c"
+#line 1827 "parser.c"
switch( (*p) ) {
case 13: goto st10;
case 32: goto st10;
@@ -1880,7 +1880,7 @@ case 9:
_out: {}
}
-#line 739 "parser.rl"
+#line 742 "parser.rl"
if (cs >= JSON_first_final && p == pe) {
return result;
@@ -1892,7 +1892,7 @@ case 9:
-#line 1893 "parser.c"
+#line 1896 "parser.c"
static const int JSON_quirks_mode_start = 1;
static const int JSON_quirks_mode_first_final = 10;
static const int JSON_quirks_mode_error = 0;
@@ -1900,7 +1900,7 @@ static const int JSON_quirks_mode_error = 0;
static const int JSON_quirks_mode_en_main = 1;
-#line 764 "parser.rl"
+#line 767 "parser.rl"
static VALUE cParser_parse_quirks_mode(VALUE self)
@@ -1911,16 +1911,16 @@ static VALUE cParser_parse_quirks_mode(VALUE self)
GET_PARSER;
-#line 1912 "parser.c"
+#line 1915 "parser.c"
{
cs = JSON_quirks_mode_start;
}
-#line 774 "parser.rl"
+#line 777 "parser.rl"
p = json->source;
pe = p + json->len;
-#line 1921 "parser.c"
+#line 1924 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -1954,7 +1954,7 @@ st0:
cs = 0;
goto _out;
tr2:
-#line 756 "parser.rl"
+#line 759 "parser.rl"
{
char *np = JSON_parse_value(json, p, pe, &result);
if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;}
@@ -1964,7 +1964,7 @@ st10:
if ( ++p == pe )
goto _test_eof10;
case 10:
-#line 1965 "parser.c"
+#line 1968 "parser.c"
switch( (*p) ) {
case 13: goto st10;
case 32: goto st10;
@@ -2053,7 +2053,7 @@ case 9:
_out: {}
}
-#line 777 "parser.rl"
+#line 780 "parser.rl"
if (cs >= JSON_quirks_mode_first_final && p == pe) {
return result;
diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl
index e7d47e1..ffde2ee 100644
--- a/ext/json/ext/parser/parser.rl
+++ b/ext/json/ext/parser/parser.rl
@@ -602,6 +602,9 @@ static VALUE convert_encoding(VALUE source)
* defaults to true.
* * *object_class*: Defaults to Hash
* * *array_class*: Defaults to Array
+ * * *quirks_mode*: Enables quirks_mode for parser, that is for example
+ * parsing single JSON values instead of documents is possible.
+ *
*/
static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -652,7 +655,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
if (option_given_p(opts, tmp)) {
json->create_additions = RTEST(rb_hash_aref(opts, tmp));
} else {
- json->create_additions = 1;
+ json->create_additions = 0;
}
tmp = ID2SYM(i_create_id);
if (option_given_p(opts, tmp)) {
diff --git a/java/src/json/ext/Parser.java b/java/src/json/ext/Parser.java
index 1240922..ee3d5ec 100644
--- a/java/src/json/ext/Parser.java
+++ b/java/src/json/ext/Parser.java
@@ -160,7 +160,7 @@ public class Parser extends RubyObject {
this.symbolizeNames = opts.getBool("symbolize_names", false);
this.quirksMode = opts.getBool("quirks_mode", false);
this.createId = opts.getString("create_id", getCreateId(context));
- this.createAdditions = opts.getBool("create_additions", true);
+ this.createAdditions = opts.getBool("create_additions", false);
this.objectClass = opts.getClass("object_class", runtime.getHash());
this.arrayClass = opts.getClass("array_class", runtime.getArray());
this.match_string = opts.getHash("match_string");
diff --git a/java/src/json/ext/Parser.rl b/java/src/json/ext/Parser.rl
index e8cd874..e9b3bbd 100644
--- a/java/src/json/ext/Parser.rl
+++ b/java/src/json/ext/Parser.rl
@@ -162,7 +162,7 @@ public class Parser extends RubyObject {
this.symbolizeNames = opts.getBool("symbolize_names", false);
this.quirksMode = opts.getBool("quirks_mode", false);
this.createId = opts.getString("create_id", getCreateId(context));
- this.createAdditions = opts.getBool("create_additions", true);
+ this.createAdditions = opts.getBool("create_additions", false);
this.objectClass = opts.getClass("object_class", runtime.getHash());
this.arrayClass = opts.getClass("array_class", runtime.getArray());
this.match_string = opts.getHash("match_string");
diff --git a/json.gemspec b/json.gemspec
index 344049a..ed8df20 100644
--- a/json.gemspec
+++ b/json.gemspec
@@ -2,22 +2,22 @@
Gem::Specification.new do |s|
s.name = "json"
- s.version = "1.5.4"
+ s.version = "1.5.5"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Florian Frank"]
- s.date = "2011-08-31"
+ s.date = "2013-02-10"
s.description = "This is a JSON implementation as a Ruby extension in C."
s.email = "flori () ping de"
s.executables = ["edit_json.rb", "prettify_json.rb"]
- s.extensions = ["ext/json/ext/parser/extconf.rb", "ext/json/ext/generator/extconf.rb"]
+ s.extensions = ["ext/json/ext/generator/extconf.rb", "ext/json/ext/parser/extconf.rb"]
s.extra_rdoc_files = ["README.rdoc"]
- s.files = ["tests", "tests/test_json_string_matching.rb", "tests/test_json_fixtures.rb", "tests/setup_variant.rb", "tests/fixtures", "tests/fixtures/fail6.json", "tests/fixtures/fail9.json", "tests/fixtures/fail10.json", "tests/fixtures/fail24.json", "tests/fixtures/fail28.json", "tests/fixtures/fail13.json", "tests/fixtures/fail4.json", "tests/fixtures/pass3.json", "tests/fixtures/fail11.json", "tests/fixtures/fail14.json", "tests/fixtures/fail3.json", "tests/fixtures/fail12.json", "tests/fixtures/pass16.json", "tests/fixtures/pass15.json", "tests/fixtures/fail20.json", "tests/fixtures/fail8.json", "tests/fixtures/pass2.json", "tests/fixtures/fail5.json", "tests/fixtures/fail1.json", "tests/fixtures/fail25.json", "tests/fixtures/pass17.json", "tests/fixtures/fail7.json", "tests/fixtures/pass26.json", "tests/fixtures/fail21.json", "tests/fixtures/pass1.json", "tests/fixtures/fail23.json", "tests/fixtures/fail18.json", "tests/fixtures/fail2.json", "tests/fixtures/fail22.json", "tests/fixtures/fail27.json", "tests/fixtures/fail19.json", "tests/test_json_unicode.rb", "tests/test_json_addition.rb", "tests/test_json_generate.rb", "tests/test_json_encoding.rb", "tests/test_json.rb", "COPYING", "TODO", "Rakefile", "benchmarks", "benchmarks/data-p4-3GHz-ruby18", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat", "benchmarks/parser2_benchmark.rb", "benchmarks/parser_benchmark.rb", "benchmarks/generator2_benchmark.rb", "benchmarks/generator_benchmark.rb", "benchmarks/ohai.ruby", "benchmarks/data", "benchmarks/ohai.json", "lib", "lib/json", "lib/json/json.xpm", "lib/json/TrueClass.xpm", "lib/json/version.rb", "lib/json/Array.xpm", "lib/json/add", "lib/json/add/complex.rb", "lib/json/add/rational.rb", "lib/json/add/core.rb", "lib/json/common.rb", "lib/json/pure", "lib/json/pure/generator.rb", "lib/json/pure/parser.rb", "lib/json/ext.rb", "lib/json/pure.rb", "lib/json/Key.xpm", "lib/json/FalseClass.xpm", "lib/json/editor.rb", "lib/json/Numeric.xpm", "lib/json/ext", "lib/json/NilClass.xpm", "lib/json/String.xpm", "lib/json/Hash.xpm", "lib/json.rb", "Gemfile", "README.rdoc", "json_pure.gemspec", "GPL", "CHANGES", "bin", "bin/prettify_json.rb", "bin/edit_json.rb", "COPYING-json-jruby", "ext", "ext/json", "ext/json/ext", "ext/json/ext/parser", "ext/json/ext/parser/parser.h", "ext/json/ext/parser/extconf.rb", "ext/json/ext/parser/parser.rl", "ext/json/ext/parser/parser.c", "ext/json/ext/generator", "ext/json/ext/generator/generator.c", "ext/json/ext/generator/extconf.rb", "ext/json/ext/generator/generator.h", "VERSION", "data", "data/prototype.js", "data/index.html", "data/example.json", "json.gemspec", "java", "java/src", "java/src/json", "java/src/json/ext", "java/src/json/ext/Parser.java", "java/src/json/ext/RuntimeInfo.java", "java/src/json/ext/GeneratorState.java", "java/src/json/ext/OptionsReader.java", "java/src/json/ext/ParserService.java", "java/src/json/ext/Parser.rl", "java/src/json/ext/StringEncoder.java", "java/src/json/ext/GeneratorService.java", "java/src/json/ext/Utils.java", "java/src/json/ext/StringDecoder.java", "java/src/json/ext/Generator.java", "java/src/json/ext/ByteListTranscoder.java", "java/src/json/ext/GeneratorMethods.java", "java/lib", "java/lib/bytelist-1.0.6.jar", "java/lib/jcodings.jar", "diagrams", "README-json-jruby.markdown", "install.rb", "json-java.gemspec", "tools", "tools/fuzz.rb", "tools/server.rb", "./tests/test_json_string_matching.rb", "./tests/test_json_fixtures.rb", "./tests/test_json_unicode.rb", "./tests/test_json_addition.rb", "./tests/test_json_generate.rb", "./tests/test_json_encoding.rb", "./tests/test_json.rb"]
+ s.files = ["0001-Security-fix-create_additons-JSON-GenericObject.patch", "0001-Security-fix-create_additons-problem-1.5.5.patch", "0001-Security-fix-for-create_additions-problem-1.6.8.patch", "CHANGES", "COPYING", "COPYING-json-jruby", "GPL", "Gemfile", "Gemfile.lock", "README-json-jruby.markdown", "README.rdoc", "Rakefile", "TODO", "VERSION", "benchmarks", "benchmarks/data", "benchmarks/data-p4-3GHz-ruby18", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log", "benchmarks/generator2_benchmark.rb", "benchmarks/generator_benchmark.rb", "benchmarks/ohai.json", "benchmarks/ohai.ruby", "benchmarks/parser2_benchmark.rb", "benchmarks/parser_benchmark.rb", "bin", "bin/edit_json.rb", "bin/prettify_json.rb", "data", "data/example.json", "data/index.html", "data/prototype.js", "diagrams", "ext", "ext/json", "ext/json/ext", "ext/json/ext/generator", "ext/json/ext/generator/extconf.rb", "ext/json/ext/generator/generator.c", "ext/json/ext/generator/generator.h", "ext/json/ext/parser", "ext/json/ext/parser/extconf.rb", "ext/json/ext/parser/parser.c", "ext/json/ext/parser/parser.h", "ext/json/ext/parser/parser.rl", "install.rb", "java", "java/lib", "java/lib/bytelist-1.0.6.jar", "java/lib/jcodings.jar", "java/src", "java/src/json", "java/src/json/ext", "java/src/json/ext/ByteListTranscoder.java", "java/src/json/ext/Generator.java", "java/src/json/ext/GeneratorMethods.java", "java/src/json/ext/GeneratorService.java", "java/src/json/ext/GeneratorState.java", "java/src/json/ext/OptionsReader.java", "java/src/json/ext/Parser.java", "java/src/json/ext/Parser.rl", "java/src/json/ext/ParserService.java", "java/src/json/ext/RuntimeInfo.java", "java/src/json/ext/StringDecoder.java", "java/src/json/ext/StringEncoder.java", "java/src/json/ext/Utils.java", "json-java.gemspec", "json.gemspec", "json_pure.gemspec", "lib", "lib/json", "lib/json.rb", "lib/json/Array.xpm", "lib/json/FalseClass.xpm", "lib/json/Hash.xpm", "lib/json/Key.xpm", "lib/json/NilClass.xpm", "lib/json/Numeric.xpm", "lib/json/String.xpm", "lib/json/TrueClass.xpm", "lib/json/add", "lib/json/add/complex.rb", "lib/json/add/core.rb", "lib/json/add/rational.rb", "lib/json/common.rb", "lib/json/editor.rb", "lib/json/ext", "lib/json/ext.rb", "lib/json/json.xpm", "lib/json/pure", "lib/json/pure.rb", "lib/json/pure/generator.rb", "lib/json/pure/parser.rb", "lib/json/version.rb", "tests", "tests/fixtures", "tests/fixtures/fail1.json", "tests/fixtures/fail10.json", "tests/fixtures/fail11.json", "tests/fixtures/fail12.json", "tests/fixtures/fail13.json", "tests/fixtures/fail14.json", "tests/fixtures/fail18.json", "tests/fixtures/fail19.json", "tests/fixtures/fail2.json", "tests/fixtures/fail20.json", "tests/fixtures/fail21.json", "tests/fixtures/fail22.json", "tests/fixtures/fail23.json", "tests/fixtures/fail24.json", "tests/fixtures/fail25.json", "tests/fixtures/fail27.json", "tests/fixtures/fail28.json", "tests/fixtures/fail3.json", "tests/fixtures/fail4.json", "tests/fixtures/fail5.json", "tests/fixtures/fail6.json", "tests/fixtures/fail7.json", "tests/fixtures/fail8.json", "tests/fixtures/fail9.json", "tests/fixtures/pass1.json", "tests/fixtures/pass15.json", "tests/fixtures/pass16.json", "tests/fixtures/pass17.json", "tests/fixtures/pass2.json", "tests/fixtures/pass26.json", "tests/fixtures/pass3.json", "tests/setup_variant.rb", "tests/test_json.rb", "tests/test_json_addition.rb", "tests/test_json_encoding.rb", "tests/test_json_fixtures.rb", "tests/test_json_generate.rb", "tests/test_json_string_matching.rb", "tests/test_json_unicode.rb", "tools", "tools/fuzz.rb", "tools/server.rb", "./tests/test_json_string_matching.rb", "./tests/test_json_fixtures.rb", "./tests/test_json_unicode.rb", "./tests/test_json_addition.rb", "./tests/test_json_generate.rb", "./tests/test_json_encoding.rb", "./tests/test_json.rb"]
s.homepage = "http://flori.github.com/json"
s.rdoc_options = ["--title", "JSON implemention for Ruby", "--main", "README.rdoc"]
s.require_paths = ["ext/json/ext", "ext", "lib"]
s.rubyforge_project = "json"
- s.rubygems_version = "1.8.10"
+ s.rubygems_version = "1.8.25"
s.summary = "JSON Implementation for Ruby"
s.test_files = ["./tests/test_json_string_matching.rb", "./tests/test_json_fixtures.rb", "./tests/test_json_unicode.rb", "./tests/test_json_addition.rb", "./tests/test_json_generate.rb", "./tests/test_json_encoding.rb", "./tests/test_json.rb"]
diff --git a/json_pure.gemspec b/json_pure.gemspec
index f5f662e..d9356f4 100644
--- a/json_pure.gemspec
+++ b/json_pure.gemspec
@@ -2,21 +2,21 @@
Gem::Specification.new do |s|
s.name = "json_pure"
- s.version = "1.5.4"
+ s.version = "1.5.5"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Florian Frank"]
- s.date = "2011-08-31"
+ s.date = "2013-02-10"
s.description = "This is a JSON implementation in pure Ruby."
s.email = "flori () ping de"
s.executables = ["edit_json.rb", "prettify_json.rb"]
s.extra_rdoc_files = ["README.rdoc"]
- s.files = ["tests", "tests/test_json_string_matching.rb", "tests/test_json_fixtures.rb", "tests/setup_variant.rb", "tests/fixtures", "tests/fixtures/fail6.json", "tests/fixtures/fail9.json", "tests/fixtures/fail10.json", "tests/fixtures/fail24.json", "tests/fixtures/fail28.json", "tests/fixtures/fail13.json", "tests/fixtures/fail4.json", "tests/fixtures/pass3.json", "tests/fixtures/fail11.json", "tests/fixtures/fail14.json", "tests/fixtures/fail3.json", "tests/fixtures/fail12.json", "tests/fixtures/pass16.json", "tests/fixtures/pass15.json", "tests/fixtures/fail20.json", "tests/fixtures/fail8.json", "tests/fixtures/pass2.json", "tests/fixtures/fail5.json", "tests/fixtures/fail1.json", "tests/fixtures/fail25.json", "tests/fixtures/pass17.json", "tests/fixtures/fail7.json", "tests/fixtures/pass26.json", "tests/fixtures/fail21.json", "tests/fixtures/pass1.json", "tests/fixtures/fail23.json", "tests/fixtures/fail18.json", "tests/fixtures/fail2.json", "tests/fixtures/fail22.json", "tests/fixtures/fail27.json", "tests/fixtures/fail19.json", "tests/test_json_unicode.rb", "tests/test_json_addition.rb", "tests/test_json_generate.rb", "tests/test_json_encoding.rb", "tests/test_json.rb", "COPYING", "TODO", "Rakefile", "benchmarks", "benchmarks/data-p4-3GHz-ruby18", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat", "benchmarks/parser2_benchmark.rb", "benchmarks/parser_benchmark.rb", "benchmarks/generator2_benchmark.rb", "benchmarks/generator_benchmark.rb", "benchmarks/ohai.ruby", "benchmarks/data", "benchmarks/ohai.json", "lib", "lib/json", "lib/json/json.xpm", "lib/json/TrueClass.xpm", "lib/json/version.rb", "lib/json/Array.xpm", "lib/json/add", "lib/json/add/complex.rb", "lib/json/add/rational.rb", "lib/json/add/core.rb", "lib/json/common.rb", "lib/json/pure", "lib/json/pure/generator.rb", "lib/json/pure/parser.rb", "lib/json/ext.rb", "lib/json/pure.rb", "lib/json/Key.xpm", "lib/json/FalseClass.xpm", "lib/json/editor.rb", "lib/json/Numeric.xpm", "lib/json/ext", "lib/json/NilClass.xpm", "lib/json/String.xpm", "lib/json/Hash.xpm", "lib/json.rb", "Gemfile", "README.rdoc", "json_pure.gemspec", "GPL", "CHANGES", "bin", "bin/prettify_json.rb", "bin/edit_json.rb", "COPYING-json-jruby", "ext", "ext/json", "ext/json/ext", "ext/json/ext/parser", "ext/json/ext/parser/parser.h", "ext/json/ext/parser/extconf.rb", "ext/json/ext/parser/parser.rl", "ext/json/ext/parser/parser.c", "ext/json/ext/generator", "ext/json/ext/generator/generator.c", "ext/json/ext/generator/extconf.rb", "ext/json/ext/generator/generator.h", "VERSION", "data", "data/prototype.js", "data/index.html", "data/example.json", "json.gemspec", "java", "java/src", "java/src/json", "java/src/json/ext", "java/src/json/ext/Parser.java", "java/src/json/ext/RuntimeInfo.java", "java/src/json/ext/GeneratorState.java", "java/src/json/ext/OptionsReader.java", "java/src/json/ext/ParserService.java", "java/src/json/ext/Parser.rl", "java/src/json/ext/StringEncoder.java", "java/src/json/ext/GeneratorService.java", "java/src/json/ext/Utils.java", "java/src/json/ext/StringDecoder.java", "java/src/json/ext/Generator.java", "java/src/json/ext/ByteListTranscoder.java", "java/src/json/ext/GeneratorMethods.java", "java/lib", "java/lib/bytelist-1.0.6.jar", "java/lib/jcodings.jar", "diagrams", "README-json-jruby.markdown", "install.rb", "json-java.gemspec", "tools", "tools/fuzz.rb", "tools/server.rb", "./tests/test_json_string_matching.rb", "./tests/test_json_fixtures.rb", "./tests/test_json_unicode.rb", "./tests/test_json_addition.rb", "./tests/test_json_generate.rb", "./tests/test_json_encoding.rb", "./tests/test_json.rb"]
+ s.files = ["0001-Security-fix-create_additons-JSON-GenericObject.patch", "0001-Security-fix-create_additons-problem-1.5.5.patch", "0001-Security-fix-for-create_additions-problem-1.6.8.patch", "CHANGES", "COPYING", "COPYING-json-jruby", "GPL", "Gemfile", "Gemfile.lock", "README-json-jruby.markdown", "README.rdoc", "Rakefile", "TODO", "VERSION", "benchmarks", "benchmarks/data", "benchmarks/data-p4-3GHz-ruby18", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat", "benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat", "benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log", "benchmarks/generator2_benchmark.rb", "benchmarks/generator_benchmark.rb", "benchmarks/ohai.json", "benchmarks/ohai.ruby", "benchmarks/parser2_benchmark.rb", "benchmarks/parser_benchmark.rb", "bin", "bin/edit_json.rb", "bin/prettify_json.rb", "data", "data/example.json", "data/index.html", "data/prototype.js", "diagrams", "ext", "ext/json", "ext/json/ext", "ext/json/ext/generator", "ext/json/ext/generator/extconf.rb", "ext/json/ext/generator/generator.c", "ext/json/ext/generator/generator.h", "ext/json/ext/parser", "ext/json/ext/parser/extconf.rb", "ext/json/ext/parser/parser.c", "ext/json/ext/parser/parser.h", "ext/json/ext/parser/parser.rl", "install.rb", "java", "java/lib", "java/lib/bytelist-1.0.6.jar", "java/lib/jcodings.jar", "java/src", "java/src/json", "java/src/json/ext", "java/src/json/ext/ByteListTranscoder.java", "java/src/json/ext/Generator.java", "java/src/json/ext/GeneratorMethods.java", "java/src/json/ext/GeneratorService.java", "java/src/json/ext/GeneratorState.java", "java/src/json/ext/OptionsReader.java", "java/src/json/ext/Parser.java", "java/src/json/ext/Parser.rl", "java/src/json/ext/ParserService.java", "java/src/json/ext/RuntimeInfo.java", "java/src/json/ext/StringDecoder.java", "java/src/json/ext/StringEncoder.java", "java/src/json/ext/Utils.java", "json-java.gemspec", "json.gemspec", "json_pure.gemspec", "lib", "lib/json", "lib/json.rb", "lib/json/Array.xpm", "lib/json/FalseClass.xpm", "lib/json/Hash.xpm", "lib/json/Key.xpm", "lib/json/NilClass.xpm", "lib/json/Numeric.xpm", "lib/json/String.xpm", "lib/json/TrueClass.xpm", "lib/json/add", "lib/json/add/complex.rb", "lib/json/add/core.rb", "lib/json/add/rational.rb", "lib/json/common.rb", "lib/json/editor.rb", "lib/json/ext", "lib/json/ext.rb", "lib/json/json.xpm", "lib/json/pure", "lib/json/pure.rb", "lib/json/pure/generator.rb", "lib/json/pure/parser.rb", "lib/json/version.rb", "tests", "tests/fixtures", "tests/fixtures/fail1.json", "tests/fixtures/fail10.json", "tests/fixtures/fail11.json", "tests/fixtures/fail12.json", "tests/fixtures/fail13.json", "tests/fixtures/fail14.json", "tests/fixtures/fail18.json", "tests/fixtures/fail19.json", "tests/fixtures/fail2.json", "tests/fixtures/fail20.json", "tests/fixtures/fail21.json", "tests/fixtures/fail22.json", "tests/fixtures/fail23.json", "tests/fixtures/fail24.json", "tests/fixtures/fail25.json", "tests/fixtures/fail27.json", "tests/fixtures/fail28.json", "tests/fixtures/fail3.json", "tests/fixtures/fail4.json", "tests/fixtures/fail5.json", "tests/fixtures/fail6.json", "tests/fixtures/fail7.json", "tests/fixtures/fail8.json", "tests/fixtures/fail9.json", "tests/fixtures/pass1.json", "tests/fixtures/pass15.json", "tests/fixtures/pass16.json", "tests/fixtures/pass17.json", "tests/fixtures/pass2.json", "tests/fixtures/pass26.json", "tests/fixtures/pass3.json", "tests/setup_variant.rb", "tests/test_json.rb", "tests/test_json_addition.rb", "tests/test_json_encoding.rb", "tests/test_json_fixtures.rb", "tests/test_json_generate.rb", "tests/test_json_string_matching.rb", "tests/test_json_unicode.rb", "tools", "tools/fuzz.rb", "tools/server.rb", "./tests/test_json_string_matching.rb", "./tests/test_json_fixtures.rb", "./tests/test_json_unicode.rb", "./tests/test_json_addition.rb", "./tests/test_json_generate.rb", "./tests/test_json_encoding.rb", "./tests/test_json.rb"]
s.homepage = "http://flori.github.com/json"
s.rdoc_options = ["--title", "JSON implemention for ruby", "--main", "README.rdoc"]
s.require_paths = ["lib"]
s.rubyforge_project = "json"
- s.rubygems_version = "1.8.10"
+ s.rubygems_version = "1.8.25"
s.summary = "JSON Implementation for Ruby"
s.test_files = ["./tests/test_json_string_matching.rb", "./tests/test_json_fixtures.rb", "./tests/test_json_unicode.rb", "./tests/test_json_addition.rb", "./tests/test_json_generate.rb", "./tests/test_json_encoding.rb", "./tests/test_json.rb"]
diff --git a/lib/json/add/core.rb b/lib/json/add/core.rb
index 1ae00d0..01b8e04 100644
--- a/lib/json/add/core.rb
+++ b/lib/json/add/core.rb
@@ -36,8 +36,8 @@ class Time
if usec = object.delete('u') # used to be tv_usec -> tv_nsec
object['n'] = usec * 1000
end
- if respond_to?(:tv_nsec)
- at(*object.values_at('s', 'n'))
+ if instance_methods.include?(:tv_nsec)
+ at(object['s'], Rational(object['n'], 1000))
else
at(object['s'], object['n'] / 1000)
end
@@ -46,10 +46,13 @@ class Time
# Returns a hash, that will be turned into a JSON object and represent this
# object.
def as_json(*)
+ nanoseconds = [ tv_usec * 1000 ]
+ respond_to?(:tv_nsec) and nanoseconds << tv_nsec
+ nanoseconds = nanoseconds.max
{
JSON.create_id => self.class.name,
's' => tv_sec,
- 'n' => respond_to?(:tv_nsec) ? tv_nsec : tv_usec * 1000
+ 'n' => nanoseconds,
}
end
diff --git a/lib/json/common.rb b/lib/json/common.rb
index 43e249c..9ad1fab 100644
--- a/lib/json/common.rb
+++ b/lib/json/common.rb
@@ -141,7 +141,7 @@ module JSON
# the default.
# * *create_additions*: If set to false, the Parser doesn't create
# additions even if a matching class and create_id was found. This option
- # defaults to true.
+ # defaults to false.
# * *object_class*: Defaults to Hash
# * *array_class*: Defaults to Array
def parse(source, opts = {})
@@ -162,7 +162,7 @@ module JSON
# to true.
# * *create_additions*: If set to false, the Parser doesn't create
# additions even if a matching class and create_id was found. This option
- # defaults to true.
+ # defaults to false.
def parse!(source, opts = {})
opts = {
:max_nesting => false,
@@ -287,11 +287,18 @@ module JSON
# Load a ruby data structure from a JSON _source_ and return it. A source can
# either be a string-like object, an IO-like object, or an object responding
# to the read method. If _proc_ was given, it will be called with any nested
- # Ruby object as an argument recursively in depth first order.
+ # Ruby object as an argument recursively in depth first order. To modify the
+ # default options pass in the optional _options_ argument as well.
#
# This method is part of the implementation of the load/dump interface of
# Marshal and YAML.
- def load(source, proc = nil)
+ def load(source, proc = nil, options = {})
+ load_default_options = {
+ :max_nesting => false,
+ :allow_nan => true,
+ :create_additions => false
+ }
+ opts = load_default_options.merge options
if source.respond_to? :to_str
source = source.to_str
elsif source.respond_to? :to_io
@@ -299,7 +306,7 @@ module JSON
else
source = source.read
end
- result = parse(source, :max_nesting => false, :allow_nan => true)
+ result = parse(source, opts)
recurse_proc(result, &proc) if proc
result
end
diff --git a/lib/json/pure/parser.rb b/lib/json/pure/parser.rb
index e24aac1..d02ec34 100644
--- a/lib/json/pure/parser.rb
+++ b/lib/json/pure/parser.rb
@@ -63,9 +63,9 @@ module JSON
# * *symbolize_names*: If set to true, returns symbols for the names
# (keys) in a JSON object. Otherwise strings are returned, which is also
# the default.
- # * *create_additions*: If set to false, the Parser doesn't create
- # additions even if a matchin class and create_id was found. This option
- # defaults to true.
+ # * *create_additions*: If set to true, the Parser creates
+ # additions when if a matching class and create_id was found. This
+ # option defaults to false.
# * *object_class*: Defaults to Hash
# * *array_class*: Defaults to Array
# * *quirks_mode*: Enables quirks_mode for parser, that is for example
@@ -88,7 +88,7 @@ module JSON
if opts.key?(:create_additions)
@create_additions = !!opts[:create_additions]
else
- @create_additions = true
+ @create_additions = false
end
@create_id = @create_additions ? JSON.create_id : nil
@object_class = opts[:object_class] || Hash
diff --git a/lib/json/version.rb b/lib/json/version.rb
index 2175ac0..baacdc9 100644
--- a/lib/json/version.rb
+++ b/lib/json/version.rb
@@ -1,6 +1,6 @@
module JSON
# JSON version
- VERSION = '1.5.4'
+ VERSION = '1.5.5'
VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
diff --git a/tests/test_json.rb b/tests/test_json.rb
index eafd758..fa96130 100755
--- a/tests/test_json.rb
+++ b/tests/test_json.rb
@@ -4,6 +4,7 @@
require 'test/unit'
require File.join(File.dirname(__FILE__), 'setup_variant')
require 'stringio'
+require 'tempfile'
unless Array.method_defined?(:permutation)
begin
@@ -263,12 +264,12 @@ class TC_JSON < Test::Unit::TestCase
def test_generation_of_core_subclasses_with_new_to_json
obj = SubHash2["foo" => SubHash2["bar" => true]]
obj_json = JSON(obj)
- obj_again = JSON(obj_json)
+ obj_again = JSON.parse(obj_json, :create_additions => true)
assert_kind_of SubHash2, obj_again
assert_kind_of SubHash2, obj_again['foo']
assert obj_again['foo']['bar']
assert_equal obj, obj_again
- assert_equal ["foo"], JSON(JSON(SubArray2["foo"]))
+ assert_equal ["foo"], JSON(JSON(SubArray2["foo"]), :create_additions => true)
end
def test_generation_of_core_subclasses_with_default_to_json
@@ -414,6 +415,25 @@ EOT
JSON.parse('{"foo":"bar", "baz":"quux"}', :symbolize_names => true))
end
+ def test_load
+ assert_equal @hash, JSON.load(@json)
+ tempfile = Tempfile.open('json')
+ tempfile.write @json
+ tempfile.rewind
+ assert_equal @hash, JSON.load(tempfile)
+ stringio = StringIO.new(@json)
+ stringio.rewind
+ assert_equal @hash, JSON.load(stringio)
+ assert_raise(NoMethodError) { JSON.load(nil) }
+ assert_raise(JSON::ParserError) {JSON.load('') }
+ end
+
+ def test_load_with_options
+ small_hash = JSON("foo" => 'bar')
+ symbol_hash = { :foo => 'bar' }
+ assert_equal symbol_hash, JSON.load(small_hash, nil, :symbolize_names => true)
+ end
+
def test_load_dump
too_deep = '[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]'
assert_equal too_deep, JSON.dump(eval(too_deep))
diff --git a/tests/test_json_addition.rb b/tests/test_json_addition.rb
index 9f578a4..865880c 100755
--- a/tests/test_json_addition.rb
+++ b/tests/test_json_addition.rb
@@ -71,11 +71,19 @@ class TC_JSONAddition < Test::Unit::TestCase
a = A.new(666)
assert A.json_creatable?
json = generate(a)
- a_again = JSON.parse(json)
+ a_again = JSON.parse(json, :create_additions => true)
assert_kind_of a.class, a_again
assert_equal a, a_again
end
+ def test_extended_json_default
+ a = A.new(666)
+ assert A.json_creatable?
+ json = generate(a)
+ a_hash = JSON.parse(json)
+ assert_kind_of Hash, a_hash
+ end
+
def test_extended_json_disabled
a = A.new(666)
assert A.json_creatable?
@@ -102,7 +110,7 @@ class TC_JSONAddition < Test::Unit::TestCase
c = C.new
assert !C.json_creatable?
json = generate(c)
- assert_raises(ArgumentError, NameError) { JSON.parse(json) }
+ assert_raises(ArgumentError, NameError) { JSON.parse(json, :create_additions => true) }
end
def test_raw_strings
@@ -120,7 +128,7 @@ class TC_JSONAddition < Test::Unit::TestCase
assert_match(/\A\{.*\}\Z/, json)
assert_match(/"json_class":"String"/, json)
assert_match(/"raw":\[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255\]/, json)
- raw_again = JSON.parse(json)
+ raw_again = JSON.parse(json, :create_additions => true)
assert_equal raw, raw_again
end
@@ -128,17 +136,17 @@ class TC_JSONAddition < Test::Unit::TestCase
def test_core
t = Time.now
- assert_equal t.inspect, JSON(JSON(t)).inspect
+ assert_equal t, JSON(JSON(t), :create_additions => true)
d = Date.today
- assert_equal d, JSON(JSON(d))
+ assert_equal d, JSON(JSON(d), :create_additions => true)
d = DateTime.civil(2007, 6, 14, 14, 57, 10, Rational(1, 12), 2299161)
- assert_equal d, JSON(JSON(d))
- assert_equal 1..10, JSON(JSON(1..10))
- assert_equal 1...10, JSON(JSON(1...10))
- assert_equal "a".."c", JSON(JSON("a".."c"))
- assert_equal "a"..."c", JSON(JSON("a"..."c"))
+ assert_equal d, JSON(JSON(d), :create_additions => true)
+ assert_equal 1..10, JSON(JSON(1..10), :create_additions => true)
+ assert_equal 1...10, JSON(JSON(1...10), :create_additions => true)
+ assert_equal "a".."c", JSON(JSON("a".."c"), :create_additions => true)
+ assert_equal "a"..."c", JSON(JSON("a"..."c"), :create_additions => true)
s = MyJsonStruct.new 4711, 'foot'
- assert_equal s, JSON(JSON(s))
+ assert_equal s, JSON(JSON(s), :create_additions => true)
struct = Struct.new :foo, :bar
s = struct.new 4711, 'foot'
assert_raises(JSONError) { JSON(s) }
@@ -146,29 +154,29 @@ class TC_JSONAddition < Test::Unit::TestCase
raise TypeError, "test me"
rescue TypeError => e
e_json = JSON.generate e
- e_again = JSON e_json
+ e_again = JSON e_json, :create_additions => true
assert_kind_of TypeError, e_again
assert_equal e.message, e_again.message
assert_equal e.backtrace, e_again.backtrace
end
- assert_equal(/foo/, JSON(JSON(/foo/)))
- assert_equal(/foo/i, JSON(JSON(/foo/i)))
+ assert_equal(/foo/, JSON(JSON(/foo/), :create_additions => true))
+ assert_equal(/foo/i, JSON(JSON(/foo/i), :create_additions => true))
end
def test_utc_datetime
now = Time.now
- d = DateTime.parse(now.to_s) # usual case
- assert_equal d, JSON.parse(d.to_json)
+ d = DateTime.parse(now.to_s, :create_additions => true) # usual case
+ assert_equal d, JSON.parse(d.to_json, :create_additions => true)
d = DateTime.parse(now.utc.to_s) # of = 0
- assert_equal d, JSON.parse(d.to_json)
+ assert_equal d, JSON.parse(d.to_json, :create_additions => true)
d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(1,24))
- assert_equal d, JSON.parse(d.to_json)
+ assert_equal d, JSON.parse(d.to_json, :create_additions => true)
d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(12,24))
- assert_equal d, JSON.parse(d.to_json)
+ assert_equal d, JSON.parse(d.to_json, :create_additions => true)
end
def test_rational_complex
- assert_equal Rational(2, 9), JSON(JSON(Rational(2, 9)))
- assert_equal Complex(2, 9), JSON(JSON(Complex(2, 9)))
+ assert_equal Rational(2, 9), JSON.parse(JSON(Rational(2, 9)), :create_additions => true)
+ assert_equal Complex(2, 9), JSON.parse(JSON(Complex(2, 9)), :create_additions => true)
end
end
diff --git a/tests/test_json_string_matching.rb b/tests/test_json_string_matching.rb
index df26a68..7335c0e 100644
--- a/tests/test_json_string_matching.rb
+++ b/tests/test_json_string_matching.rb
@@ -27,14 +27,13 @@ class TestJsonStringMatching < Test::Unit::TestCase
t = TestTime.new
t_json = [ t ].to_json
assert_equal [ t ],
- JSON.parse(t_json,
- :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\Z/ => TestTime })
+ JSON.parse(t_json, :create_additions => true,
+ :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime })
assert_equal [ t.strftime('%FT%T%z') ],
- JSON.parse(t_json,
- :match_string => { /\A\d{3}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\Z/ => TestTime })
+ JSON.parse(t_json, :create_additions => true,
+ :match_string => { /\A\d{3}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime })
assert_equal [ t.strftime('%FT%T%z') ],
JSON.parse(t_json,
- :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\Z/ => TestTime },
- :create_additions => false)
+ :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime })
end
end
--
1.8.1.2
1-6-denial-of-service.patch
Description:
From 3ce359bbf308354b86e94248fc13dfd4b23c792e Mon Sep 17 00:00:00 2001
From: Florian Frank <flori () ping de>
Date: Mon, 4 Feb 2013 23:28:30 +0100
Subject: [PATCH] Security fix for create_additions problem 1.6.8
---
CHANGES | 5 +++
Gemfile | 10 ++----
VERSION | 2 +-
ext/json/ext/parser/parser.c | 2 +-
ext/json/ext/parser/parser.rl | 2 +-
java/src/json/ext/Parser.java | 66 +++++++++++++++++++-------------------
java/src/json/ext/Parser.rl | 2 +-
json.gemspec | 8 ++---
json_pure.gemspec | 6 ++--
lib/json/common.rb | 21 ++++++++----
lib/json/pure/parser.rb | 8 ++---
lib/json/version.rb | 2 +-
tests/test_json.rb | 10 ++++--
tests/test_json_addition.rb | 56 ++++++++++++++++++--------------
tests/test_json_string_matching.rb | 11 +++----
15 files changed, 116 insertions(+), 95 deletions(-)
diff --git a/CHANGES b/CHANGES
index b347a7c..811e964 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,8 @@
+2013-02-04 (1.6.8)
+ * Security fix for JSON create_additions default value. It should not be
+ possible to create additions unless
+ explicitely requested by setting the create_additions argument to true or
+ using the JSON.load/dump interface.
2012-04-27 (1.6.7)
* Fix possible crash when trying to parse nil value.
2012-02-11 (1.6.6)
diff --git a/Gemfile b/Gemfile
index 79bafcc..e405da2 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,10 +6,6 @@ gemspec :name => 'json'
gemspec :name => 'json_pure'
gemspec :name => 'json-java'
-group :development, :test do
- gem 'simplecov', :platform => :mri_19
-end
-
-group :test do
- gem 'test-unit', '2.4.7', :platform => :mri_19
-end
+gem 'utils'
+gem 'test-unit'
+gem 'debugger', :platform => :mri_19
diff --git a/VERSION b/VERSION
index 400084b..d8c5e72 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.6.7
+1.6.8
diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c
index c140fdb..cbd8b93 100644
--- a/ext/json/ext/parser/parser.c
+++ b/ext/json/ext/parser/parser.c
@@ -1680,7 +1680,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
if (option_given_p(opts, tmp)) {
json->create_additions = RTEST(rb_hash_aref(opts, tmp));
} else {
- json->create_additions = 1;
+ json->create_additions = 0;
}
tmp = ID2SYM(i_create_id);
if (option_given_p(opts, tmp)) {
diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl
index 20ecc48..f416b2d 100644
--- a/ext/json/ext/parser/parser.rl
+++ b/ext/json/ext/parser/parser.rl
@@ -664,7 +664,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
if (option_given_p(opts, tmp)) {
json->create_additions = RTEST(rb_hash_aref(opts, tmp));
} else {
- json->create_additions = 1;
+ json->create_additions = 0;
}
tmp = ID2SYM(i_create_id);
if (option_given_p(opts, tmp)) {
diff --git a/java/src/json/ext/Parser.java b/java/src/json/ext/Parser.java
index 0058f95..95fb9cf 100644
--- a/java/src/json/ext/Parser.java
+++ b/java/src/json/ext/Parser.java
@@ -166,7 +166,7 @@ public class Parser extends RubyObject {
this.symbolizeNames = opts.getBool("symbolize_names", false);
this.quirksMode = opts.getBool("quirks_mode", false);
this.createId = opts.getString("create_id", getCreateId(context));
- this.createAdditions = opts.getBool("create_additions", true);
+ this.createAdditions = opts.getBool("create_additions", false);
this.objectClass = opts.getClass("object_class", runtime.getHash());
this.arrayClass = opts.getClass("array_class", runtime.getArray());
this.match_string = opts.getHash("match_string");
@@ -1617,14 +1617,14 @@ static final int JSON_array_en_main = 1;
}
-// line 1623 "Parser.java"
+// line 1621 "Parser.java"
{
cs = JSON_array_start;
}
-// line 714 "Parser.rl"
+// line 712 "Parser.rl"
-// line 1630 "Parser.java"
+// line 1628 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -1728,7 +1728,7 @@ case 1:
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 1734 "Parser.java"
+// line 1732 "Parser.java"
}
}
}
@@ -1748,7 +1748,7 @@ case 5:
break; }
}
-// line 715 "Parser.rl"
+// line 713 "Parser.rl"
if (cs >= JSON_array_first_final) {
res.update(result, p + 1);
@@ -1758,7 +1758,7 @@ case 5:
}
-// line 1764 "Parser.java"
+// line 1762 "Parser.java"
private static byte[] init__JSON_object_actions_0()
{
return new byte [] {
@@ -1881,7 +1881,7 @@ static final int JSON_object_error = 0;
static final int JSON_object_en_main = 1;
-// line 774 "Parser.rl"
+// line 772 "Parser.rl"
void parseObject(ParserResult res, int p, int pe) {
@@ -1906,14 +1906,14 @@ static final int JSON_object_en_main = 1;
}
-// line 1912 "Parser.java"
+// line 1910 "Parser.java"
{
cs = JSON_object_start;
}
-// line 798 "Parser.rl"
+// line 796 "Parser.rl"
-// line 1919 "Parser.java"
+// line 1917 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -1994,7 +1994,7 @@ case 1:
switch ( _JSON_object_actions[_acts++] )
{
case 0:
-// line 729 "Parser.rl"
+// line 727 "Parser.rl"
{
parseValue(res, p, pe);
if (res.result == null) {
@@ -2011,7 +2011,7 @@ case 1:
}
break;
case 1:
-// line 744 "Parser.rl"
+// line 742 "Parser.rl"
{
parseString(res, p, pe);
if (res.result == null) {
@@ -2031,13 +2031,13 @@ case 1:
}
break;
case 2:
-// line 762 "Parser.rl"
+// line 760 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 2043 "Parser.java"
+// line 2041 "Parser.java"
}
}
}
@@ -2057,7 +2057,7 @@ case 5:
break; }
}
-// line 799 "Parser.rl"
+// line 797 "Parser.rl"
if (cs < JSON_object_first_final) {
res.update(null, p + 1);
@@ -2090,7 +2090,7 @@ case 5:
}
-// line 2096 "Parser.java"
+// line 2094 "Parser.java"
private static byte[] init__JSON_actions_0()
{
return new byte [] {
@@ -2194,7 +2194,7 @@ static final int JSON_error = 0;
static final int JSON_en_main = 1;
-// line 864 "Parser.rl"
+// line 862 "Parser.rl"
public IRubyObject parseStrict() {
@@ -2204,16 +2204,16 @@ static final int JSON_en_main = 1;
ParserResult res = new ParserResult();
-// line 2210 "Parser.java"
+// line 2208 "Parser.java"
{
cs = JSON_start;
}
-// line 873 "Parser.rl"
+// line 871 "Parser.rl"
p = byteList.begin();
pe = p + byteList.length();
-// line 2219 "Parser.java"
+// line 2217 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -2294,7 +2294,7 @@ case 1:
switch ( _JSON_actions[_acts++] )
{
case 0:
-// line 836 "Parser.rl"
+// line 834 "Parser.rl"
{
currentNesting = 1;
parseObject(res, p, pe);
@@ -2308,7 +2308,7 @@ case 1:
}
break;
case 1:
-// line 848 "Parser.rl"
+// line 846 "Parser.rl"
{
currentNesting = 1;
parseArray(res, p, pe);
@@ -2321,7 +2321,7 @@ case 1:
}
}
break;
-// line 2327 "Parser.java"
+// line 2325 "Parser.java"
}
}
}
@@ -2341,7 +2341,7 @@ case 5:
break; }
}
-// line 876 "Parser.rl"
+// line 874 "Parser.rl"
if (cs >= JSON_first_final && p == pe) {
return result;
@@ -2351,7 +2351,7 @@ case 5:
}
-// line 2357 "Parser.java"
+// line 2355 "Parser.java"
private static byte[] init__JSON_quirks_mode_actions_0()
{
return new byte [] {
@@ -2454,7 +2454,7 @@ static final int JSON_quirks_mode_error = 0;
static final int JSON_quirks_mode_en_main = 1;
-// line 904 "Parser.rl"
+// line 902 "Parser.rl"
public IRubyObject parseQuirksMode() {
@@ -2464,16 +2464,16 @@ static final int JSON_quirks_mode_en_main = 1;
ParserResult res = new ParserResult();
-// line 2470 "Parser.java"
+// line 2468 "Parser.java"
{
cs = JSON_quirks_mode_start;
}
-// line 913 "Parser.rl"
+// line 911 "Parser.rl"
p = byteList.begin();
pe = p + byteList.length();
-// line 2479 "Parser.java"
+// line 2477 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -2554,7 +2554,7 @@ case 1:
switch ( _JSON_quirks_mode_actions[_acts++] )
{
case 0:
-// line 890 "Parser.rl"
+// line 888 "Parser.rl"
{
parseValue(res, p, pe);
if (res.result == null) {
@@ -2566,7 +2566,7 @@ case 1:
}
}
break;
-// line 2572 "Parser.java"
+// line 2570 "Parser.java"
}
}
}
@@ -2586,7 +2586,7 @@ case 5:
break; }
}
-// line 916 "Parser.rl"
+// line 914 "Parser.rl"
if (cs >= JSON_quirks_mode_first_final && p == pe) {
return result;
diff --git a/java/src/json/ext/Parser.rl b/java/src/json/ext/Parser.rl
index 6d9d4f9..4c54cf9 100644
--- a/java/src/json/ext/Parser.rl
+++ b/java/src/json/ext/Parser.rl
@@ -164,7 +164,7 @@ public class Parser extends RubyObject {
this.symbolizeNames = opts.getBool("symbolize_names", false);
this.quirksMode = opts.getBool("quirks_mode", false);
this.createId = opts.getString("create_id", getCreateId(context));
- this.createAdditions = opts.getBool("create_additions", true);
+ this.createAdditions = opts.getBool("create_additions", false);
this.objectClass = opts.getClass("object_class", runtime.getHash());
this.arrayClass = opts.getClass("array_class", runtime.getArray());
this.match_string = opts.getHash("match_string");
diff --git a/json.gemspec b/json.gemspec
index 860f10e..7f7b641 100644
--- a/json.gemspec
+++ b/json.gemspec
@@ -2,21 +2,21 @@
Gem::Specification.new do |s|
s.name = "json"
- s.version = "1.6.7"
+ s.version = "1.6.8"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Florian Frank"]
- s.date = "2012-04-28"
+ s.date = "2013-02-10"
s.description = "This is a JSON implementation as a Ruby extension in C."
s.email = "flori () ping de"
- s.extensions = ["ext/json/ext/parser/extconf.rb", "ext/json/ext/generator/extconf.rb"]
+ s.extensions = ["ext/json/ext/generator/extconf.rb", "ext/json/ext/parser/extconf.rb"]
s.extra_rdoc_files = ["README.rdoc"]
s.files = [".gitignore", ".travis.yml", "CHANGES", "COPYING", "COPYING-json-jruby", "GPL", "Gemfile", "README-json-jruby.markdown", "README.rdoc", "Rakefile", "TODO", "VERSION", "data/example.json", "data/index.html", "data/prototype.js", "diagrams/.keep", "ext/json/ext/fbuffer/fbuffer.h", "ext/json/ext/generator/extconf.rb", "ext/json/ext/generator/generator.c", "ext/json/ext/generator/generator.h", "ext/json/ext/parser/extconf.rb", "ext/json/ext/parser/parser.c", "ext/json/ext/parser/parser.h", "ext/json/ext/parser/parser.rl", "install.rb", "java/src/json/ext/ByteListTranscoder.java", "java/src/json/ext/Generator.java", "java/src/json/ext/GeneratorMethods.java", "java/src/json/ext/GeneratorService.java", "java/src/json/ext/GeneratorState.java", "java/src/json/ext/OptionsReader.java", "java/src/json/ext/Parser.java", "java/src/json/ext/Parser.rl", "java/src/json/ext/ParserService.java", "java/src/json/ext/RuntimeInfo.java", "java/src/json/ext/StringDecoder.java", "java/src/json/ext/StringEncoder.java", "java/src/json/ext/Utils.java", "json-java.gemspec", "json.gemspec", "json_pure.gemspec", "lib/json.rb", "lib/json/add/bigdecimal.rb", "lib/json/add/complex.rb", "lib/json/add/core.rb", "lib/json/add/date.rb", "lib/json/add/date_time.rb", "lib/json/add/exception.rb", "lib/json/add/ostruct.rb", "lib/json/add/range.rb", "lib/json/add/rational.rb", "lib/json/add/regexp.rb", "lib/json/add/struct.rb", "lib/json/add/symbol.rb", "lib/json/add/time.rb", "lib/json/common.rb", "lib/json/ext.rb", "lib/json/ext/.keep", "lib/json/light_object.rb", "lib/json/pure.rb", "lib/json/pure/generator.rb", "lib/json/pure/parser.rb", "lib/json/version.rb", "tests/fixtures/fail1.json", "tests/fixtures/fail10.json", "tests/fixtures/fail11.json", "tests/fixtures/fail12.json", "tests/fixtures/fail13.json", "tests/fixtures/fail14.json", "tests/fixtures/fail18.json", "tests/fixtures/fail19.json", "tests/fixtures/fail2.json", "tests/fixtures/fail20.json", "tests/fixtures/fail21.json", "tests/fixtures/fail22.json", "tests/fixtures/fail23.json", "tests/fixtures/fail24.json", "tests/fixtures/fail25.json", "tests/fixtures/fail27.json", "tests/fixtures/fail28.json", "tests/fixtures/fail3.json", "tests/fixtures/fail4.json", "tests/fixtures/fail5.json", "tests/fixtures/fail6.json", "tests/fixtures/fail7.json", "tests/fixtures/fail8.json", "tests/fixtures/fail9.json", "tests/fixtures/pass1.json", "tests/fixtures/pass15.json", "tests/fixtures/pass16.json", "tests/fixtures/pass17.json", "tests/fixtures/pass2.json", "tests/fixtures/pass26.json", "tests/fixtures/pass3.json", "tests/setup_variant.rb", "tests/test_json.rb", "tests/test_json_addition.rb", "tests/test_json_encoding.rb", "tests/test_json_fixtures.rb", "tests/test_json_generate.rb", "tests/test_json_string_matching.rb", "tests/test_json_unicode.rb", "tools/fuzz.rb", "tools/server.rb", "./tests/test_json_string_matching.rb", "./tests/test_json_fixtures.rb", "./tests/test_json_unicode.rb", "./tests/test_json_addition.rb", "./tests/test_json_generate.rb", "./tests/test_json_encoding.rb", "./tests/test_json.rb"]
s.homepage = "http://flori.github.com/json"
s.rdoc_options = ["--title", "JSON implemention for Ruby", "--main", "README.rdoc"]
s.require_paths = ["ext/json/ext", "ext", "lib"]
s.rubyforge_project = "json"
- s.rubygems_version = "1.8.23"
+ s.rubygems_version = "1.8.25"
s.summary = "JSON Implementation for Ruby"
s.test_files = ["./tests/test_json_string_matching.rb", "./tests/test_json_fixtures.rb", "./tests/test_json_unicode.rb", "./tests/test_json_addition.rb", "./tests/test_json_generate.rb", "./tests/test_json_encoding.rb", "./tests/test_json.rb"]
diff --git a/json_pure.gemspec b/json_pure.gemspec
index 5383c3c..c0f4f23 100644
--- a/json_pure.gemspec
+++ b/json_pure.gemspec
@@ -2,11 +2,11 @@
Gem::Specification.new do |s|
s.name = "json_pure"
- s.version = "1.6.7"
+ s.version = "1.6.8"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Florian Frank"]
- s.date = "2012-04-28"
+ s.date = "2013-02-10"
s.description = "This is a JSON implementation in pure Ruby."
s.email = "flori () ping de"
s.extra_rdoc_files = ["README.rdoc"]
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
s.rdoc_options = ["--title", "JSON implemention for ruby", "--main", "README.rdoc"]
s.require_paths = ["lib"]
s.rubyforge_project = "json"
- s.rubygems_version = "1.8.23"
+ s.rubygems_version = "1.8.25"
s.summary = "JSON Implementation for Ruby"
s.test_files = ["./tests/test_json_string_matching.rb", "./tests/test_json_fixtures.rb", "./tests/test_json_unicode.rb", "./tests/test_json_addition.rb", "./tests/test_json_generate.rb", "./tests/test_json_encoding.rb", "./tests/test_json.rb"]
diff --git a/lib/json/common.rb b/lib/json/common.rb
index e8e76b6..7fd2db3 100644
--- a/lib/json/common.rb
+++ b/lib/json/common.rb
@@ -293,21 +293,28 @@ module JSON
attr_accessor :load_default_options
end
self.load_default_options = {
- :max_nesting => false,
- :allow_nan => true,
- :quirks_mode => true,
+ :max_nesting => false,
+ :allow_nan => true,
+ :quirks_mode => true,
+ :create_additions => true,
}
# Load a ruby data structure from a JSON _source_ and return it. A source can
# either be a string-like object, an IO-like object, or an object responding
# to the read method. If _proc_ was given, it will be called with any nested
- # Ruby object as an argument recursively in depth first order. The default
- # options for the parser can be changed via the load_default_options method.
+ # Ruby object as an argument recursively in depth first order. To modify the
+ # default options pass in the optional _options_ argument as well.
+ #
+ # BEWARE: This method is meant to serialise data from trusted user input,
+ # like from your own database server or clients under your control, it could
+ # be dangerous to allow untrusted users to pass JSON sources into it. The
+ # default options for the parser can be changed via the load_default_options
+ # method.
#
# This method is part of the implementation of the load/dump interface of
# Marshal and YAML.
- def load(source, proc = nil)
- opts = load_default_options
+ def load(source, proc = nil, options = {})
+ opts = load_default_options.merge options
if source.respond_to? :to_str
source = source.to_str
elsif source.respond_to? :to_io
diff --git a/lib/json/pure/parser.rb b/lib/json/pure/parser.rb
index 84eb67f..70a8edc 100644
--- a/lib/json/pure/parser.rb
+++ b/lib/json/pure/parser.rb
@@ -63,9 +63,9 @@ module JSON
# * *symbolize_names*: If set to true, returns symbols for the names
# (keys) in a JSON object. Otherwise strings are returned, which is also
# the default.
- # * *create_additions*: If set to false, the Parser doesn't create
- # additions even if a matchin class and create_id was found. This option
- # defaults to true.
+ # * *create_additions*: If set to true, the Parser creates
+ # additions when if a matching class and create_id was found. This
+ # option defaults to false.
# * *object_class*: Defaults to Hash
# * *array_class*: Defaults to Array
# * *quirks_mode*: Enables quirks_mode for parser, that is for example
@@ -88,7 +88,7 @@ module JSON
if opts.key?(:create_additions)
@create_additions = !!opts[:create_additions]
else
- @create_additions = true
+ @create_additions = false
end
@create_id = @create_additions ? JSON.create_id : nil
@object_class = opts[:object_class] || Hash
diff --git a/lib/json/version.rb b/lib/json/version.rb
index c74e914..d02b58c 100644
--- a/lib/json/version.rb
+++ b/lib/json/version.rb
@@ -1,6 +1,6 @@
module JSON
# JSON version
- VERSION = '1.6.7'
+ VERSION = '1.6.8'
VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
diff --git a/tests/test_json.rb b/tests/test_json.rb
index 4b4bc55..84c0539 100755
--- a/tests/test_json.rb
+++ b/tests/test_json.rb
@@ -329,12 +329,12 @@ class TestJSON < Test::Unit::TestCase
def test_generate_core_subclasses_with_new_to_json
obj = SubHash2["foo" => SubHash2["bar" => true]]
obj_json = JSON(obj)
- obj_again = JSON(obj_json)
+ obj_again = JSON.parse(obj_json, :create_additions => true)
assert_kind_of SubHash2, obj_again
assert_kind_of SubHash2, obj_again['foo']
assert obj_again['foo']['bar']
assert_equal obj, obj_again
- assert_equal ["foo"], JSON(JSON(SubArray2["foo"]))
+ assert_equal ["foo"], JSON(JSON(SubArray2["foo"]), :create_additions => true)
end
def test_generate_core_subclasses_with_default_to_json
@@ -493,6 +493,12 @@ EOT
assert_equal nil, JSON.load('')
end
+ def test_load_with_options
+ small_hash = JSON("foo" => 'bar')
+ symbol_hash = { :foo => 'bar' }
+ assert_equal symbol_hash, JSON.load(small_hash, nil, :symbolize_names => true)
+ end
+
def test_dump
too_deep = '[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]'
assert_equal too_deep, JSON.dump(eval(too_deep))
diff --git a/tests/test_json_addition.rb b/tests/test_json_addition.rb
index cf80866..824a1fa 100755
--- a/tests/test_json_addition.rb
+++ b/tests/test_json_addition.rb
@@ -73,11 +73,19 @@ class TestJSONAddition < Test::Unit::TestCase
a = A.new(666)
assert A.json_creatable?
json = generate(a)
- a_again = JSON.parse(json)
+ a_again = JSON.parse(json, :create_additions => true)
assert_kind_of a.class, a_again
assert_equal a, a_again
end
+ def test_extended_json_default
+ a = A.new(666)
+ assert A.json_creatable?
+ json = generate(a)
+ a_hash = JSON.parse(json)
+ assert_kind_of Hash, a_hash
+ end
+
def test_extended_json_disabled
a = A.new(666)
assert A.json_creatable?
@@ -104,7 +112,7 @@ class TestJSONAddition < Test::Unit::TestCase
c = C.new
assert !C.json_creatable?
json = generate(c)
- assert_raises(ArgumentError, NameError) { JSON.parse(json) }
+ assert_raises(ArgumentError, NameError) { JSON.parse(json, :create_additions => true) }
end
def test_raw_strings
@@ -122,7 +130,7 @@ class TestJSONAddition < Test::Unit::TestCase
assert_match(/\A\{.*\}\Z/, json)
assert_match(/"json_class":"String"/, json)
assert_match(/"raw":\[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255\]/, json)
- raw_again = JSON.parse(json)
+ raw_again = JSON.parse(json, :create_additions => true)
assert_equal raw, raw_again
end
@@ -130,17 +138,17 @@ class TestJSONAddition < Test::Unit::TestCase
def test_core
t = Time.now
- assert_equal t, JSON(JSON(t))
+ assert_equal t, JSON(JSON(t), :create_additions => true)
d = Date.today
- assert_equal d, JSON(JSON(d))
+ assert_equal d, JSON(JSON(d), :create_additions => true)
d = DateTime.civil(2007, 6, 14, 14, 57, 10, Rational(1, 12), 2299161)
- assert_equal d, JSON(JSON(d))
- assert_equal 1..10, JSON(JSON(1..10))
- assert_equal 1...10, JSON(JSON(1...10))
- assert_equal "a".."c", JSON(JSON("a".."c"))
- assert_equal "a"..."c", JSON(JSON("a"..."c"))
+ assert_equal d, JSON(JSON(d), :create_additions => true)
+ assert_equal 1..10, JSON(JSON(1..10), :create_additions => true)
+ assert_equal 1...10, JSON(JSON(1...10), :create_additions => true)
+ assert_equal "a".."c", JSON(JSON("a".."c"), :create_additions => true)
+ assert_equal "a"..."c", JSON(JSON("a"..."c"), :create_additions => true)
s = MyJsonStruct.new 4711, 'foot'
- assert_equal s, JSON(JSON(s))
+ assert_equal s, JSON(JSON(s), :create_additions => true)
struct = Struct.new :foo, :bar
s = struct.new 4711, 'foot'
assert_raises(JSONError) { JSON(s) }
@@ -148,41 +156,41 @@ class TestJSONAddition < Test::Unit::TestCase
raise TypeError, "test me"
rescue TypeError => e
e_json = JSON.generate e
- e_again = JSON e_json
+ e_again = JSON e_json, :create_additions => true
assert_kind_of TypeError, e_again
assert_equal e.message, e_again.message
assert_equal e.backtrace, e_again.backtrace
end
- assert_equal(/foo/, JSON(JSON(/foo/)))
- assert_equal(/foo/i, JSON(JSON(/foo/i)))
+ assert_equal(/foo/, JSON(JSON(/foo/), :create_additions => true))
+ assert_equal(/foo/i, JSON(JSON(/foo/i), :create_additions => true))
end
def test_utc_datetime
now = Time.now
- d = DateTime.parse(now.to_s) # usual case
- assert_equal d, JSON.parse(d.to_json)
+ d = DateTime.parse(now.to_s, :create_additions => true) # usual case
+ assert_equal d, JSON.parse(d.to_json, :create_additions => true)
d = DateTime.parse(now.utc.to_s) # of = 0
- assert_equal d, JSON.parse(d.to_json)
+ assert_equal d, JSON.parse(d.to_json, :create_additions => true)
d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(1,24))
- assert_equal d, JSON.parse(d.to_json)
+ assert_equal d, JSON.parse(d.to_json, :create_additions => true)
d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(12,24))
- assert_equal d, JSON.parse(d.to_json)
+ assert_equal d, JSON.parse(d.to_json, :create_additions => true)
end
def test_rational_complex
- assert_equal Rational(2, 9), JSON(JSON(Rational(2, 9)))
- assert_equal Complex(2, 9), JSON(JSON(Complex(2, 9)))
+ assert_equal Rational(2, 9), JSON.parse(JSON(Rational(2, 9)), :create_additions => true)
+ assert_equal Complex(2, 9), JSON.parse(JSON(Complex(2, 9)), :create_additions => true)
end
def test_bigdecimal
- assert_equal BigDecimal('3.141', 23), JSON(JSON(BigDecimal('3.141', 23)))
- assert_equal BigDecimal('3.141', 666), JSON(JSON(BigDecimal('3.141', 666)))
+ assert_equal BigDecimal('3.141', 23), JSON(JSON(BigDecimal('3.141', 23)), :create_additions => true)
+ assert_equal BigDecimal('3.141', 666), JSON(JSON(BigDecimal('3.141', 666)), :create_additions => true)
end
def test_ostruct
o = OpenStruct.new
# XXX this won't work; o.foo = { :bar => true }
o.foo = { 'bar' => true }
- assert_equal o, JSON(JSON(o))
+ assert_equal o, JSON.parse(JSON(o), :create_additions => true)
end
end
diff --git a/tests/test_json_string_matching.rb b/tests/test_json_string_matching.rb
index b8a7169..7f2148e 100644
--- a/tests/test_json_string_matching.rb
+++ b/tests/test_json_string_matching.rb
@@ -27,14 +27,13 @@ class TestJSONStringMatching < Test::Unit::TestCase
t = TestTime.new
t_json = [ t ].to_json
assert_equal [ t ],
- JSON.parse(t_json,
- :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\Z/ => TestTime })
+ JSON.parse(t_json, :create_additions => true,
+ :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime })
assert_equal [ t.strftime('%FT%T%z') ],
- JSON.parse(t_json,
- :match_string => { /\A\d{3}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\Z/ => TestTime })
+ JSON.parse(t_json, :create_additions => true,
+ :match_string => { /\A\d{3}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime })
assert_equal [ t.strftime('%FT%T%z') ],
JSON.parse(t_json,
- :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\Z/ => TestTime },
- :create_additions => false)
+ :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime })
end
end
--
1.8.1.2
1-7-denial-of-service.patch
Description:
From a26f7e96b52efe0be508e223cd31f97ed04099ea Mon Sep 17 00:00:00 2001
From: Florian Frank <flori () ping de>
Date: Mon, 4 Feb 2013 23:28:30 +0100
Subject: [PATCH] Security fix create_additons/JSON::GenericObject
---
CHANGES | 8 ++++++
Gemfile | 1 +
ext/json/ext/parser/parser.c | 2 +-
ext/json/ext/parser/parser.rl | 2 +-
java/src/json/ext/Parser.java | 2 +-
java/src/json/ext/Parser.rl | 2 +-
json.gemspec | 2 +-
json_pure.gemspec | 2 +-
lib/json/common.rb | 21 +++++++++-----
lib/json/generic_object.rb | 7 +++++
lib/json/pure/parser.rb | 8 +++---
tests/test_json.rb | 10 +++++--
tests/test_json_addition.rb | 56 ++++++++++++++++++++++----------------
tests/test_json_generic_object.rb | 30 ++++++++++++++------
tests/test_json_string_matching.rb | 7 ++---
15 files changed, 105 insertions(+), 55 deletions(-)
diff --git a/CHANGES b/CHANGES
index a8c0b35..e3d12a7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,12 @@
2013-02-04 (1.7.7)
+ * Security fix for JSON create_additions default value and
+ JSON::GenericObject. It should not be possible to create additions unless
+ explicitely requested by setting the create_additions argument to true or
+ using the JSON.load/dump interface. If JSON::GenericObject is supposed to
+ be automatically deserialised, this has to be explicitely enabled by
+ setting
+ JSON::GenericObject.json_createble = true
+ as well.
* Remove useless assert in fbuffer implementation.
* Apply patch attached to https://github.com/flori/json/issues#issue/155
provided by John Shahid <jvshahid () gmail com>, Thx!
diff --git a/Gemfile b/Gemfile
index 98d7837..e405da2 100644
--- a/Gemfile
+++ b/Gemfile
@@ -8,3 +8,4 @@ gemspec :name => 'json-java'
gem 'utils'
gem 'test-unit'
+gem 'debugger', :platform => :mri_19
diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c
index 8442d21..df89f2c 100644
--- a/ext/json/ext/parser/parser.c
+++ b/ext/json/ext/parser/parser.c
@@ -1680,7 +1680,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
if (option_given_p(opts, tmp)) {
json->create_additions = RTEST(rb_hash_aref(opts, tmp));
} else {
- json->create_additions = 1;
+ json->create_additions = 0;
}
tmp = ID2SYM(i_create_id);
if (option_given_p(opts, tmp)) {
diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl
index 6138a6f..ab8d318 100644
--- a/ext/json/ext/parser/parser.rl
+++ b/ext/json/ext/parser/parser.rl
@@ -664,7 +664,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
if (option_given_p(opts, tmp)) {
json->create_additions = RTEST(rb_hash_aref(opts, tmp));
} else {
- json->create_additions = 1;
+ json->create_additions = 0;
}
tmp = ID2SYM(i_create_id);
if (option_given_p(opts, tmp)) {
diff --git a/java/src/json/ext/Parser.java b/java/src/json/ext/Parser.java
index ab3585e..6cb5886 100644
--- a/java/src/json/ext/Parser.java
+++ b/java/src/json/ext/Parser.java
@@ -166,7 +166,7 @@ public class Parser extends RubyObject {
this.symbolizeNames = opts.getBool("symbolize_names", false);
this.quirksMode = opts.getBool("quirks_mode", false);
this.createId = opts.getString("create_id", getCreateId(context));
- this.createAdditions = opts.getBool("create_additions", true);
+ this.createAdditions = opts.getBool("create_additions", false);
this.objectClass = opts.getClass("object_class", runtime.getHash());
this.arrayClass = opts.getClass("array_class", runtime.getArray());
this.match_string = opts.getHash("match_string");
diff --git a/java/src/json/ext/Parser.rl b/java/src/json/ext/Parser.rl
index e26637d..6dd335a 100644
--- a/java/src/json/ext/Parser.rl
+++ b/java/src/json/ext/Parser.rl
@@ -164,7 +164,7 @@ public class Parser extends RubyObject {
this.symbolizeNames = opts.getBool("symbolize_names", false);
this.quirksMode = opts.getBool("quirks_mode", false);
this.createId = opts.getString("create_id", getCreateId(context));
- this.createAdditions = opts.getBool("create_additions", true);
+ this.createAdditions = opts.getBool("create_additions", false);
this.objectClass = opts.getClass("object_class", runtime.getHash());
this.arrayClass = opts.getClass("array_class", runtime.getArray());
this.match_string = opts.getHash("match_string");
diff --git a/json.gemspec b/json.gemspec
index fb52be8..8d7c693 100644
--- a/json.gemspec
+++ b/json.gemspec
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Florian Frank"]
- s.date = "2013-02-04"
+ s.date = "2013-02-10"
s.description = "This is a JSON implementation as a Ruby extension in C."
s.email = "flori () ping de"
s.extensions = ["ext/json/ext/generator/extconf.rb", "ext/json/ext/parser/extconf.rb"]
diff --git a/json_pure.gemspec b/json_pure.gemspec
index 1d4b4c0..0d696c9 100644
--- a/json_pure.gemspec
+++ b/json_pure.gemspec
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Florian Frank"]
- s.date = "2013-02-04"
+ s.date = "2013-02-10"
s.description = "This is a JSON implementation in pure Ruby."
s.email = "flori () ping de"
s.extra_rdoc_files = ["README.rdoc"]
diff --git a/lib/json/common.rb b/lib/json/common.rb
index 03892d9..65a74a1 100644
--- a/lib/json/common.rb
+++ b/lib/json/common.rb
@@ -299,21 +299,28 @@ module JSON
attr_accessor :load_default_options
end
self.load_default_options = {
- :max_nesting => false,
- :allow_nan => true,
- :quirks_mode => true,
+ :max_nesting => false,
+ :allow_nan => true,
+ :quirks_mode => true,
+ :create_additions => true,
}
# Load a ruby data structure from a JSON _source_ and return it. A source can
# either be a string-like object, an IO-like object, or an object responding
# to the read method. If _proc_ was given, it will be called with any nested
- # Ruby object as an argument recursively in depth first order. The default
- # options for the parser can be changed via the load_default_options method.
+ # Ruby object as an argument recursively in depth first order. To modify the
+ # default options pass in the optional _options_ argument as well.
+ #
+ # BEWARE: This method is meant to serialise data from trusted user input,
+ # like from your own database server or clients under your control, it could
+ # be dangerous to allow untrusted users to pass JSON sources into it. The
+ # default options for the parser can be changed via the load_default_options
+ # method.
#
# This method is part of the implementation of the load/dump interface of
# Marshal and YAML.
- def load(source, proc = nil)
- opts = load_default_options
+ def load(source, proc = nil, options = {})
+ opts = load_default_options.merge options
if source.respond_to? :to_str
source = source.to_str
elsif source.respond_to? :to_io
diff --git a/lib/json/generic_object.rb b/lib/json/generic_object.rb
index cd93e1a..8b1074c 100644
--- a/lib/json/generic_object.rb
+++ b/lib/json/generic_object.rb
@@ -5,6 +5,12 @@ module JSON
class << self
alias [] new
+ def json_creatable?
+ @json_creatable
+ end
+
+ attr_writer :json_creatable
+
def json_create(data)
data = data.dup
data.delete JSON.create_id
@@ -26,6 +32,7 @@ module JSON
end
end
end
+ self.json_creatable = false
def to_hash
table
diff --git a/lib/json/pure/parser.rb b/lib/json/pure/parser.rb
index cb249b2..a41d1ee 100644
--- a/lib/json/pure/parser.rb
+++ b/lib/json/pure/parser.rb
@@ -63,9 +63,9 @@ module JSON
# * *symbolize_names*: If set to true, returns symbols for the names
# (keys) in a JSON object. Otherwise strings are returned, which is also
# the default.
- # * *create_additions*: If set to false, the Parser doesn't create
- # additions even if a matchin class and create_id was found. This option
- # defaults to true.
+ # * *create_additions*: If set to true, the Parser creates
+ # additions when if a matching class and create_id was found. This
+ # option defaults to false.
# * *object_class*: Defaults to Hash
# * *array_class*: Defaults to Array
# * *quirks_mode*: Enables quirks_mode for parser, that is for example
@@ -88,7 +88,7 @@ module JSON
if opts.key?(:create_additions)
@create_additions = !!opts[:create_additions]
else
- @create_additions = true
+ @create_additions = false
end
@create_id = @create_additions ? JSON.create_id : nil
@object_class = opts[:object_class] || Hash
diff --git a/tests/test_json.rb b/tests/test_json.rb
index be974cd..6af6b32 100755
--- a/tests/test_json.rb
+++ b/tests/test_json.rb
@@ -329,12 +329,12 @@ class TestJSON < Test::Unit::TestCase
def test_generate_core_subclasses_with_new_to_json
obj = SubHash2["foo" => SubHash2["bar" => true]]
obj_json = JSON(obj)
- obj_again = JSON(obj_json)
+ obj_again = JSON.parse(obj_json, :create_additions => true)
assert_kind_of SubHash2, obj_again
assert_kind_of SubHash2, obj_again['foo']
assert obj_again['foo']['bar']
assert_equal obj, obj_again
- assert_equal ["foo"], JSON(JSON(SubArray2["foo"]))
+ assert_equal ["foo"], JSON(JSON(SubArray2["foo"]), :create_additions => true)
end
def test_generate_core_subclasses_with_default_to_json
@@ -493,6 +493,12 @@ EOT
assert_equal nil, JSON.load('')
end
+ def test_load_with_options
+ small_hash = JSON("foo" => 'bar')
+ symbol_hash = { :foo => 'bar' }
+ assert_equal symbol_hash, JSON.load(small_hash, nil, :symbolize_names => true)
+ end
+
def test_dump
too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'
assert_equal too_deep, JSON.dump(eval(too_deep))
diff --git a/tests/test_json_addition.rb b/tests/test_json_addition.rb
index 707aa32..a30f06a 100755
--- a/tests/test_json_addition.rb
+++ b/tests/test_json_addition.rb
@@ -73,11 +73,19 @@ class TestJSONAddition < Test::Unit::TestCase
a = A.new(666)
assert A.json_creatable?
json = generate(a)
- a_again = JSON.parse(json)
+ a_again = JSON.parse(json, :create_additions => true)
assert_kind_of a.class, a_again
assert_equal a, a_again
end
+ def test_extended_json_default
+ a = A.new(666)
+ assert A.json_creatable?
+ json = generate(a)
+ a_hash = JSON.parse(json)
+ assert_kind_of Hash, a_hash
+ end
+
def test_extended_json_disabled
a = A.new(666)
assert A.json_creatable?
@@ -104,7 +112,7 @@ class TestJSONAddition < Test::Unit::TestCase
c = C.new
assert !C.json_creatable?
json = generate(c)
- assert_raises(ArgumentError, NameError) { JSON.parse(json) }
+ assert_raises(ArgumentError, NameError) { JSON.parse(json, :create_additions => true) }
end
def test_raw_strings
@@ -122,7 +130,7 @@ class TestJSONAddition < Test::Unit::TestCase
assert_match(/\A\{.*\}\z/, json)
assert_match(/"json_class":"String"/, json)
assert_match(/"raw":\[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255\]/, json)
- raw_again = JSON.parse(json)
+ raw_again = JSON.parse(json, :create_additions => true)
assert_equal raw, raw_again
end
@@ -130,17 +138,17 @@ class TestJSONAddition < Test::Unit::TestCase
def test_core
t = Time.now
- assert_equal t, JSON(JSON(t))
+ assert_equal t, JSON(JSON(t), :create_additions => true)
d = Date.today
- assert_equal d, JSON(JSON(d))
+ assert_equal d, JSON(JSON(d), :create_additions => true)
d = DateTime.civil(2007, 6, 14, 14, 57, 10, Rational(1, 12), 2299161)
- assert_equal d, JSON(JSON(d))
- assert_equal 1..10, JSON(JSON(1..10))
- assert_equal 1...10, JSON(JSON(1...10))
- assert_equal "a".."c", JSON(JSON("a".."c"))
- assert_equal "a"..."c", JSON(JSON("a"..."c"))
+ assert_equal d, JSON(JSON(d), :create_additions => true)
+ assert_equal 1..10, JSON(JSON(1..10), :create_additions => true)
+ assert_equal 1...10, JSON(JSON(1...10), :create_additions => true)
+ assert_equal "a".."c", JSON(JSON("a".."c"), :create_additions => true)
+ assert_equal "a"..."c", JSON(JSON("a"..."c"), :create_additions => true)
s = MyJsonStruct.new 4711, 'foot'
- assert_equal s, JSON(JSON(s))
+ assert_equal s, JSON(JSON(s), :create_additions => true)
struct = Struct.new :foo, :bar
s = struct.new 4711, 'foot'
assert_raises(JSONError) { JSON(s) }
@@ -148,41 +156,41 @@ class TestJSONAddition < Test::Unit::TestCase
raise TypeError, "test me"
rescue TypeError => e
e_json = JSON.generate e
- e_again = JSON e_json
+ e_again = JSON e_json, :create_additions => true
assert_kind_of TypeError, e_again
assert_equal e.message, e_again.message
assert_equal e.backtrace, e_again.backtrace
end
- assert_equal(/foo/, JSON(JSON(/foo/)))
- assert_equal(/foo/i, JSON(JSON(/foo/i)))
+ assert_equal(/foo/, JSON(JSON(/foo/), :create_additions => true))
+ assert_equal(/foo/i, JSON(JSON(/foo/i), :create_additions => true))
end
def test_utc_datetime
now = Time.now
- d = DateTime.parse(now.to_s) # usual case
- assert_equal d, JSON.parse(d.to_json)
+ d = DateTime.parse(now.to_s, :create_additions => true) # usual case
+ assert_equal d, JSON.parse(d.to_json, :create_additions => true)
d = DateTime.parse(now.utc.to_s) # of = 0
- assert_equal d, JSON.parse(d.to_json)
+ assert_equal d, JSON.parse(d.to_json, :create_additions => true)
d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(1,24))
- assert_equal d, JSON.parse(d.to_json)
+ assert_equal d, JSON.parse(d.to_json, :create_additions => true)
d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(12,24))
- assert_equal d, JSON.parse(d.to_json)
+ assert_equal d, JSON.parse(d.to_json, :create_additions => true)
end
def test_rational_complex
- assert_equal Rational(2, 9), JSON(JSON(Rational(2, 9)))
- assert_equal Complex(2, 9), JSON(JSON(Complex(2, 9)))
+ assert_equal Rational(2, 9), JSON.parse(JSON(Rational(2, 9)), :create_additions => true)
+ assert_equal Complex(2, 9), JSON.parse(JSON(Complex(2, 9)), :create_additions => true)
end
def test_bigdecimal
- assert_equal BigDecimal('3.141', 23), JSON(JSON(BigDecimal('3.141', 23)))
- assert_equal BigDecimal('3.141', 666), JSON(JSON(BigDecimal('3.141', 666)))
+ assert_equal BigDecimal('3.141', 23), JSON(JSON(BigDecimal('3.141', 23)), :create_additions => true)
+ assert_equal BigDecimal('3.141', 666), JSON(JSON(BigDecimal('3.141', 666)), :create_additions => true)
end
def test_ostruct
o = OpenStruct.new
# XXX this won't work; o.foo = { :bar => true }
o.foo = { 'bar' => true }
- assert_equal o, JSON(JSON(o))
+ assert_equal o, JSON.parse(JSON(o), :create_additions => true)
end
end
diff --git a/tests/test_json_generic_object.rb b/tests/test_json_generic_object.rb
index 83093b8..77ef22e 100644
--- a/tests/test_json_generic_object.rb
+++ b/tests/test_json_generic_object.rb
@@ -20,17 +20,22 @@ class TestJSONGenericObject < Test::Unit::TestCase
end
def test_generate_json
- assert_equal @go, JSON(JSON(@go))
+ switch_json_creatable do
+ assert_equal @go, JSON(JSON(@go), :create_additions => true)
+ end
end
def test_parse_json
- assert_equal @go, l = JSON('{ "json_class": "JSON::GenericObject", "a": 1, "b": 2 }')
- assert_equal 1, l.a
- assert_equal @go, l = JSON('{ "a": 1, "b": 2 }', :object_class => GenericObject)
- assert_equal 1, l.a
- assert_equal GenericObject[:a => GenericObject[:b => 2]],
- l = JSON('{ "a": { "b": 2 } }', :object_class => GenericObject)
- assert_equal 2, l.a.b
+ assert_kind_of Hash, JSON('{ "json_class": "JSON::GenericObject", "a": 1, "b": 2 }', :create_additions => true)
+ switch_json_creatable do
+ assert_equal @go, l = JSON('{ "json_class": "JSON::GenericObject", "a": 1, "b": 2 }', :create_additions => true)
+ assert_equal 1, l.a
+ assert_equal @go, l = JSON('{ "a": 1, "b": 2 }', :object_class => GenericObject)
+ assert_equal 1, l.a
+ assert_equal GenericObject[:a => GenericObject[:b => 2]],
+ l = JSON('{ "a": { "b": 2 } }', :object_class => GenericObject)
+ assert_equal 2, l.a.b
+ end
end
def test_from_hash
@@ -43,4 +48,13 @@ class TestJSONGenericObject < Test::Unit::TestCase
assert_equal true, result.foo.quux.first.foobar
assert_equal true, GenericObject.from_hash(true)
end
+
+ private
+
+ def switch_json_creatable
+ JSON::GenericObject.json_creatable = true
+ yield
+ ensure
+ JSON::GenericObject.json_creatable = false
+ end
end
diff --git a/tests/test_json_string_matching.rb b/tests/test_json_string_matching.rb
index 2ddedfa..c233df8 100644
--- a/tests/test_json_string_matching.rb
+++ b/tests/test_json_string_matching.rb
@@ -27,14 +27,13 @@ class TestJSONStringMatching < Test::Unit::TestCase
t = TestTime.new
t_json = [ t ].to_json
assert_equal [ t ],
- JSON.parse(t_json,
+ JSON.parse(t_json, :create_additions => true,
:match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime })
assert_equal [ t.strftime('%FT%T%z') ],
- JSON.parse(t_json,
+ JSON.parse(t_json, :create_additions => true,
:match_string => { /\A\d{3}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime })
assert_equal [ t.strftime('%FT%T%z') ],
JSON.parse(t_json,
- :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime },
- :create_additions => false)
+ :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime })
end
end
--
1.8.1.2