From 6c46db611b59a83deac4de09637df23a84647666 Mon Sep 17 00:00:00 2001 From: Ewoud Kohl van Wijngaarden Date: Wed, 31 Aug 2022 13:43:45 +0200 Subject: [PATCH] Deal with kwargs Ruby 3 has started to separate args and kwargs. --- lib/safemode/jail.rb | 4 ++-- lib/safemode/scope.rb | 16 +++++++++++----- test/test_helper.rb | 10 +++++++--- test/test_jail.rb | 10 ++++++++++ 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/lib/safemode/jail.rb b/lib/safemode/jail.rb index de88a75..bd47add 100644 --- a/lib/safemode/jail.rb +++ b/lib/safemode/jail.rb @@ -12,7 +12,7 @@ def to_s @source.to_s end - def method_missing(method, *args, &block) + def method_missing(method, *args, **kwargs, &block) if @source.is_a?(Class) unless self.class.allowed_class_method?(method) raise Safemode::NoMethodError.new(".#{method}", self.class.name, @source.name) @@ -28,7 +28,7 @@ def method_missing(method, *args, &block) # don't need to jail objects returned from a jail. Doing so would provide # "double" protection, but it also would break using a return value in an if # statement, passing them to a Rails helper etc. - @source.send(method, *args, &block) + @source.send(method, *args, **kwargs, &block) end def respond_to_missing?(method_name, include_private = false) diff --git a/lib/safemode/scope.rb b/lib/safemode/scope.rb index 189b487..5ed49b4 100644 --- a/lib/safemode/scope.rb +++ b/lib/safemode/scope.rb @@ -30,11 +30,11 @@ def output @_safemode_output end - def method_missing(method, *args, &block) + def method_missing(method, *args, **kwargs, &block) if @locals.has_key?(method) @locals[method] elsif @delegate_methods.include?(method) - @delegate.send method, *unjail_args(args), &block + @delegate.send method, *unjail_args(args), **unjail_kwargs(kwargs), &block else raise Safemode::SecurityError.new(method, "#") end @@ -49,10 +49,16 @@ def symbolize_keys(hash) end end + def unjail(arg) + arg.class.name.end_with?('::Jail') ? arg.instance_variable_get(:@source) : arg + end + def unjail_args(args) - args.collect do |arg| - arg.class.name =~ /::Jail$/ ? arg.instance_variable_get(:@source) : arg - end + args.collect { |arg| unjail(arg) } + end + + def unjail_kwargs(kwargs) + kwargs.map { |key, value| [unjail(key), unjail(value)] }.to_h end end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 82e1247..52416da 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -110,8 +110,12 @@ def comment_class Comment end - def method_missing(method, *args, &block) - super(method, *args, &block) + def method_with_kwargs(a_keyword: false) + a_keyword + end + + def method_missing(method, *args, **kwargs, &block) + super end end @@ -144,7 +148,7 @@ def self.destroy_all end class Article::Jail < Safemode::Jail - allow :title, :comments, :is_article?, :comment_class + allow :title, :comments, :is_article?, :comment_class, :method_with_kwargs def author_name "this article's author name" diff --git a/test/test_jail.rb b/test/test_jail.rb index 3a42176..3629cd9 100644 --- a/test/test_jail.rb +++ b/test/test_jail.rb @@ -24,6 +24,16 @@ def test_sending_to_jail_to_an_object_should_return_a_jail assert_equal "Article::Jail", @article.class.name end + def test_sending_of_kwargs_works + assert @article.method_with_kwargs(a_keyword: true) + end + + def test_sending_to_method_missing + assert_raise_with_message(Safemode::NoMethodError, /#no_such_method/) do + @article.no_such_method('arg', key: 'value') + end + end + def test_jail_instances_should_have_limited_methods expected = ["class", "method_missing", "methods", "respond_to?", "to_jail", "to_s", "instance_variable_get"] objects.each do |object|