From 1e5370a6dbed55df520ab2b9a5a0123c68569360 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Mon, 22 Oct 2012 18:52:13 +0100 Subject: [PATCH] updated to use latest version of ruby_parser, ruby2ruby, and sexp_processor --- Gemfile | 11 +++++---- Gemfile.lock | 46 +++++++++++++++++++++++++------------- Rakefile | 20 ++++++++++++----- lib/safemode/blankslate.rb | 4 ++-- lib/safemode/core_jails.rb | 4 ++-- lib/safemode/parser.rb | 37 ++++++++++++++++++++---------- lib/safemode/scope.rb | 6 ++--- safemode.gemspec | 19 +++++++++------- test/test_erb_eval.rb | 2 +- test/test_helper.rb | 9 ++++++++ test/test_jail.rb | 4 ++-- test/test_safemode_eval.rb | 2 +- 12 files changed, 107 insertions(+), 57 deletions(-) diff --git a/Gemfile b/Gemfile index 1ff26ca..1578461 100644 --- a/Gemfile +++ b/Gemfile @@ -1,15 +1,18 @@ source "http://rubygems.org" -gem "ruby2ruby" -gem "ruby_parser" +gem 'sexp_processor', ">= 4.1.2" +gem 'ruby2ruby', ">= 2.0.1" +gem "ruby_parser", ">= 3.0.1" # Add dependencies to develop your gem here. # Include everything needed to run rake, tests, features, etc. group :development do gem "shoulda", ">= 0" gem "rdoc", "~> 3.12" - gem "bundler", "~> 1.0.0" + gem "bundler", "~> 1.0" gem "jeweler", "~> 1.8.3" - gem "rcov", ">= 0" + gem "rcov", :platforms => :ruby_18 + gem "simplecov", :platforms => :ruby_19 + gem "test-unit", :platforms => :ruby_19 gem "rake" end diff --git a/Gemfile.lock b/Gemfile.lock index 98c77d5..696e96c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,38 +1,52 @@ GEM remote: http://rubygems.org/ specs: + activesupport (3.2.8) + i18n (~> 0.6) + multi_json (~> 1.0) git (1.2.5) - jeweler (1.8.3) + i18n (0.6.1) + jeweler (1.8.4) bundler (~> 1.0) git (>= 1.2.5) rake rdoc - json (1.6.5) + json (1.7.5) + multi_json (1.3.6) rake (0.9.2.2) rcov (1.0.0) rdoc (3.12) json (~> 1.4) - ruby2ruby (1.3.1) - ruby_parser (~> 2.0) - sexp_processor (~> 3.0) - ruby_parser (2.3.1) - sexp_processor (~> 3.0) - sexp_processor (3.1.0) - shoulda (3.0.1) - shoulda-context (~> 1.0.0) - shoulda-matchers (~> 1.0.0) - shoulda-context (1.0.0) - shoulda-matchers (1.0.0) + ruby2ruby (2.0.1) + ruby_parser (~> 3.0.0) + sexp_processor (~> 4.0) + ruby_parser (3.0.1) + sexp_processor (~> 4.1) + sexp_processor (4.1.2) + shoulda (3.3.2) + shoulda-context (~> 1.0.1) + shoulda-matchers (~> 1.4.1) + shoulda-context (1.0.1) + shoulda-matchers (1.4.1) + activesupport (>= 3.0.0) + simplecov (0.7.1) + multi_json (~> 1.0) + simplecov-html (~> 0.7.1) + simplecov-html (0.7.1) + test-unit (2.5.2) PLATFORMS ruby DEPENDENCIES - bundler (~> 1.0.0) + bundler (~> 1.0) jeweler (~> 1.8.3) rake rcov rdoc (~> 3.12) - ruby2ruby - ruby_parser + ruby2ruby (>= 2.0.1) + ruby_parser (>= 3.0.1) + sexp_processor (>= 4.1.2) shoulda + simplecov + test-unit diff --git a/Rakefile b/Rakefile index 7618d0b..f49f157 100644 --- a/Rakefile +++ b/Rakefile @@ -46,12 +46,20 @@ Rake::TestTask.new(:test) do |test| test.verbose = true end -require 'rcov/rcovtask' -Rcov::RcovTask.new do |test| - test.libs << 'test' - test.pattern = 'test/**/test_*.rb' - test.verbose = true - test.rcov_opts << '--exclude "gems/*"' +if RUBY_VERSION >= "1.9" + desc "Generate coverage report for tests" + task :coverage do |cov| + ENV['COVERAGE'] = 'true' + Rake::Task[:test].execute + end +else + require 'rcov/rcovtask' + Rcov::RcovTask.new do |test| + test.libs << 'test' + test.pattern = 'test/**/test_*.rb' + test.verbose = true + test.rcov_opts << '--exclude "gems/*"' + end end task :default => :test diff --git a/lib/safemode/blankslate.rb b/lib/safemode/blankslate.rb index d1a7954..19dee00 100644 --- a/lib/safemode/blankslate.rb +++ b/lib/safemode/blankslate.rb @@ -3,9 +3,9 @@ class Blankslate @@allow_instance_methods = ['class', 'inspect', 'methods', 'respond_to?', 'to_s', 'instance_variable_get'] @@allow_class_methods = ['methods', 'new', 'name', 'inspect', '<', 'ancestors', '=='] # < needed in Rails Object#subclasses_of - silently { undef_methods(*instance_methods - @@allow_instance_methods) } + silently { undef_methods(*instance_methods.map(&:to_s) - @@allow_instance_methods) } class << self - silently { undef_methods(*instance_methods - @@allow_class_methods) } + silently { undef_methods(*instance_methods.map(&:to_s) - @@allow_class_methods) } def method_added(name) end # ActiveSupport needs this diff --git a/lib/safemode/core_jails.rb b/lib/safemode/core_jails.rb index f6a04bf..b7d428f 100644 --- a/lib/safemode/core_jails.rb +++ b/lib/safemode/core_jails.rb @@ -22,7 +22,7 @@ def core_classes end def core_jail_methods(klass) - @@methods_whitelist[klass.name] + (@@default_methods & klass.instance_methods) + @@methods_whitelist[klass.name] + (@@default_methods & klass.instance_methods.map(&:to_s)) end end @@ -67,7 +67,7 @@ def core_jail_methods(klass) 'String' => %w(blank? capitalize capitalize! casecmp center chomp chomp! chop chop! concat count crypt delete delete! downcase - downcase! dump each each_byte each_line empty? end_with? gsub + downcase! dump each_byte each_line empty? end_with? force_encoding gsub gsub! hash hex include? index insert intern iseuc issjis isutf8 kconv length ljust lstrip lstrip! match next next! oct reverse reverse! rindex rjust rstrip rstrip! scan size slice diff --git a/lib/safemode/parser.rb b/lib/safemode/parser.rb index a1516aa..55bbef4 100644 --- a/lib/safemode/parser.rb +++ b/lib/safemode/parser.rb @@ -36,7 +36,7 @@ def process_call(exp) receiver = jail process_call_receiver(exp) name = exp.shift args = process_call_args(exp) - process_call_code(receiver, name, args) + process_call_code(receiver, name, args) end def process_fcall(exp) @@ -79,6 +79,8 @@ def process_iasgn(exp) :iasgn, # iasgn is sometimes allowed # not sure about self ... :self, + # :args is now used for block parameters + :args, # unnecessarily advanced? :argscat, :argspush, :splat, :block_pass, :op_asgn1, :op_asgn2, :op_asgn_and, :op_asgn_or, @@ -86,9 +88,10 @@ def process_iasgn(exp) :block ] disallowed = [ # :self, # self doesn't seem to be needed for vcalls? - :const, :defn, :defs, :alias, :valias, :undef, :class, :attrset, + # see below for :const handling + :defn, :defs, :alias, :valias, :undef, :class, :attrset, :module, :sclass, :colon2, :colon3, - :fbody, :scope, :args, :block_arg, :postexe, + :fbody, :scope, :block_arg, :postexe, :redo, :retry, :begin, :rescue, :resbody, :ensure, :defined, :super, :zsuper, :return, :dmethod, :bmethod, :to_ary, :svalue, :match, @@ -102,11 +105,18 @@ def process_iasgn(exp) # :ifunc, :method, :last, :opt_n, :cfunc, :newline, :alloca, :memo, :cref disallowed.each do |name| - define_method "process_#{name}" do - code = super + define_method "process_#{name}" do |arg| + code = super(arg) raise_security_error(name, code) end end + + # handling of Encoding constants in ruby 1.9. + # Note: ruby_parser evaluates __ENCODING__ to :const Encoding::UTF_8 + def process_const(arg) + raise_security_error("constant", super(arg)) unless (RUBY_VERSION >= "1.9" and arg.sexp_type.class == Encoding) + "Encoding::#{super(arg).gsub('-', '_')}" + end def raise_security_error(type, info) raise Safemode::SecurityError.new(type, info) @@ -124,14 +134,17 @@ def process_call_receiver(exp) end def process_call_args(exp) - args_exp = exp.shift rescue nil - if args_exp && args_exp.first == :array # FIX - args = "#{process(args_exp)[1..-2]}" - else - args = process args_exp - args = nil if args.empty? + args = [] + while not exp.empty? do + args_exp = exp.shift + if args_exp && args_exp.first == :array # FIX + processed = "#{process(args_exp)[1..-2]}" + else + processed = process args_exp + end + args << processed unless (processed.nil? or processed.empty?) end - args + args.empty? ? nil : args.join(", ") end def process_call_code(receiver, name, args) diff --git a/lib/safemode/scope.rb b/lib/safemode/scope.rb index a70a804..1c3ab6d 100644 --- a/lib/safemode/scope.rb +++ b/lib/safemode/scope.rb @@ -29,10 +29,10 @@ def print(*args) def output @_safemode_output end - + def method_missing(method, *args, &block) if @locals.has_key?(method) - @locals[method] + @locals[method] elsif @delegate_methods.include?(method) @delegate.send method, *unjail_args(args), &block else @@ -54,5 +54,5 @@ def unjail_args(args) arg.class.name =~ /::Jail$/ ? arg.instance_variable_get(:@source) : arg end end - end + end end diff --git a/safemode.gemspec b/safemode.gemspec index 9671613..cf02bca 100644 --- a/safemode.gemspec +++ b/safemode.gemspec @@ -5,11 +5,11 @@ Gem::Specification.new do |s| s.name = "safemode" - s.version = "1.0.1" + s.version = "1.0.2" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Sven Fuchs", "Peter Cooper", "Matthias Viehweger", "Kingsley Hendrickse", "Ohad Levy"] - s.date = "2012-03-16" + s.date = "2012-10-24" s.description = "A library for safe evaluation of Ruby code based on RubyParser and Ruby2Ruby. Provides Rails ActionView template handlers for ERB and Haml." s.email = "ohadlevy@gmail.com" s.extra_rdoc_files = [ @@ -56,31 +56,34 @@ Gem::Specification.new do |s| s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_runtime_dependency(%q, [">= 0"]) - s.add_runtime_dependency(%q, [">= 0"]) + s.add_runtime_dependency(%q, [">= 2.0.0.b1"]) + s.add_runtime_dependency(%q, [">= 3.0.0.a9"]) s.add_development_dependency(%q, [">= 0"]) s.add_development_dependency(%q, ["~> 3.12"]) s.add_development_dependency(%q, ["~> 1.0.0"]) s.add_development_dependency(%q, ["~> 1.8.3"]) s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0"]) s.add_development_dependency(%q, [">= 0"]) else - s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 2.0.0.b1"]) + s.add_dependency(%q, [">= 3.0.0.a9"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, ["~> 3.12"]) s.add_dependency(%q, ["~> 1.0.0"]) s.add_dependency(%q, ["~> 1.8.3"]) + s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) end else - s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 2.0.0.b1"]) + s.add_dependency(%q, [">= 3.0.0.a9"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, ["~> 3.12"]) s.add_dependency(%q, ["~> 1.0.0"]) s.add_dependency(%q, ["~> 1.8.3"]) + s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) end diff --git a/test/test_erb_eval.rb b/test/test_erb_eval.rb index 409296d..0754a89 100644 --- a/test/test_erb_eval.rb +++ b/test/test_erb_eval.rb @@ -73,4 +73,4 @@ def test_calling_#{call.gsub(/[\W]/, '_')}_should_raise_security ) end -end \ No newline at end of file +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 0a87c8d..a4956b5 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,3 +1,8 @@ +if RUBY_VERSION >= '1.9'and ENV['COVERAGE'] + require 'simplecov' + SimpleCov.start {add_filter 'test_'} +end + $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib') require 'rubygems' @@ -96,6 +101,10 @@ def to_jail def comments [Comment.new(self), Comment.new(self)] end + + def method_missing(method, *args, &block) + super(method, *args, &block) + end end class Comment diff --git a/test/test_jail.rb b/test/test_jail.rb index f192658..dfd4879 100644 --- a/test/test_jail.rb +++ b/test/test_jail.rb @@ -21,7 +21,7 @@ def test_sending_to_jail_to_an_object_should_return_a_jail def test_jail_instances_should_have_limited_methods expected = ["class", "inspect", "method_missing", "methods", "respond_to?", "to_jail", "to_s", "instance_variable_get"] objects.each do |object| - assert_equal expected.sort, reject_pretty_methods(object.to_jail.methods.sort) + assert_equal expected.sort, reject_pretty_methods(object.to_jail.methods.map(&:to_s).sort) end end @@ -32,7 +32,7 @@ def test_jail_classes_should_have_limited_methods "ancestors", "==" # ancestors and == needed in Rails::Generator::Spec#lookup_class ] objects.each do |object| - assert_equal expected.sort, reject_pretty_methods(object.to_jail.class.methods.sort) + assert_equal expected.sort, reject_pretty_methods(object.to_jail.class.methods.map(&:to_s).sort) end end diff --git a/test/test_safemode_eval.rb b/test/test_safemode_eval.rb index 3e84c85..f4cc5bd 100644 --- a/test/test_safemode_eval.rb +++ b/test/test_safemode_eval.rb @@ -28,7 +28,7 @@ def test_should_allow_method_access_on_assigns end def test_should_allow_method_access_on_locals - assert_nothing_raised{ @box.eval "article.title", {}, @locals } + assert_nothing_raised{ @box.eval("article.title", {}, @locals) } end def test_should_not_raise_on_if_using_return_values