Module: Safemode

Defined in:
lib/safemode.rb,
lib/safemode/jail.rb,
lib/safemode/scope.rb,
lib/safemode/parser.rb,
lib/safemode/blankslate.rb,
lib/safemode/core_jails.rb,
lib/safemode/exceptions.rb

Defined Under Namespace

Classes: Blankslate, Box, Error, Jail, NoMethodError, Parser, Scope, SecurityError

Constant Summary collapse

@@default_methods =

these methods are allowed in all classes if they are present

%w( % & * ** + +@ - -@ / < << <= <=> ! != == === > >= >> ^ | ~
eql? equal? new methods is_a? kind_of? nil?
[] []= to_a to_jail to_s inspect to_param not freeze)
@@methods_whitelist =

whitelisted methods for core classes … kind of arbitrary selection

{
  'Array'      => %w(any? assoc at blank? collect collect! compact compact!
                  concat delete delete_at delete_if each each_index each_with_index
                  empty? fetch fill first flatten flatten! hash include? index
                  indexes indices inject insert join last length map map! max min
                  nitems pop push present? rassoc reject reject! reverse
                  reverse! reverse_each rindex select shift size slice
                  slice! sort sort! transpose to_sentence uniq uniq! unshift
                  values_at zip),
   'Float'      => %w(abs blank? ceil coerce div divmod finite? floor hash
                  infinite? integer? modulo nan? nonzero? present? quo
                  remainder round singleton_method_added step to_f to_i
                  to_int to_s truncate zero?),
   'Hash'       => %w(any? blank? clear delete delete_if each each_key each_pair
                  each_value each_with_index empty? fetch dig has_key? has_value?
                  include? index invert key? keys length member? merge merge!
                  present? rec_merge! rehash reject reject! select shift
                  size sort store update value? values values_at),
   'Integer'    => %w(abs blank? ceil chr coerce div divmod downto floor id2name
                  integer? modulo modulo next nonzero? present? quo remainder
                  round singleton_method_added size step succ times to_f to_i
                  to_int to_s to_sym truncate upto zero?),
   'Range'      => %w(any? begin blank? each end exclude_end? first hash
                  include? include_without_range? last member? present?
                  step),
   'String'     => %w(blank? capitalize capitalize! casecmp center chomp chomp!
                  chop chop! concat count crypt delete delete! downcase
                  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 present? reverse reverse!
                  rindex rjust rstrip rstrip! scan size slice slice! split
                  squeeze squeeze! start_with? strip strip! sub sub! succ
                  succ! sum swapcase swapcase! to_f to_i to_str to_sym to_xs
                  toeuc tojis tosjis toutf16 toutf8 tr tr! tr_s tr_s! upcase
                  upcase! upto),
   'Symbol'     => %w(blank? present? to_i to_int),
   'Time'       => %w(blank? _dump asctime ctime day dst? getgm getlocal
                  getutc gmt? gmt_offset gmtime gmtoff hash hour httpdate
                  isdst iso8601 localtime mday min minus_without_duration mon
                  month plus_without_duration present? rfc2822 rfc822 sec
                  strftime succ to_date to_datetime to_f to_i tv_sec tv_usec
                  usec utc utc? utc_offset wday xmlschema yday year zone
                  to_formatted_s),
   'Date'       => %w(ajd amjd asctime blank? ctime cwday cweek cwyear day
                  day_fraction default_inspect downto england gregorian
                  gregorian? hash italy jd julian julian? ld leap? mday
                  minus_without_duration mjd mon month new_start newsg next
                  ns? os? plus_without_duration present? sg start step
                  strftime succ upto wday yday year),
   'DateTime'   => %w(blank? hour min new_offset newof of offset present? sec
                  sec_fraction strftime to_datetime_default_s to_json zone),
   'Data'       => %w(deconstruct deconstruct_keys hash members),
   'Set'        => %w(any? blank? clear clone collect count delete delete?
                  delete_if difference disjoint? each each_with_index
                  each_with_object empty? filter find first flatten
                  flatten! hash include? inject intersect? intersection
                  join keep_if length map max member? merge min
                  present? reject reject! replace select select!
                  size sort sort_by subset? superset? union
                  uniq zip),
   'NilClass'   => %w(blank? duplicable? present? to_f to_i),
   'FalseClass' => %w(blank? duplicable? present?),
   'TrueClass'  => %w(blank? duplicable? present?)
}
@@default_class_methods =

these class methods are allowed on all classes if they are present

%w(name to_jail to_s)
@@class_methods_whitelist =

whitelisted class methods for core classes

{
  'String' => %w(new)
}

Class Method Summary collapse

Class Method Details

.core_classesObject



19
20
21
22
23
24
25
26
# File 'lib/safemode/core_jails.rb', line 19

def core_classes
  klasses = [ Array, Float, Hash, Integer, Range, String, Symbol, Time, NilClass, FalseClass, TrueClass ]
  klasses << Date if defined? Date
  klasses << DateTime if defined? DateTime
  klasses << Data if defined? Data # Ruby 3.2 addition
  klasses << Set if defined? Set # Ruby 3.2 addition
  klasses
end

.core_jail_class_methods(klass) ⇒ Object



32
33
34
# File 'lib/safemode/core_jails.rb', line 32

def core_jail_class_methods(klass)
  @@class_methods_whitelist.fetch(klass.name, []) + (@@default_class_methods & klass.methods.map(&:to_s))
end

.core_jail_methods(klass) ⇒ Object



28
29
30
# File 'lib/safemode/core_jails.rb', line 28

def core_jail_methods(klass)
  @@methods_whitelist.fetch(klass.name, []) + (@@default_methods & klass.instance_methods.map(&:to_s))
end

.define_core_jail_classesObject



3
4
5
6
7
8
9
10
# File 'lib/safemode/core_jails.rb', line 3

def define_core_jail_classes
  core_classes.each do |klass|
    jail = define_jail_class(klass)
    jail.allow_instance_method *core_jail_methods(klass).uniq
    jail.allow_class_method *core_jail_class_methods(klass).uniq
    jail
  end
end

.define_jail_class(klass) ⇒ Object



12
13
14
15
16
17
# File 'lib/safemode/core_jails.rb', line 12

def define_jail_class(klass)
  unless klass.const_defined?("Jail")
    klass.const_set("Jail", jail = Class.new(Safemode::Jail))
  end
  klass.const_get('Jail')
end

.find_jail_class(klass) ⇒ Object



21
22
23
24
25
26
27
# File 'lib/safemode.rb', line 21

def find_jail_class(klass)
  while klass != Object
    return klass.const_get('Jail') if klass.const_defined?('Jail')
    klass = klass.superclass
  end
  Jail
end

.jail(obj) ⇒ Object



17
18
19
# File 'lib/safemode.rb', line 17

def jail(obj)
  find_jail_class(obj.is_a?(Class) ? obj : obj.class).new obj
end