safemode 1.3.1 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +16 -0
- data/Gemfile +11 -12
- data/README.markdown +7 -5
- data/Rakefile +4 -14
- data/VERSION +1 -1
- data/lib/action_view/template_handlers/safe_erb.rb +2 -2
- data/lib/safemode/blankslate.rb +7 -1
- data/lib/safemode/core_jails.rb +3 -3
- data/lib/safemode/jail.rb +6 -11
- data/lib/safemode/parser.rb +28 -21
- data/safemode.gemspec +20 -28
- data/test/test_helper.rb +18 -18
- data/test/test_jail.rb +7 -4
- data/test/test_safemode_eval.rb +15 -19
- data/test/test_safemode_parser.rb +6 -0
- metadata +20 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9c122fc8f941080a885c335b7356d2e1af7545cec8633ca23571273f069f36e0
|
4
|
+
data.tar.gz: f5555df33c321fbc85bff612c80568c4667e1c17d77aaa74da3311ea659b2574
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 253de818e490f1e03030dfb9600960322ee6ea3c2d1d7ae571ccbc9ad44c99cb58af2d23227d6244a4de4006e0d56716b6b12c5fe83fc2fb8c874bbae5f1aca1
|
7
|
+
data.tar.gz: 2b468cf47ef692c3623daba9b1ea100ab4e74243d701aad3c86e46a04cc09d91470a9a57c5ecd117f26142b223ec33f1169b09bc90756d5dc96104d9b00c341e
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,18 +1,17 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
gem
|
3
|
+
source 'http://rubygems.org'
|
4
|
+
|
5
|
+
gem 'ruby2ruby', '>= 2.4.0'
|
6
|
+
gem 'ruby_parser', '>= 3.10.1'
|
7
|
+
gem 'sexp_processor', '>= 4.10.0'
|
6
8
|
|
7
9
|
# Add dependencies to develop your gem here.
|
8
10
|
# Include everything needed to run rake, tests, features, etc.
|
9
11
|
group :development do
|
10
|
-
gem
|
11
|
-
gem
|
12
|
-
gem
|
13
|
-
gem
|
14
|
-
gem
|
15
|
-
gem "simplecov", :platforms => [:ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24]
|
16
|
-
gem "test-unit", :platforms => [:ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24]
|
17
|
-
gem "rake"
|
12
|
+
gem 'jeweler'
|
13
|
+
gem 'rake'
|
14
|
+
gem 'rdoc', '~> 3.12'
|
15
|
+
gem 'simplecov'
|
16
|
+
gem 'test-unit'
|
18
17
|
end
|
data/README.markdown
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
A library for safe evaluation of Ruby code based on RubyParser and
|
4
4
|
Ruby2Ruby. Provides Rails ActionView template handlers for ERB and Haml.
|
5
5
|
|
6
|
+
[](https://travis-ci.org/svenfuchs/safemode)
|
7
|
+
|
6
8
|
### Word of warning
|
7
9
|
|
8
10
|
This library is still highly experimental. Only use it at your own risk for
|
@@ -52,9 +54,9 @@ class is only accessible when returned by a method or passed into a template.
|
|
52
54
|
For more details about the concepts behind Safemode please refer to the
|
53
55
|
following blog posts until a more comprehensive writeup is available:
|
54
56
|
|
55
|
-
* Initial reasoning:
|
56
|
-
* Refined concept:
|
57
|
-
* ActionView ERB handler:
|
57
|
+
* Initial reasoning: http://www.artweb-design.de/2008/2/5/sexy-theme-templating-with-haml-safemode-finally
|
58
|
+
* Refined concept: http://www.artweb-design.de/2008/2/17/sending-ruby-to-the-jail-an-attemp-on-a-haml-safemode
|
59
|
+
* ActionView ERB handler: http://www.artweb-design.de/2008/4/22/an-erb-safemode-handler-for-actionview
|
58
60
|
|
59
61
|
### Dependencies
|
60
62
|
|
@@ -64,14 +66,14 @@ Requires the gems:
|
|
64
66
|
* Ruby2Ruby
|
65
67
|
|
66
68
|
As of writing RubyParser alters StringIO and thus breaks usage with Rails.
|
67
|
-
See
|
69
|
+
See http://www.zenspider.com/pipermail/parsetree/2008-April/000026.html
|
68
70
|
|
69
71
|
A patch is included that fixes this issue and can be applied to RubyParser.
|
70
72
|
See lib/ruby\_parser\_string\_io\_patch.diff
|
71
73
|
|
72
74
|
### Credits
|
73
75
|
|
74
|
-
* Sven Fuchs - Maintainer
|
76
|
+
* Sven Fuchs - Initial Maintainer
|
75
77
|
* Peter Cooper
|
76
78
|
* Matthias Viehweger
|
77
79
|
* Ohad Levy
|
data/Rakefile
CHANGED
@@ -47,20 +47,10 @@ Rake::TestTask.new(:test) do |test|
|
|
47
47
|
test.verbose = true
|
48
48
|
end
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
Rake::Task[:test].execute
|
55
|
-
end
|
56
|
-
else
|
57
|
-
require 'rcov/rcovtask'
|
58
|
-
Rcov::RcovTask.new do |test|
|
59
|
-
test.libs << 'test'
|
60
|
-
test.pattern = 'test/**/test_*.rb'
|
61
|
-
test.verbose = true
|
62
|
-
test.rcov_opts << '--exclude "gems/*"'
|
63
|
-
end
|
50
|
+
desc "Generate coverage report for tests"
|
51
|
+
task :coverage do |cov|
|
52
|
+
ENV['COVERAGE'] = 'true'
|
53
|
+
Rake::Task[:test].execute
|
64
54
|
end
|
65
55
|
|
66
56
|
task :default => :test
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.3.
|
1
|
+
1.3.6
|
@@ -20,9 +20,9 @@ module ActionView
|
|
20
20
|
|
21
21
|
# code = ::ERB.new(src, nil, @view.erb_trim_mode).src
|
22
22
|
code = ::ERB.new("<% __in_erb_template=true %>#{src}", nil, erb_trim_mode, '@output_buffer').src
|
23
|
-
# Ruby 1.9 prepends an encoding to the source. However this is
|
23
|
+
# Ruby 1.9+ prepends an encoding to the source. However this is
|
24
24
|
# useless because you can only set an encoding on the first line
|
25
|
-
|
25
|
+
src.sub(/\A#coding:.*\n/, '') : src
|
26
26
|
|
27
27
|
code.gsub!('\\','\\\\\\') # backslashes would disappear in compile_template/modul_eval, so we escape them
|
28
28
|
|
data/lib/safemode/blankslate.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
module Safemode
|
2
2
|
class Blankslate
|
3
3
|
@@allow_instance_methods = ['class', 'methods', 'respond_to?', 'respond_to_missing?', 'to_s', 'instance_variable_get']
|
4
|
-
@@allow_class_methods = ['methods', 'new', 'name', '<', 'ancestors', '==']
|
4
|
+
@@allow_class_methods = ['methods', 'new', 'name', '<', 'ancestors', '=='] # < needed in Rails Object#subclasses_of
|
5
|
+
if defined?(JRUBY_VERSION)
|
6
|
+
# JRuby seems to silently fail to remove method_missing
|
7
|
+
# (also see https://github.com/jruby/jruby/blob/9.1.7.0/core/src/main/java/org/jruby/RubyModule.java#L1109)
|
8
|
+
@@allow_class_methods << 'method_missing'
|
9
|
+
(@@allow_class_methods << ['singleton_method_undefined', 'singleton_method_added']).flatten! # needed for JRuby support
|
10
|
+
end
|
5
11
|
|
6
12
|
silently { undef_methods(*instance_methods.map(&:to_s) - @@allow_instance_methods) }
|
7
13
|
class << self
|
data/lib/safemode/core_jails.rb
CHANGED
@@ -41,7 +41,7 @@ module Safemode
|
|
41
41
|
# these methods are allowed in all classes if they are present
|
42
42
|
@@default_methods = %w( % & * ** + +@ - -@ / < << <= <=> ! != == === > >= >> ^ | ~
|
43
43
|
eql? equal? new methods is_a? kind_of? nil?
|
44
|
-
[] []= to_a to_jail to_s inspect to_param not)
|
44
|
+
[] []= to_a to_jail to_s inspect to_param not freeze)
|
45
45
|
|
46
46
|
# whitelisted methods for core classes ... kind of arbitrary selection
|
47
47
|
@@methods_whitelist = {
|
@@ -51,8 +51,8 @@ module Safemode
|
|
51
51
|
indexes indices inject insert join last length map map!
|
52
52
|
nitems pop push present? rassoc reject reject! reverse
|
53
53
|
reverse! reverse_each rindex select shift size slice
|
54
|
-
slice! sort sort! transpose uniq uniq! unshift
|
55
|
-
zip),
|
54
|
+
slice! sort sort! transpose to_sentence uniq uniq! unshift
|
55
|
+
values_at zip),
|
56
56
|
|
57
57
|
'Bignum' => %w(abs blank? ceil chr coerce div divmod downto floor hash
|
58
58
|
integer? modulo next nonzero? present? quo remainder round
|
data/lib/safemode/jail.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
module Safemode
|
2
|
-
class Jail < Blankslate
|
1
|
+
module Safemode
|
2
|
+
class Jail < Blankslate
|
3
3
|
def initialize(source = nil)
|
4
4
|
@source = source
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
7
|
def to_jail
|
8
8
|
self
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def to_s
|
12
12
|
@source.to_s
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def method_missing(method, *args, &block)
|
16
16
|
if @source.is_a?(Class)
|
17
17
|
unless self.class.allowed_class_method?(method)
|
@@ -22,7 +22,7 @@ module Safemode
|
|
22
22
|
raise Safemode::NoMethodError.new("##{method}", self.class.name, @source.class.name)
|
23
23
|
end
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
# As every call to an object in the eval'ed string will be jailed by the
|
27
27
|
# parser we don't need to "proactively" jail arrays and hashes. Likewise we
|
28
28
|
# don't need to jail objects returned from a jail. Doing so would provide
|
@@ -31,11 +31,6 @@ module Safemode
|
|
31
31
|
@source.send(method, *args, &block)
|
32
32
|
end
|
33
33
|
|
34
|
-
# needed for compatibility with 1.8.7; remove this method once 1.8.7 support has been dropped
|
35
|
-
def respond_to?(method, *)
|
36
|
-
respond_to_missing?(method)
|
37
|
-
end
|
38
|
-
|
39
34
|
def respond_to_missing?(method_name, include_private = false)
|
40
35
|
self.class.allowed_instance_method?(method_name)
|
41
36
|
end
|
data/lib/safemode/parser.rb
CHANGED
@@ -2,14 +2,14 @@ module Safemode
|
|
2
2
|
class Parser < Ruby2Ruby
|
3
3
|
# @@parser = defined?(RubyParser) ? 'RubyParser' : 'ParseTree'
|
4
4
|
@@parser = 'RubyParser'
|
5
|
-
|
5
|
+
|
6
6
|
class << self
|
7
7
|
def jail(code, allowed_fcalls = [])
|
8
8
|
@@allowed_fcalls = allowed_fcalls
|
9
9
|
tree = parse code
|
10
10
|
self.new.process(tree)
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def parse(code)
|
14
14
|
case @@parser
|
15
15
|
# when 'ParseTree'
|
@@ -20,12 +20,12 @@ module Safemode
|
|
20
20
|
raise "unknown parser #{@@parser}"
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def parser=(parser)
|
25
25
|
@@parser = parser
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def jail(str, parentheses = false)
|
30
30
|
str = parentheses ? "(#{str})." : "#{str}." if str
|
31
31
|
"#{str}to_jail"
|
@@ -33,13 +33,14 @@ module Safemode
|
|
33
33
|
|
34
34
|
# split up #process_call. see below ...
|
35
35
|
def process_call(exp)
|
36
|
+
exp.shift # remove ":call" symbol
|
36
37
|
receiver = jail process_call_receiver(exp)
|
37
38
|
name = exp.shift
|
38
39
|
args = process_call_args(exp)
|
39
40
|
|
40
41
|
process_call_code(receiver, name, args)
|
41
42
|
end
|
42
|
-
|
43
|
+
|
43
44
|
def process_fcall(exp)
|
44
45
|
# using haml we probably never arrive here because :lasgn'ed :fcalls
|
45
46
|
# somehow seem to change to :calls somewhere during processing
|
@@ -85,7 +86,7 @@ module Safemode
|
|
85
86
|
# :colon2 is used for module constants
|
86
87
|
:colon2,
|
87
88
|
# unnecessarily advanced?
|
88
|
-
:argscat, :argspush, :splat,
|
89
|
+
:argscat, :argspush, :splat,
|
89
90
|
:op_asgn1, :op_asgn2, :op_asgn_and, :op_asgn_or,
|
90
91
|
# needed for haml
|
91
92
|
:block ]
|
@@ -101,13 +102,17 @@ module Safemode
|
|
101
102
|
:attrasgn, :cdecl, :cvasgn, :cvdecl, :cvar, :gvar, :gasgn,
|
102
103
|
:xstr, :dxstr,
|
103
104
|
# not sure how secure ruby regexp is, so leave it out for now
|
104
|
-
:dregx, :dregx_once, :match2, :match3, :nth_ref, :back_ref
|
105
|
+
:dregx, :dregx_once, :match2, :match3, :nth_ref, :back_ref,
|
106
|
+
# block_pass represents &:method, which would bypass the whitelist e.g. by array.each(&:destroy)
|
107
|
+
# at this point we don't know the receiver so we rather disable it completely,
|
108
|
+
# use array.each { |item| item.destroy } instead
|
109
|
+
:block_pass ]
|
105
110
|
|
106
|
-
# SexpProcessor bails when we overwrite these ... but they are listed as
|
111
|
+
# SexpProcessor bails when we overwrite these ... but they are listed as
|
107
112
|
# "internal nodes that you can't get to" in sexp_processor.rb
|
108
113
|
# :ifunc, :method, :last, :opt_n, :cfunc, :newline, :alloca, :memo, :cref
|
109
|
-
|
110
|
-
disallowed.each do |name|
|
114
|
+
|
115
|
+
disallowed.each do |name|
|
111
116
|
define_method "process_#{name}" do |arg|
|
112
117
|
code = super(arg)
|
113
118
|
raise_security_error(name, code)
|
@@ -115,30 +120,31 @@ module Safemode
|
|
115
120
|
end
|
116
121
|
|
117
122
|
def process_const(arg)
|
118
|
-
|
119
|
-
|
123
|
+
sexp_type = arg.sexp_body.sexp_type # constants are encoded as: "s(:const, :Encoding)"
|
124
|
+
if sexp_type == :Encoding
|
125
|
+
# handling of Encoding constants.
|
120
126
|
# Note: ruby_parser evaluates __ENCODING__ to s(:colon2, s(:const, :Encoding), :UTF_8)
|
121
127
|
"#{super(arg).gsub('-', '_')}"
|
122
|
-
elsif
|
128
|
+
elsif sexp_type == :String
|
123
129
|
# Allow String.new as used in ERB in Ruby 2.4+ to create a string buffer
|
124
130
|
super(arg).to_s
|
125
131
|
else
|
126
132
|
raise_security_error("constant", super(arg))
|
127
133
|
end
|
128
134
|
end
|
129
|
-
|
135
|
+
|
130
136
|
def raise_security_error(type, info)
|
131
137
|
raise Safemode::SecurityError.new(type, info)
|
132
138
|
end
|
133
|
-
|
139
|
+
|
134
140
|
# split up Ruby2Ruby#process_call monster method so we can hook into it
|
135
141
|
# in a more readable manner
|
136
142
|
|
137
143
|
def process_call_receiver(exp)
|
138
144
|
receiver_node_type = exp.first.nil? ? nil : exp.first.first
|
139
|
-
receiver = process exp.shift
|
145
|
+
receiver = process exp.shift
|
140
146
|
receiver = "(#{receiver})" if
|
141
|
-
Ruby2Ruby::ASSIGN_NODES.include? receiver_node_type
|
147
|
+
Ruby2Ruby::ASSIGN_NODES.include? receiver_node_type
|
142
148
|
receiver
|
143
149
|
end
|
144
150
|
|
@@ -174,15 +180,16 @@ module Safemode
|
|
174
180
|
end
|
175
181
|
end
|
176
182
|
end
|
177
|
-
|
183
|
+
|
178
184
|
# Ruby2Ruby process_if rewrites if and unless statements in a way that
|
179
185
|
# makes the result unusable for evaluation in, e.g. ERB which appends a
|
180
|
-
# call to to_s when using <%= %> tags. We'd need to either enclose the
|
186
|
+
# call to to_s when using <%= %> tags. We'd need to either enclose the
|
181
187
|
# result from process_if into parentheses like (1 if true) and
|
182
188
|
# (true ? (1) : (2)) or just use the plain if-then-else-end syntax (so
|
183
189
|
# that ERB can safely append to_s to the resulting block).
|
184
190
|
|
185
191
|
def process_if(exp)
|
192
|
+
exp.shift # remove ":if" symbol from exp
|
186
193
|
expand = Ruby2Ruby::ASSIGN_NODES.include? exp.first.first
|
187
194
|
c = process exp.shift
|
188
195
|
t = process exp.shift
|
@@ -212,6 +219,6 @@ module Safemode
|
|
212
219
|
# end
|
213
220
|
"unless #{c} then\n#{indent(f)}\nend"
|
214
221
|
end
|
215
|
-
end
|
216
|
-
end
|
222
|
+
end
|
223
|
+
end
|
217
224
|
end
|
data/safemode.gemspec
CHANGED
@@ -2,22 +2,23 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: safemode 1.3.
|
5
|
+
# stub: safemode 1.3.6 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "safemode".freeze
|
9
|
-
s.version = "1.3.
|
9
|
+
s.version = "1.3.6"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Sven Fuchs".freeze, "Peter Cooper".freeze, "Matthias Viehweger".freeze, "Kingsley Hendrickse".freeze, "Ohad Levy".freeze, "Dmitri Dolguikh".freeze]
|
14
|
-
s.date = "
|
14
|
+
s.date = "2020-08-31"
|
15
15
|
s.description = "A library for safe evaluation of Ruby code based on RubyParser and Ruby2Ruby. Provides Rails ActionView template handlers for ERB and Haml.".freeze
|
16
16
|
s.email = "ohadlevy@gmail.com".freeze
|
17
17
|
s.extra_rdoc_files = [
|
18
18
|
"README.markdown"
|
19
19
|
]
|
20
20
|
s.files = [
|
21
|
+
".travis.yml",
|
21
22
|
"Gemfile",
|
22
23
|
"LICENCSE",
|
23
24
|
"README.markdown",
|
@@ -48,49 +49,40 @@ Gem::Specification.new do |s|
|
|
48
49
|
]
|
49
50
|
s.homepage = "http://github.com/svenfuchs/safemode".freeze
|
50
51
|
s.licenses = ["MIT".freeze]
|
51
|
-
s.rubygems_version = "2.6
|
52
|
+
s.rubygems_version = "2.7.6".freeze
|
52
53
|
s.summary = "A library for safe evaluation of Ruby code based on ParseTree/RubyParser and Ruby2Ruby".freeze
|
53
54
|
|
54
55
|
if s.respond_to? :specification_version then
|
55
56
|
s.specification_version = 4
|
56
57
|
|
57
58
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
58
|
-
s.add_runtime_dependency(%q<
|
59
|
-
s.add_runtime_dependency(%q<
|
60
|
-
s.add_runtime_dependency(%q<
|
61
|
-
s.add_development_dependency(%q<shoulda>.freeze, [">= 0"])
|
62
|
-
s.add_development_dependency(%q<rdoc>.freeze, ["~> 3.12"])
|
63
|
-
s.add_development_dependency(%q<bundler>.freeze, ["~> 1.0"])
|
59
|
+
s.add_runtime_dependency(%q<ruby2ruby>.freeze, [">= 2.4.0"])
|
60
|
+
s.add_runtime_dependency(%q<ruby_parser>.freeze, [">= 3.10.1"])
|
61
|
+
s.add_runtime_dependency(%q<sexp_processor>.freeze, [">= 4.10.0"])
|
64
62
|
s.add_development_dependency(%q<jeweler>.freeze, [">= 0"])
|
65
|
-
s.add_development_dependency(%q<
|
63
|
+
s.add_development_dependency(%q<rake>.freeze, [">= 0"])
|
64
|
+
s.add_development_dependency(%q<rdoc>.freeze, ["~> 3.12"])
|
66
65
|
s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
|
67
66
|
s.add_development_dependency(%q<test-unit>.freeze, [">= 0"])
|
68
|
-
s.add_development_dependency(%q<rake>.freeze, [">= 0"])
|
69
67
|
else
|
70
|
-
s.add_dependency(%q<
|
71
|
-
s.add_dependency(%q<
|
72
|
-
s.add_dependency(%q<
|
73
|
-
s.add_dependency(%q<shoulda>.freeze, [">= 0"])
|
74
|
-
s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
|
75
|
-
s.add_dependency(%q<bundler>.freeze, ["~> 1.0"])
|
68
|
+
s.add_dependency(%q<ruby2ruby>.freeze, [">= 2.4.0"])
|
69
|
+
s.add_dependency(%q<ruby_parser>.freeze, [">= 3.10.1"])
|
70
|
+
s.add_dependency(%q<sexp_processor>.freeze, [">= 4.10.0"])
|
76
71
|
s.add_dependency(%q<jeweler>.freeze, [">= 0"])
|
77
|
-
s.add_dependency(%q<
|
72
|
+
s.add_dependency(%q<rake>.freeze, [">= 0"])
|
73
|
+
s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
|
78
74
|
s.add_dependency(%q<simplecov>.freeze, [">= 0"])
|
79
75
|
s.add_dependency(%q<test-unit>.freeze, [">= 0"])
|
80
|
-
s.add_dependency(%q<rake>.freeze, [">= 0"])
|
81
76
|
end
|
82
77
|
else
|
83
|
-
s.add_dependency(%q<
|
84
|
-
s.add_dependency(%q<
|
85
|
-
s.add_dependency(%q<
|
86
|
-
s.add_dependency(%q<shoulda>.freeze, [">= 0"])
|
87
|
-
s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
|
88
|
-
s.add_dependency(%q<bundler>.freeze, ["~> 1.0"])
|
78
|
+
s.add_dependency(%q<ruby2ruby>.freeze, [">= 2.4.0"])
|
79
|
+
s.add_dependency(%q<ruby_parser>.freeze, [">= 3.10.1"])
|
80
|
+
s.add_dependency(%q<sexp_processor>.freeze, [">= 4.10.0"])
|
89
81
|
s.add_dependency(%q<jeweler>.freeze, [">= 0"])
|
90
|
-
s.add_dependency(%q<
|
82
|
+
s.add_dependency(%q<rake>.freeze, [">= 0"])
|
83
|
+
s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
|
91
84
|
s.add_dependency(%q<simplecov>.freeze, [">= 0"])
|
92
85
|
s.add_dependency(%q<test-unit>.freeze, [">= 0"])
|
93
|
-
s.add_dependency(%q<rake>.freeze, [">= 0"])
|
94
86
|
end
|
95
87
|
end
|
96
88
|
|
data/test/test_helper.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
if
|
1
|
+
if ENV['COVERAGE']
|
2
2
|
require 'simplecov'
|
3
3
|
SimpleCov.start {add_filter 'test_'}
|
4
4
|
end
|
@@ -22,7 +22,7 @@ module TestHelper
|
|
22
22
|
'@article.comment_class.new',
|
23
23
|
'String.instance_variable_set :@a, :a' ]
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def security_error_raising_calls
|
27
27
|
[ "class A\n end",
|
28
28
|
'File.open("/etc/passwd")',
|
@@ -42,10 +42,10 @@ module TestHelper
|
|
42
42
|
"attr_reader :a",
|
43
43
|
'URI("http://google.com")',
|
44
44
|
"`ls -a`", "exec('echo *')", "syscall 4, 1, 'hello', 5", "system('touch /tmp/helloworld')",
|
45
|
-
"abort",
|
45
|
+
"abort",
|
46
46
|
"exit(0)", "exit!(0)", "at_exit{'goodbye'}",
|
47
47
|
"autoload(::MyModule, 'my_module.rb')",
|
48
|
-
"binding",
|
48
|
+
"binding",
|
49
49
|
"callcc{|cont| cont.call}",
|
50
50
|
'eval %Q(send(:system, "ls -a"))',
|
51
51
|
"fork",
|
@@ -58,12 +58,12 @@ module TestHelper
|
|
58
58
|
"open('/etc/passwd'){|f| f.read}",
|
59
59
|
"p 'text'", "pretty_inspect",
|
60
60
|
# "print 'text'", "puts 'text'", allowed and buffered these (see ScopeObject)
|
61
|
-
"printf 'text'", "putc 'a'",
|
61
|
+
"printf 'text'", "putc 'a'",
|
62
62
|
"raise RuntimeError, 'should not happen'",
|
63
|
-
"rand(0)", "srand(0)",
|
63
|
+
"rand(0)", "srand(0)",
|
64
64
|
"set_trace_func proc{|event| puts event}", "trace_var :$_, proc {|v| puts v }", "untrace_var :$_",
|
65
|
-
"sleep", "sleep(0)",
|
66
|
-
"test(1, a, b)",
|
65
|
+
"sleep", "sleep(0)",
|
66
|
+
"test(1, a, b)",
|
67
67
|
"Signal.trap(0, proc { puts 'Terminating: #{$$}' })",
|
68
68
|
"warn 'warning'",
|
69
69
|
'Array.new' ]
|
@@ -77,31 +77,31 @@ module TestHelper
|
|
77
77
|
def assert_raise_security(code = nil, assigns = {}, locals = {}, &block)
|
78
78
|
assert_raise_safemode_error(Safemode::SecurityError, code, assigns, locals, &block)
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
def assert_raise_safemode_error(error, code, assigns = {}, locals = {})
|
82
82
|
code = yield(code) if block_given?
|
83
83
|
assert_raise(error, code) { safebox_eval(code, assigns, locals) }
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
def safebox_eval(code, assigns = {}, locals = {})
|
87
87
|
# puts Safemode::Parser.jail(code)
|
88
88
|
Safemode::Box.new.eval code, assigns, locals
|
89
|
-
end
|
89
|
+
end
|
90
90
|
end
|
91
91
|
|
92
92
|
class Article
|
93
93
|
def is_article?
|
94
94
|
true
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
def title
|
98
98
|
'an article title'
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
def to_jail
|
102
102
|
Article::Jail.new self
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
def comments
|
106
106
|
[Comment.new(self), Comment.new(self)]
|
107
107
|
end
|
@@ -117,15 +117,15 @@ end
|
|
117
117
|
|
118
118
|
class Comment
|
119
119
|
attr_reader :article
|
120
|
-
|
120
|
+
|
121
121
|
def initialize(article)
|
122
122
|
@article = article
|
123
123
|
end
|
124
|
-
|
124
|
+
|
125
125
|
def text
|
126
126
|
"comment #{object_id}"
|
127
127
|
end
|
128
|
-
|
128
|
+
|
129
129
|
def to_jail
|
130
130
|
Comment::Jail.new self
|
131
131
|
end
|
@@ -145,7 +145,7 @@ end
|
|
145
145
|
|
146
146
|
class Article::Jail < Safemode::Jail
|
147
147
|
allow :title, :comments, :is_article?, :comment_class
|
148
|
-
|
148
|
+
|
149
149
|
def author_name
|
150
150
|
"this article's author name"
|
151
151
|
end
|
data/test/test_jail.rb
CHANGED
@@ -24,8 +24,7 @@ class TestJail < Test::Unit::TestCase
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def test_jail_instances_should_have_limited_methods
|
27
|
-
expected = ["class", "method_missing", "methods", "respond_to?", "
|
28
|
-
expected.delete('respond_to_missing?') if RUBY_VERSION > '1.9.3' # respond_to_missing? is private in rubies above 1.9.3
|
27
|
+
expected = ["class", "method_missing", "methods", "respond_to?", "to_jail", "to_s", "instance_variable_get"]
|
29
28
|
objects.each do |object|
|
30
29
|
assert_equal expected.sort, reject_pretty_methods(object.to_jail.methods.map(&:to_s).sort)
|
31
30
|
end
|
@@ -37,8 +36,12 @@ class TestJail < Test::Unit::TestCase
|
|
37
36
|
"allow_instance_method", "allow_class_method", "allowed_instance_method?",
|
38
37
|
"allowed_class_method?", "allowed_instance_methods", "allowed_class_methods",
|
39
38
|
"<", # < needed in Rails Object#subclasses_of
|
40
|
-
"ancestors", "==" # ancestors and == needed in Rails::Generator::Spec#lookup_class
|
41
|
-
|
39
|
+
"ancestors", "=="] # ancestors and == needed in Rails::Generator::Spec#lookup_class
|
40
|
+
|
41
|
+
if defined?(JRUBY_VERSION)
|
42
|
+
(expected << ['method_missing', 'singleton_method_undefined', 'singleton_method_added']).flatten! # needed for running under jruby
|
43
|
+
end
|
44
|
+
|
42
45
|
objects.each do |object|
|
43
46
|
assert_equal expected.sort, reject_pretty_methods(object.to_jail.class.methods.map(&:to_s).sort)
|
44
47
|
end
|
data/test/test_safemode_eval.rb
CHANGED
@@ -2,7 +2,7 @@ require File.join(File.dirname(__FILE__), 'test_helper')
|
|
2
2
|
|
3
3
|
class TestSafemodeEval < Test::Unit::TestCase
|
4
4
|
include TestHelper
|
5
|
-
|
5
|
+
|
6
6
|
def setup
|
7
7
|
@box = Safemode::Box.new
|
8
8
|
@locals = { :article => Article.new }
|
@@ -18,14 +18,10 @@ class TestSafemodeEval < Test::Unit::TestCase
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_unary_operators_on_instances_of_boolean_vars
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
assert !@box.eval('!true')
|
26
|
-
else
|
27
|
-
p "no unary ops under 1.8.7!"
|
28
|
-
end
|
21
|
+
assert @box.eval('not false')
|
22
|
+
assert @box.eval('!false')
|
23
|
+
assert !@box.eval('not true')
|
24
|
+
assert !@box.eval('!true')
|
29
25
|
end
|
30
26
|
|
31
27
|
def test_false_class_ops
|
@@ -55,35 +51,35 @@ class TestSafemodeEval < Test::Unit::TestCase
|
|
55
51
|
def test_should_turn_assigns_to_jails
|
56
52
|
assert_raise_no_method "@article.system", @assigns
|
57
53
|
end
|
58
|
-
|
54
|
+
|
59
55
|
def test_should_turn_locals_to_jails
|
60
56
|
assert_raise(Safemode::NoMethodError){ @box.eval "article.system", {}, @locals }
|
61
57
|
end
|
62
|
-
|
58
|
+
|
63
59
|
def test_should_allow_method_access_on_assigns
|
64
60
|
assert_nothing_raised{ @box.eval "@article.title", @assigns }
|
65
61
|
end
|
66
|
-
|
62
|
+
|
67
63
|
def test_should_allow_method_access_on_locals
|
68
64
|
assert_nothing_raised{ @box.eval("article.title", {}, @locals) }
|
69
65
|
end
|
70
|
-
|
66
|
+
|
71
67
|
def test_should_not_raise_on_if_using_return_values
|
72
68
|
assert_nothing_raised{ @box.eval "if @article.is_article? then 1 end", @assigns }
|
73
69
|
end
|
74
|
-
|
70
|
+
|
75
71
|
def test_should_work_with_if_using_return_values
|
76
72
|
assert_equal @box.eval("if @article.is_article? then 1 end", @assigns), 1
|
77
73
|
end
|
78
|
-
|
74
|
+
|
79
75
|
def test__FILE__should_not_render_filename
|
80
76
|
assert_equal '(string)', @box.eval("__FILE__")
|
81
77
|
end
|
82
|
-
|
78
|
+
|
83
79
|
def test_interpolated_xstr_should_raise_security
|
84
80
|
assert_raise_security '"#{`ls -a`}"'
|
85
|
-
end
|
86
|
-
|
81
|
+
end
|
82
|
+
|
87
83
|
TestHelper.no_method_error_raising_calls.each do |call|
|
88
84
|
call.gsub!('"', '\\\\"')
|
89
85
|
class_eval %Q(
|
@@ -100,6 +96,6 @@ class TestSafemodeEval < Test::Unit::TestCase
|
|
100
96
|
assert_raise_security "#{call}", @assigns, @locals
|
101
97
|
end
|
102
98
|
)
|
103
|
-
end
|
99
|
+
end
|
104
100
|
|
105
101
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: safemode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sven Fuchs
|
@@ -13,92 +13,50 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date:
|
16
|
+
date: 2020-08-31 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
|
-
- !ruby/object:Gem::Dependency
|
19
|
-
name: sexp_processor
|
20
|
-
requirement: !ruby/object:Gem::Requirement
|
21
|
-
requirements:
|
22
|
-
- - ">="
|
23
|
-
- !ruby/object:Gem::Version
|
24
|
-
version: 4.3.0
|
25
|
-
type: :runtime
|
26
|
-
prerelease: false
|
27
|
-
version_requirements: !ruby/object:Gem::Requirement
|
28
|
-
requirements:
|
29
|
-
- - ">="
|
30
|
-
- !ruby/object:Gem::Version
|
31
|
-
version: 4.3.0
|
32
18
|
- !ruby/object:Gem::Dependency
|
33
19
|
name: ruby2ruby
|
34
20
|
requirement: !ruby/object:Gem::Requirement
|
35
21
|
requirements:
|
36
22
|
- - ">="
|
37
23
|
- !ruby/object:Gem::Version
|
38
|
-
version: 2.0
|
24
|
+
version: 2.4.0
|
39
25
|
type: :runtime
|
40
26
|
prerelease: false
|
41
27
|
version_requirements: !ruby/object:Gem::Requirement
|
42
28
|
requirements:
|
43
29
|
- - ">="
|
44
30
|
- !ruby/object:Gem::Version
|
45
|
-
version: 2.0
|
31
|
+
version: 2.4.0
|
46
32
|
- !ruby/object:Gem::Dependency
|
47
33
|
name: ruby_parser
|
48
34
|
requirement: !ruby/object:Gem::Requirement
|
49
35
|
requirements:
|
50
36
|
- - ">="
|
51
37
|
- !ruby/object:Gem::Version
|
52
|
-
version: 3.
|
38
|
+
version: 3.10.1
|
53
39
|
type: :runtime
|
54
40
|
prerelease: false
|
55
41
|
version_requirements: !ruby/object:Gem::Requirement
|
56
42
|
requirements:
|
57
43
|
- - ">="
|
58
44
|
- !ruby/object:Gem::Version
|
59
|
-
version: 3.
|
45
|
+
version: 3.10.1
|
60
46
|
- !ruby/object:Gem::Dependency
|
61
|
-
name:
|
47
|
+
name: sexp_processor
|
62
48
|
requirement: !ruby/object:Gem::Requirement
|
63
49
|
requirements:
|
64
50
|
- - ">="
|
65
51
|
- !ruby/object:Gem::Version
|
66
|
-
version:
|
67
|
-
type: :
|
52
|
+
version: 4.10.0
|
53
|
+
type: :runtime
|
68
54
|
prerelease: false
|
69
55
|
version_requirements: !ruby/object:Gem::Requirement
|
70
56
|
requirements:
|
71
57
|
- - ">="
|
72
58
|
- !ruby/object:Gem::Version
|
73
|
-
version:
|
74
|
-
- !ruby/object:Gem::Dependency
|
75
|
-
name: rdoc
|
76
|
-
requirement: !ruby/object:Gem::Requirement
|
77
|
-
requirements:
|
78
|
-
- - "~>"
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
version: '3.12'
|
81
|
-
type: :development
|
82
|
-
prerelease: false
|
83
|
-
version_requirements: !ruby/object:Gem::Requirement
|
84
|
-
requirements:
|
85
|
-
- - "~>"
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
version: '3.12'
|
88
|
-
- !ruby/object:Gem::Dependency
|
89
|
-
name: bundler
|
90
|
-
requirement: !ruby/object:Gem::Requirement
|
91
|
-
requirements:
|
92
|
-
- - "~>"
|
93
|
-
- !ruby/object:Gem::Version
|
94
|
-
version: '1.0'
|
95
|
-
type: :development
|
96
|
-
prerelease: false
|
97
|
-
version_requirements: !ruby/object:Gem::Requirement
|
98
|
-
requirements:
|
99
|
-
- - "~>"
|
100
|
-
- !ruby/object:Gem::Version
|
101
|
-
version: '1.0'
|
59
|
+
version: 4.10.0
|
102
60
|
- !ruby/object:Gem::Dependency
|
103
61
|
name: jeweler
|
104
62
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,7 +72,7 @@ dependencies:
|
|
114
72
|
- !ruby/object:Gem::Version
|
115
73
|
version: '0'
|
116
74
|
- !ruby/object:Gem::Dependency
|
117
|
-
name:
|
75
|
+
name: rake
|
118
76
|
requirement: !ruby/object:Gem::Requirement
|
119
77
|
requirements:
|
120
78
|
- - ">="
|
@@ -128,21 +86,21 @@ dependencies:
|
|
128
86
|
- !ruby/object:Gem::Version
|
129
87
|
version: '0'
|
130
88
|
- !ruby/object:Gem::Dependency
|
131
|
-
name:
|
89
|
+
name: rdoc
|
132
90
|
requirement: !ruby/object:Gem::Requirement
|
133
91
|
requirements:
|
134
|
-
- - "
|
92
|
+
- - "~>"
|
135
93
|
- !ruby/object:Gem::Version
|
136
|
-
version: '
|
94
|
+
version: '3.12'
|
137
95
|
type: :development
|
138
96
|
prerelease: false
|
139
97
|
version_requirements: !ruby/object:Gem::Requirement
|
140
98
|
requirements:
|
141
|
-
- - "
|
99
|
+
- - "~>"
|
142
100
|
- !ruby/object:Gem::Version
|
143
|
-
version: '
|
101
|
+
version: '3.12'
|
144
102
|
- !ruby/object:Gem::Dependency
|
145
|
-
name:
|
103
|
+
name: simplecov
|
146
104
|
requirement: !ruby/object:Gem::Requirement
|
147
105
|
requirements:
|
148
106
|
- - ">="
|
@@ -156,7 +114,7 @@ dependencies:
|
|
156
114
|
- !ruby/object:Gem::Version
|
157
115
|
version: '0'
|
158
116
|
- !ruby/object:Gem::Dependency
|
159
|
-
name:
|
117
|
+
name: test-unit
|
160
118
|
requirement: !ruby/object:Gem::Requirement
|
161
119
|
requirements:
|
162
120
|
- - ">="
|
@@ -177,6 +135,7 @@ extensions: []
|
|
177
135
|
extra_rdoc_files:
|
178
136
|
- README.markdown
|
179
137
|
files:
|
138
|
+
- ".travis.yml"
|
180
139
|
- Gemfile
|
181
140
|
- LICENCSE
|
182
141
|
- README.markdown
|
@@ -224,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
224
183
|
version: '0'
|
225
184
|
requirements: []
|
226
185
|
rubyforge_project:
|
227
|
-
rubygems_version: 2.6
|
186
|
+
rubygems_version: 2.7.6
|
228
187
|
signing_key:
|
229
188
|
specification_version: 4
|
230
189
|
summary: A library for safe evaluation of Ruby code based on ParseTree/RubyParser
|