From b1552e086906c65d246114734d7996abe060629f Mon Sep 17 00:00:00 2001 From: merefield Date: Wed, 5 Jun 2024 09:39:30 +0100 Subject: [PATCH 1/2] improve safe ruby --- .../safe_ruby/lib/constant_whitelist.rb | 29 +- .../safe_ruby/lib/make_safe_code.rb | 83 +-- .../safe_ruby/lib/method_whitelist.rb | 482 +++++++++--------- 3 files changed, 300 insertions(+), 294 deletions(-) diff --git a/lib/discourse_chatbot/safe_ruby/lib/constant_whitelist.rb b/lib/discourse_chatbot/safe_ruby/lib/constant_whitelist.rb index 5c58934..70fe712 100644 --- a/lib/discourse_chatbot/safe_ruby/lib/constant_whitelist.rb +++ b/lib/discourse_chatbot/safe_ruby/lib/constant_whitelist.rb @@ -1,15 +1,16 @@ # frozen_string_literal: true - -ALLOWED_CONSTANTS= [ - :Object, :Module, :Class, :BasicObject, :Kernel, :NilClass, :NIL, :Data, :TrueClass, :TRUE, :FalseClass, :FALSE, :Encoding, - :Comparable, :Enumerable, :String, :Symbol, :Exception, :SystemExit, :SignalException, :Interrupt, :StandardError, :TypeError, - :ArgumentError, :IndexError, :KeyError, :RangeError, :ScriptError, :SyntaxError, :LoadError, :NotImplementedError, :NameError, - :NoMethodError, :RuntimeError, :SecurityError, :NoMemoryError, :EncodingError, :SystemCallError, :Errno, :ZeroDivisionError, - :FloatDomainError, :Numeric, :Integer, :Fixnum, :Float, :Bignum, :Array, :Hash, :Struct, :RegexpError, :Regexp, - :MatchData, :Marshal, :Range, :IOError, :EOFError, :IO, :STDIN, :STDOUT, :STDERR, :Time, :Random, - :Signal, :Proc, :LocalJumpError, :SystemStackError, :Method, :UnboundMethod, :Binding, :Math, :Enumerator, - :StopIteration, :RubyVM, :Thread, :TOPLEVEL_BINDING, :ThreadGroup, :Mutex, :ThreadError, :Fiber, :FiberError, :Rational, :Complex, - :RUBY_VERSION, :RUBY_RELEASE_DATE, :RUBY_PLATFORM, :RUBY_PATCHLEVEL, :RUBY_REVISION, :RUBY_DESCRIPTION, :RUBY_COPYRIGHT, :RUBY_ENGINE, - :TracePoint, :ARGV, :Gem, :RbConfig, :Config, :CROSS_COMPILING, :Date, :ConditionVariable, :Queue, :SizedQueue, :MonitorMixin, :Monitor, - :Exception2MessageMapper, :IRB, :RubyToken, :RubyLex, :Readline, :RUBYGEMS_ACTIVATION_MONITOR -] +class SafeRuby + ALLOWED_CONSTANTS= [ + :Object, :Module, :Class, :BasicObject, :Kernel, :NilClass, :NIL, :Data, :TrueClass, :TRUE, :FalseClass, :FALSE, :Encoding, + :Comparable, :Enumerable, :String, :Symbol, :Exception, :SystemExit, :SignalException, :Interrupt, :StandardError, :TypeError, + :ArgumentError, :IndexError, :KeyError, :RangeError, :ScriptError, :SyntaxError, :LoadError, :NotImplementedError, :NameError, + :NoMethodError, :RuntimeError, :SecurityError, :NoMemoryError, :EncodingError, :SystemCallError, :Errno, :ZeroDivisionError, + :FloatDomainError, :Numeric, :Integer, :Fixnum, :Float, :Bignum, :Array, :Hash, :Struct, :RegexpError, :Regexp, + :MatchData, :Marshal, :Range, :IOError, :EOFError, :IO, :STDIN, :STDOUT, :STDERR, :Time, :Random, + :Signal, :Proc, :LocalJumpError, :SystemStackError, :Method, :UnboundMethod, :Binding, :Math, :Enumerator, + :StopIteration, :RubyVM, :Thread, :TOPLEVEL_BINDING, :ThreadGroup, :Mutex, :ThreadError, :Fiber, :FiberError, :Rational, :Complex, + :RUBY_VERSION, :RUBY_RELEASE_DATE, :RUBY_PLATFORM, :RUBY_PATCHLEVEL, :RUBY_REVISION, :RUBY_DESCRIPTION, :RUBY_COPYRIGHT, :RUBY_ENGINE, + :TracePoint, :ARGV, :Gem, :RbConfig, :Config, :CROSS_COMPILING, :Date, :ConditionVariable, :Queue, :SizedQueue, :MonitorMixin, :Monitor, + :Exception2MessageMapper, :IRB, :RubyToken, :RubyLex, :Readline, :RUBYGEMS_ACTIVATION_MONITOR + ] +end diff --git a/lib/discourse_chatbot/safe_ruby/lib/make_safe_code.rb b/lib/discourse_chatbot/safe_ruby/lib/make_safe_code.rb index 5c11251..3a888e1 100644 --- a/lib/discourse_chatbot/safe_ruby/lib/make_safe_code.rb +++ b/lib/discourse_chatbot/safe_ruby/lib/make_safe_code.rb @@ -1,53 +1,54 @@ # frozen_string_literal: true +class SafeRuby + MAKE_SAFE_CODE = <<-STRING + def keep_singleton_methods(klass, singleton_methods) + klass = Object.const_get(klass) + singleton_methods = singleton_methods.map(&:to_sym) + undef_methods = (klass.singleton_methods - singleton_methods) -MAKE_SAFE_CODE = <<-STRING -def keep_singleton_methods(klass, singleton_methods) - klass = Object.const_get(klass) - singleton_methods = singleton_methods.map(&:to_sym) - undef_methods = (klass.singleton_methods - singleton_methods) + undef_methods.each do |method| + klass.singleton_class.send(:undef_method, method) + end - undef_methods.each do |method| - klass.singleton_class.send(:undef_method, method) end -end + def keep_methods(klass, methods) + klass = Object.const_get(klass) + methods = methods.map(&:to_sym) + undef_methods = (klass.methods(false) - methods) + undef_methods.each do |method| + klass.send(:undef_method, method) + end + end -def keep_methods(klass, methods) - klass = Object.const_get(klass) - methods = methods.map(&:to_sym) - undef_methods = (klass.methods(false) - methods) - undef_methods.each do |method| - klass.send(:undef_method, method) + def clean_constants + (Object.constants - #{ALLOWED_CONSTANTS}).each do |const| + Object.send(:remove_const, const) if defined?(const) + end end -end -def clean_constants - (Object.constants - #{ALLOWED_CONSTANTS}).each do |const| - Object.send(:remove_const, const) if defined?(const) + keep_singleton_methods(:Kernel, #{KERNEL_S_METHODS}) + keep_singleton_methods(:Symbol, #{SYMBOL_S_METHODS}) + keep_singleton_methods(:String, #{STRING_S_METHODS}) + keep_singleton_methods(:IO, #{IO_S_METHODS}) + + keep_methods(:Kernel, #{KERNEL_METHODS}) + keep_methods(:NilClass, #{NILCLASS_METHODS}) + keep_methods(:TrueClass, #{TRUECLASS_METHODS}) + keep_methods(:FalseClass, #{FALSECLASS_METHODS}) + keep_methods(:Enumerable, #{ENUMERABLE_METHODS}) + keep_methods(:String, #{STRING_METHODS}) + Kernel.class_eval do + def `(*args) + raise NoMethodError, "` is unavailable" end -end -keep_singleton_methods(:Kernel, #{KERNEL_S_METHODS}) -keep_singleton_methods(:Symbol, #{SYMBOL_S_METHODS}) -keep_singleton_methods(:String, #{STRING_S_METHODS}) -keep_singleton_methods(:IO, #{IO_S_METHODS}) - -keep_methods(:Kernel, #{KERNEL_METHODS}) -keep_methods(:NilClass, #{NILCLASS_METHODS}) -keep_methods(:TrueClass, #{TRUECLASS_METHODS}) -keep_methods(:FalseClass, #{FALSECLASS_METHODS}) -keep_methods(:Enumerable, #{ENUMERABLE_METHODS}) -keep_methods(:String, #{STRING_METHODS}) -Kernel.class_eval do - def `(*args) - raise NoMethodError, "` is unavailable" - end - - def system(*args) - raise NoMethodError, "system is unavailable" - end -end + def system(*args) + raise NoMethodError, "system is unavailable" + end + end -clean_constants + clean_constants -STRING + STRING +end diff --git a/lib/discourse_chatbot/safe_ruby/lib/method_whitelist.rb b/lib/discourse_chatbot/safe_ruby/lib/method_whitelist.rb index 8049511..d905f66 100644 --- a/lib/discourse_chatbot/safe_ruby/lib/method_whitelist.rb +++ b/lib/discourse_chatbot/safe_ruby/lib/method_whitelist.rb @@ -1,272 +1,276 @@ # frozen_string_literal: true -IO_S_METHODS = %w[ - new - foreach - open -] +class SafeRuby -KERNEL_S_METHODS = %w[ - Array - binding - block_given? - catch - chomp - chomp! - chop - chop! + IO_S_METHODS = %w[ + new + foreach + open + ] + + KERNEL_S_METHODS = %w[ + Array + binding + block_given? + catch + chomp + chomp! + chop + chop! + eval + fail + Float + format + global_variables + gsub + gsub! + Integer + iterator? + lambda + local_variables + loop + method_missing + proc + raise + scan + split + sprintf + String + sub + sub! + throw + ].freeze + + SYMBOL_S_METHODS = %w[ + all_symbols + ].freeze + + STRING_S_METHODS = %w[ + ].freeze + + KERNEL_METHODS = %w[ + == + + ray + nding + ock_given? + tch + omp + omp! + op + op! + ass + clone + dup + eql? + equal? eval fail Float format + freeze + frozen? global_variables gsub gsub! + hash + id + initialize_copy + inspect + instance_eval + instance_of? + instance_variables + instance_variable_get + instance_variable_set + instance_variable_defined? Integer + is_a? iterator? + kind_of? lambda local_variables loop + methods method_missing + nil? + private_methods + print proc + protected_methods + public_methods raise + remove_instance_variable + respond_to? + respond_to_missing? scan + send + singleton_methods + singleton_method_added + singleton_method_removed + singleton_method_undefined split sprintf String sub sub! + taint + tainted? throw + to_a + to_s + type + untaint + __send__ ].freeze -SYMBOL_S_METHODS = %w[ -all_symbols -].freeze - -STRING_S_METHODS = %w[ -].freeze - -KERNEL_METHODS = %w[ -== - -ray -nding -ock_given? -tch -omp -omp! -op -op! -ass -clone -dup -eql? -equal? -eval -fail -Float -format -freeze -frozen? -global_variables -gsub -gsub! -hash -id -initialize_copy -inspect -instance_eval -instance_of? -instance_variables -instance_variable_get -instance_variable_set -instance_variable_defined? -Integer -is_a? -iterator? -kind_of? -lambda -local_variables -loop -methods -method_missing -nil? -private_methods -print -proc -protected_methods -public_methods -raise -remove_instance_variable -respond_to? -respond_to_missing? -scan -send -singleton_methods -singleton_method_added -singleton_method_removed -singleton_method_undefined -split -sprintf -String -sub -sub! -taint -tainted? -throw -to_a -to_s -type -untaint -__send__ -].freeze + NILCLASS_METHODS = %w[ + & + inspect + nil? + to_a + to_f + to_i + to_s + ^ + | + ].freeze -NILCLASS_METHODS = %w[ -& -inspect -nil? -to_a -to_f -to_i -to_s -^ -| -].freeze + SYMBOL_METHODS = %w[ + === + id2name + inspect + to_i + to_int + to_s + to_sym + ].freeze -SYMBOL_METHODS = %w[ -=== -id2name -inspect -to_i -to_int -to_s -to_sym -].freeze + TRUECLASS_METHODS = %w[ + & + to_s + ^ + | + ].freeze -TRUECLASS_METHODS = %w[ -& -to_s -^ -| -].freeze + FALSECLASS_METHODS = %w[ + & + to_s + ^ + | + ].freeze -FALSECLASS_METHODS = %w[ -& -to_s -^ -| -].freeze + ENUMERABLE_METHODS = %w[ + all? + any? + collect + detect + each_with_index + entries + find + find_all + grep + include? + inject + map + max + member? + min + partition + reject + select + sort + sort_by + to_a + zip + ].freeze -ENUMERABLE_METHODS = %w[ -all? -any? -collect -detect -each_with_index -entries -find -find_all -grep -include? -inject -map -max -member? -min -partition -reject -select -sort -sort_by -to_a -zip -].freeze + STRING_METHODS = %w[ + % + * + + + << + <=> + == + =~ + capitalize + capitalize! + casecmp + center + chomp + chomp! + chop + chop! + concat + count + crypt + delete + delete! + downcase + downcase! + dump + each + each_byte + each_line + empty? + eql? + gsub + gsub! + hash + hex + include? + index + initialize + initialize_copy + insert + inspect + intern + length + ljust + lines + lstrip + lstrip! + match + next + next! + oct + replace + reverse + reverse! + rindex + rjust + rstrip + rstrip! + scan + size + slice + slice! + split + squeeze + squeeze! + strip + strip! + start_with? + sub + sub! + succ + succ! + sum + swapcase + swapcase! + to_f + to_i + to_s + to_str + to_sym + tr + tr! + tr_s + tr_s! + upcase + upcase! + upto + [] + []= + ].freeze -STRING_METHODS = %w[ -% -* -+ -<< -<=> -== -=~ -capitalize -capitalize! -casecmp -center -chomp -chomp! -chop -chop! -concat -count -crypt -delete -delete! -downcase -downcase! -dump -each -each_byte -each_line -empty? -eql? -gsub -gsub! -hash -hex -include? -index -initialize -initialize_copy -insert -inspect -intern -length -ljust -lines -lstrip -lstrip! -match -next -next! -oct -replace -reverse -reverse! -rindex -rjust -rstrip -rstrip! -scan -size -slice -slice! -split -squeeze -squeeze! -strip -strip! -start_with? -sub -sub! -succ -succ! -sum -swapcase -swapcase! -to_f -to_i -to_s -to_str -to_sym -tr -tr! -tr_s -tr_s! -upcase -upcase! -upto -[] -[]= -].freeze +end \ No newline at end of file From 68e2899482c4056f80c72bf6d5aefaef21e644b4 Mon Sep 17 00:00:00 2001 From: merefield Date: Wed, 5 Jun 2024 09:40:22 +0100 Subject: [PATCH 2/2] bump patch --- plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.rb b/plugin.rb index ddd0f4b..b3c6cd3 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-chatbot # about: a plugin that allows you to have a conversation with a configurable chatbot in Discourse Chat, Topics and Private Messages -# version: 0.9.23 +# version: 0.9.24 # authors: merefield # url: https://github.com/merefield/discourse-chatbot