shikashi-the-north 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/AUTHORS +8 -0
- data/CHANGELOG +45 -0
- data/Gemfile +4 -0
- data/LICENSE +674 -0
- data/README +222 -0
- data/Rakefile +40 -0
- data/TODO +2 -0
- data/examples/basic/example.rb +29 -0
- data/examples/basic/example1.rb +12 -0
- data/examples/basic/example2.rb +24 -0
- data/examples/basic/example3.rb +43 -0
- data/examples/basic/example4.rb +33 -0
- data/examples/basic/example5.rb +38 -0
- data/examples/basic/example6.rb +16 -0
- data/examples/basic/example7.rb +15 -0
- data/examples/basic/example8.rb +29 -0
- data/examples/benchmark/bm1.rb +29 -0
- data/examples/benchmark/bm2.rb +25 -0
- data/examples/timeout/example1.rb +9 -0
- data/lib/shikashi.rb +23 -0
- data/lib/shikashi/pick_argument.rb +81 -0
- data/lib/shikashi/privileges.rb +418 -0
- data/lib/shikashi/privileges/classes.rb +29 -0
- data/lib/shikashi/privileges/exceptions.rb +29 -0
- data/lib/shikashi/privileges/singleton_methods.rb +29 -0
- data/lib/shikashi/sandbox.rb +530 -0
- data/shikashi.gemspec +23 -0
- data/spec/functional/encoding_spec.rb +39 -0
- data/spec/functional/timeout_spec.rb +57 -0
- data/spec/sandbox/privileges_sugar_syntax_spec.rb +160 -0
- data/spec/sandbox/sandbox_hook_handler_spec.rb +181 -0
- data/spec/sandbox/sandbox_spec.rb +331 -0
- data/spec/sandbox/sugar_syntax_spec.rb +36 -0
- data/spec/security/system_calls_spec.rb +59 -0
- metadata +117 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
# "hello world" from within the sandbox
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "shikashi"
|
5
|
+
|
6
|
+
include Shikashi
|
7
|
+
|
8
|
+
priv = Privileges.allow_method(:print).allow_global_write(:$a)
|
9
|
+
Sandbox.run(priv,
|
10
|
+
'
|
11
|
+
$a = 9
|
12
|
+
print "assigned 9 to $a\n"
|
13
|
+
'
|
14
|
+
)
|
15
|
+
|
16
|
+
p $a
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "shikashi"
|
3
|
+
|
4
|
+
include Shikashi
|
5
|
+
|
6
|
+
module SandboxModule
|
7
|
+
end
|
8
|
+
|
9
|
+
class X
|
10
|
+
def foo
|
11
|
+
print "X#foo\n"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Sandbox.new.run( "
|
16
|
+
class ::X
|
17
|
+
def foo
|
18
|
+
print \"foo defined inside the sandbox\\n\"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
", Privileges.allow_method(:print), :base_namespace => SandboxModule)
|
22
|
+
|
23
|
+
|
24
|
+
x = X.new # X class is not affected by the sandbox (The X Class defined in the sandbox is SandboxModule::X)
|
25
|
+
x.foo
|
26
|
+
|
27
|
+
x = SandboxModule::X.new
|
28
|
+
x.foo
|
29
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "shikashi"
|
3
|
+
require "benchmark"
|
4
|
+
|
5
|
+
code = "class X
|
6
|
+
def foo(n)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
X.new.foo(1000)
|
10
|
+
"
|
11
|
+
|
12
|
+
s = Shikashi::Sandbox.new
|
13
|
+
|
14
|
+
Benchmark.bm(7) do |x|
|
15
|
+
|
16
|
+
x.report("normal") {
|
17
|
+
1000.times do
|
18
|
+
s.run(code, Shikashi::Privileges.allow_method(:new))
|
19
|
+
end
|
20
|
+
}
|
21
|
+
|
22
|
+
x.report("packet") {
|
23
|
+
packet = s.packet(code, Shikashi::Privileges.allow_method(:new))
|
24
|
+
1000.times do
|
25
|
+
packet.run
|
26
|
+
end
|
27
|
+
}
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "shikashi"
|
3
|
+
require "benchmark"
|
4
|
+
|
5
|
+
s = Shikashi::Sandbox.new
|
6
|
+
|
7
|
+
class NilClass
|
8
|
+
def foo
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Benchmark.bm(7) do |x|
|
13
|
+
|
14
|
+
x.report {
|
15
|
+
|
16
|
+
code = "
|
17
|
+
500000.times {
|
18
|
+
nil.foo
|
19
|
+
}
|
20
|
+
"
|
21
|
+
|
22
|
+
s.run code, Shikashi::Privileges.allow_method(:times).allow_method(:foo)
|
23
|
+
}
|
24
|
+
|
25
|
+
end
|
data/lib/shikashi.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the shikashi project, http://github.com/tario/shikashi
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
shikashi is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
shikashi is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with shikashi. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
require "shikashi/sandbox"
|
22
|
+
|
23
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the shikashi project, http://github.com/tario/shikashi
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
shikashi is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
shikashi is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with shikashi. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
module Arguments
|
22
|
+
module NoDefault
|
23
|
+
end
|
24
|
+
end
|
25
|
+
class Array
|
26
|
+
|
27
|
+
def pick_by_class(klass)
|
28
|
+
klassary = self.select{|x| x.instance_of? klass}
|
29
|
+
if klassary.size > 1
|
30
|
+
raise ArgumentError, "ambiguous parameters of class #{klass}"
|
31
|
+
elsif klassary.size == 1
|
32
|
+
klassary.first
|
33
|
+
else
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def pick(*args)
|
40
|
+
|
41
|
+
klass = args.pick_by_class Class
|
42
|
+
hash_key = args.pick_by_class Symbol
|
43
|
+
|
44
|
+
ary = []
|
45
|
+
|
46
|
+
if klass
|
47
|
+
ary = self.select{|x| x.instance_of? klass}
|
48
|
+
|
49
|
+
if ary.size > 1
|
50
|
+
raise ArgumentError, "ambiguous parameters of class #{klass}"
|
51
|
+
end
|
52
|
+
else
|
53
|
+
ary = []
|
54
|
+
end
|
55
|
+
|
56
|
+
if hash_key
|
57
|
+
each do |x|
|
58
|
+
if x.instance_of? Hash
|
59
|
+
if x[hash_key]
|
60
|
+
ary << x[hash_key]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
if ary.size > 1
|
66
|
+
raise ArgumentError, "ambiguous parameters of class #{klass} and key '#{hash_key}'"
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
if ary.size == 1
|
72
|
+
return ary.first
|
73
|
+
end
|
74
|
+
|
75
|
+
unless block_given?
|
76
|
+
raise ArgumentError, "missing mandatory argument '#{hash_key}' or of class #{klass}"
|
77
|
+
end
|
78
|
+
|
79
|
+
yield
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,418 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the shikashi project, http://github.com/tario/shikashi
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
shikashi is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
shikashi is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with shikashi. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
require "find"
|
22
|
+
|
23
|
+
module Shikashi
|
24
|
+
#
|
25
|
+
#The Privileges class represent permissions about methods and objects
|
26
|
+
#
|
27
|
+
class Privileges
|
28
|
+
|
29
|
+
private
|
30
|
+
def self.load_privilege_packages
|
31
|
+
Find.find(__FILE__.split("/")[0..-2].join("/") + "/privileges" ) do |path|
|
32
|
+
if path =~ /\.rb$/
|
33
|
+
require path
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
load_privilege_packages
|
39
|
+
public
|
40
|
+
|
41
|
+
# Used in Privileges to store information about specified method permissions
|
42
|
+
class AllowedMethods
|
43
|
+
def initialize(privileges = nil)
|
44
|
+
@privileges = privileges
|
45
|
+
@allowed_methods = Array.new
|
46
|
+
@redirect_hash = Hash.new
|
47
|
+
@all = false
|
48
|
+
end
|
49
|
+
|
50
|
+
#return true if the method named method_name is allowed
|
51
|
+
#Example
|
52
|
+
#
|
53
|
+
# allowed_methods = AllowedMethods.new
|
54
|
+
# allowed_methods.allowed? :foo # => false
|
55
|
+
# allowed_methods.allow :foo
|
56
|
+
# allowed_methods.allowed? :foo # => true
|
57
|
+
# allowed_methods.allow_all
|
58
|
+
# allowed_methods.allowed? :bar # => true
|
59
|
+
#
|
60
|
+
# Privileges#instance_of, Privileges#methods_of and Privileges#object returns the corresponding
|
61
|
+
# instance of AllowedMethods
|
62
|
+
def allowed?(method_name)
|
63
|
+
if @all
|
64
|
+
true
|
65
|
+
else
|
66
|
+
@allowed_methods.include?(method_name)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#Specifies that a method or list of methods are allowed
|
71
|
+
#Example
|
72
|
+
#
|
73
|
+
# allowed_methods = AllowedMethods.new
|
74
|
+
# allowed_methods.allow :foo
|
75
|
+
# allowed_methods.allow :foo, :bar
|
76
|
+
# allowed_methods.allow :foo, :bar, :test
|
77
|
+
#
|
78
|
+
def allow(*method_names)
|
79
|
+
method_names.each do |mn|
|
80
|
+
@allowed_methods << mn
|
81
|
+
end
|
82
|
+
|
83
|
+
@privileges
|
84
|
+
end
|
85
|
+
|
86
|
+
#Specifies that any method is allowed
|
87
|
+
def allow_all
|
88
|
+
@all = true
|
89
|
+
|
90
|
+
@privileges
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
def initialize
|
96
|
+
@allowed_objects = Hash.new
|
97
|
+
@allowed_kinds = Hash.new
|
98
|
+
@allowed_classes = Hash.new
|
99
|
+
@allowed_instances = Hash.new
|
100
|
+
@allowed_methods = Array.new
|
101
|
+
@allowed_klass_methods = Hash.new
|
102
|
+
@allowed_read_globals = Array.new
|
103
|
+
@allowed_read_consts = Array.new
|
104
|
+
@allowed_write_globals = Array.new
|
105
|
+
@allowed_write_consts = Array.new
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
def hash_entry(hash, key)
|
110
|
+
tmp = hash[key]
|
111
|
+
unless tmp
|
112
|
+
tmp = AllowedMethods.new(self)
|
113
|
+
hash[key] = tmp
|
114
|
+
end
|
115
|
+
tmp
|
116
|
+
end
|
117
|
+
public
|
118
|
+
|
119
|
+
#
|
120
|
+
#Specifies the methods allowed for an specific object
|
121
|
+
#
|
122
|
+
#Example 1:
|
123
|
+
# privileges.object(Hash).allow :new
|
124
|
+
#
|
125
|
+
|
126
|
+
def object(obj)
|
127
|
+
hash_entry(@allowed_objects, obj.object_id)
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
#Specifies the methods allowed for the instances of a class
|
132
|
+
#
|
133
|
+
#Example 1:
|
134
|
+
# privileges.instances_of(Array).allow :each # allow calls of methods named "each" over instances of Array
|
135
|
+
#
|
136
|
+
#Example 2:
|
137
|
+
# privileges.instances_of(Array).allow :select, map # allow calls of methods named "each" and "map" over instances of Array
|
138
|
+
#
|
139
|
+
#Example 3:
|
140
|
+
# privileges.instances_of(Hash).allow_all # allow any method call over instances of Hash
|
141
|
+
|
142
|
+
def instances_of(klass)
|
143
|
+
hash_entry(@allowed_instances, klass.object_id)
|
144
|
+
end
|
145
|
+
|
146
|
+
#
|
147
|
+
#Specifies the methods allowed for an implementation in specific class
|
148
|
+
#
|
149
|
+
#Example 1:
|
150
|
+
# privileges.methods_of(X).allow :foo
|
151
|
+
#
|
152
|
+
# ...
|
153
|
+
# class X
|
154
|
+
# def foo # allowed :)
|
155
|
+
# end
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
# class Y < X
|
159
|
+
# def foo # disallowed
|
160
|
+
# end
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
# X.new.foo # allowed
|
164
|
+
# Y.new.foo # disallowed: SecurityError
|
165
|
+
# ...
|
166
|
+
#
|
167
|
+
def methods_of(klass)
|
168
|
+
hash_entry(@allowed_klass_methods, klass.object_id)
|
169
|
+
end
|
170
|
+
|
171
|
+
#allow the execution of method named method_name whereever
|
172
|
+
#
|
173
|
+
#Example:
|
174
|
+
# privileges.allow_method(:foo)
|
175
|
+
#
|
176
|
+
|
177
|
+
def allow_method(method_name)
|
178
|
+
@allowed_methods << method_name.to_sym
|
179
|
+
self
|
180
|
+
end
|
181
|
+
|
182
|
+
def allow?(klass, recv, method_name, method_id)
|
183
|
+
|
184
|
+
m = nil
|
185
|
+
m = klass.instance_method(method_name) if method_name
|
186
|
+
|
187
|
+
begin
|
188
|
+
return true if @allowed_methods.include?(method_name)
|
189
|
+
|
190
|
+
tmp = @allowed_objects[recv.object_id]
|
191
|
+
if tmp
|
192
|
+
if tmp.allowed?(method_name)
|
193
|
+
@last_allowed = tmp
|
194
|
+
return true
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
if m
|
199
|
+
tmp = @allowed_klass_methods[m.owner.object_id]
|
200
|
+
if tmp
|
201
|
+
if tmp.allowed?(method_name)
|
202
|
+
@last_allowed = tmp
|
203
|
+
return true
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
if recv.instance_of? Class
|
209
|
+
last_class = recv
|
210
|
+
|
211
|
+
while true
|
212
|
+
tmp = @allowed_classes[last_class.object_id]
|
213
|
+
if tmp
|
214
|
+
if tmp.allowed?(method_name)
|
215
|
+
@last_allowed = tmp
|
216
|
+
return true
|
217
|
+
end
|
218
|
+
end
|
219
|
+
if last_class
|
220
|
+
break if last_class == Object
|
221
|
+
last_class = last_class.superclass
|
222
|
+
else
|
223
|
+
break
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
last_class = recv.class
|
229
|
+
while true
|
230
|
+
tmp = @allowed_kinds[last_class.object_id]
|
231
|
+
if tmp
|
232
|
+
if tmp.allowed?(method_name)
|
233
|
+
@last_allowed = tmp
|
234
|
+
return true
|
235
|
+
end
|
236
|
+
end
|
237
|
+
if last_class
|
238
|
+
break if last_class == Object
|
239
|
+
last_class = last_class.superclass
|
240
|
+
else
|
241
|
+
break
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
tmp = @allowed_instances[recv.class.object_id]
|
246
|
+
if tmp
|
247
|
+
if tmp.allowed?(method_name)
|
248
|
+
@last_allowed = tmp
|
249
|
+
return true
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
false
|
254
|
+
rescue Exception => e
|
255
|
+
print "ERROR: #{e}\n"
|
256
|
+
print e.backtrace.join("\n")
|
257
|
+
false
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def xstr_allowed?
|
262
|
+
@xstr_allowed
|
263
|
+
end
|
264
|
+
|
265
|
+
def global_read_allowed?(varname)
|
266
|
+
@allowed_read_globals.include? varname
|
267
|
+
end
|
268
|
+
|
269
|
+
def global_write_allowed?(varname)
|
270
|
+
@allowed_write_globals.include? varname
|
271
|
+
end
|
272
|
+
|
273
|
+
def const_read_allowed?(varname)
|
274
|
+
@allowed_read_consts.include? varname
|
275
|
+
end
|
276
|
+
|
277
|
+
def const_write_allowed?(varname)
|
278
|
+
@allowed_write_consts.include? varname
|
279
|
+
end
|
280
|
+
|
281
|
+
# Enables the permissions needed to execute system calls from the script
|
282
|
+
#
|
283
|
+
# Example:
|
284
|
+
#
|
285
|
+
# s = Sandbox.new
|
286
|
+
# priv = Privileges.new
|
287
|
+
#
|
288
|
+
# priv.allow_xstr
|
289
|
+
#
|
290
|
+
# s.run(priv, '
|
291
|
+
# %x[ls -l]
|
292
|
+
# ')
|
293
|
+
#
|
294
|
+
#
|
295
|
+
# Example 2:
|
296
|
+
#
|
297
|
+
# Sandbox.run('%x[ls -l]', Privileges.allow_xstr)
|
298
|
+
#
|
299
|
+
def allow_xstr
|
300
|
+
@xstr_allowed = true
|
301
|
+
|
302
|
+
self
|
303
|
+
end
|
304
|
+
|
305
|
+
# Enables the permissions needed to read one or more global variables
|
306
|
+
#
|
307
|
+
# Example:
|
308
|
+
#
|
309
|
+
# s = Sandbox.new
|
310
|
+
# priv = Privileges.new
|
311
|
+
#
|
312
|
+
# priv.allow_method :print
|
313
|
+
# priv.allow_global_read :$a
|
314
|
+
#
|
315
|
+
# $a = 9
|
316
|
+
#
|
317
|
+
# s.run(priv, '
|
318
|
+
# print "$a value:", $a, "s\n"
|
319
|
+
# ')
|
320
|
+
#
|
321
|
+
# Example 2
|
322
|
+
#
|
323
|
+
# Sandbox.run('
|
324
|
+
# print "$a value:", $a, "s\n"
|
325
|
+
# print "$b value:", $b, "s\n"
|
326
|
+
# ', Privileges.allow_global_read(:$a,:$b) )
|
327
|
+
#
|
328
|
+
def allow_global_read( *varnames )
|
329
|
+
varnames.each do |varname|
|
330
|
+
@allowed_read_globals << varname.to_sym
|
331
|
+
end
|
332
|
+
|
333
|
+
self
|
334
|
+
end
|
335
|
+
|
336
|
+
# Enables the permissions needed to create or change one or more global variables
|
337
|
+
#
|
338
|
+
# Example:
|
339
|
+
#
|
340
|
+
# s = Sandbox.new
|
341
|
+
# priv = Privileges.new
|
342
|
+
#
|
343
|
+
# priv.allow_method :print
|
344
|
+
# priv.allow_global_write :$a
|
345
|
+
#
|
346
|
+
# s.run(priv, '
|
347
|
+
# $a = 9
|
348
|
+
# print "assigned 9 to $a\n"
|
349
|
+
# ')
|
350
|
+
#
|
351
|
+
# p $a
|
352
|
+
#
|
353
|
+
def allow_global_write( *varnames )
|
354
|
+
varnames.each do |varname|
|
355
|
+
@allowed_write_globals << varname.to_sym
|
356
|
+
end
|
357
|
+
|
358
|
+
self
|
359
|
+
end
|
360
|
+
|
361
|
+
|
362
|
+
# Enables the permissions needed to create or change one or more constants
|
363
|
+
#
|
364
|
+
# Example:
|
365
|
+
# s = Sandbox.new
|
366
|
+
# priv = Privileges.new
|
367
|
+
#
|
368
|
+
# priv.allow_method :print
|
369
|
+
# priv.allow_const_write "Object::A"
|
370
|
+
#
|
371
|
+
# s.run(priv, '
|
372
|
+
# print "assigned 8 to Object::A\n"
|
373
|
+
# A = 8
|
374
|
+
# ')
|
375
|
+
#
|
376
|
+
# p A
|
377
|
+
|
378
|
+
def allow_const_write( *varnames )
|
379
|
+
varnames.each do |varname|
|
380
|
+
@allowed_write_consts << varname.to_s
|
381
|
+
end
|
382
|
+
self
|
383
|
+
end
|
384
|
+
|
385
|
+
# Enables the permissions needed to read one or more constants
|
386
|
+
#
|
387
|
+
# Example:
|
388
|
+
# s = Sandbox.new
|
389
|
+
# priv = Privileges.new
|
390
|
+
#
|
391
|
+
# priv.allow_method :print
|
392
|
+
# priv.allow_const_read "Object::A"
|
393
|
+
#
|
394
|
+
# A = 8
|
395
|
+
# s.run(priv, '
|
396
|
+
# print "assigned Object::A:", A,"\n"
|
397
|
+
# ')
|
398
|
+
#
|
399
|
+
def allow_const_read( *varnames )
|
400
|
+
varnames.each do |varname|
|
401
|
+
@allowed_read_consts << varname.to_s
|
402
|
+
end
|
403
|
+
|
404
|
+
self
|
405
|
+
end
|
406
|
+
|
407
|
+
|
408
|
+
class << self
|
409
|
+
(Shikashi::Privileges.instance_methods - Object.instance_methods).each do |mname|
|
410
|
+
define_method(mname) do |*args|
|
411
|
+
Shikashi::Privileges.new.send(mname, *args)
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
end
|
418
|
+
|