shikashi 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +3 -0
- data/CHANGELOG +1 -0
- data/README +199 -0
- data/Rakefile +48 -0
- data/TODO +0 -0
- data/examples/basic/example.rb +28 -0
- data/examples/basic/example1.rb +12 -0
- data/examples/basic/example2.rb +24 -0
- data/examples/basic/example3.rb +46 -0
- data/examples/basic/example4.rb +41 -0
- data/examples/basic/example5.rb +40 -0
- data/lib/shikashi.rb +23 -0
- data/lib/shikashi/pick_argument.rb +81 -0
- data/lib/shikashi/privileges.rb +294 -0
- data/lib/shikashi/privileges/classes.rb +28 -0
- data/lib/shikashi/privileges/exceptions.rb +29 -0
- data/lib/shikashi/privileges/singleton_methods.rb +28 -0
- data/lib/shikashi/sandbox.rb +381 -0
- metadata +81 -0
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,294 @@
|
|
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
|
44
|
+
@allowed_methods = Array.new
|
45
|
+
@redirect_hash = Hash.new
|
46
|
+
@all = false
|
47
|
+
end
|
48
|
+
|
49
|
+
#return true if the method named method_name is allowed
|
50
|
+
#Example
|
51
|
+
#
|
52
|
+
# allowed_methods = AllowedMethods.new
|
53
|
+
# allowed_methods.allowed? :foo # => false
|
54
|
+
# allowed_methods.allow :foo
|
55
|
+
# allowed_methods.allowed? :foo # => true
|
56
|
+
# allowed_methods.allow_all
|
57
|
+
# allowed_methods.allowed? :bar # => true
|
58
|
+
#
|
59
|
+
# Privileges#instance_of, Privileges#methods_of and Privileges#object returns the corresponding
|
60
|
+
# instance of AllowedMethods
|
61
|
+
def allowed?(method_name)
|
62
|
+
if @all
|
63
|
+
true
|
64
|
+
else
|
65
|
+
@allowed_methods.include?(method_name)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
#Specifies that a method or list of methods are allowed
|
70
|
+
#Example
|
71
|
+
#
|
72
|
+
# allowed_methods = AllowedMethods.new
|
73
|
+
# allowed_methods.allow :foo
|
74
|
+
# allowed_methods.allow :foo, :bar
|
75
|
+
# allowed_methods.allow :foo, :bar, :test
|
76
|
+
#
|
77
|
+
def allow(*method_names)
|
78
|
+
method_names.each do |mn|
|
79
|
+
@allowed_methods << mn
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#Specifies that any method is allowed
|
84
|
+
def allow_all
|
85
|
+
@all = true
|
86
|
+
end
|
87
|
+
|
88
|
+
def redirect(method_name, method_wrapper_class)
|
89
|
+
allow method_name
|
90
|
+
@redirect_hash[method_name] = method_wrapper_class
|
91
|
+
end
|
92
|
+
|
93
|
+
def handle_redirection(klass, recv, method_id, sandbox)
|
94
|
+
|
95
|
+
method_name = method_id.id2name
|
96
|
+
return nil unless method_name
|
97
|
+
|
98
|
+
rclass = @redirect_hash[method_name.to_sym]
|
99
|
+
|
100
|
+
if rclass
|
101
|
+
if block_given?
|
102
|
+
rclass.redirect_handler(klass, recv, method_name, method_id, sandbox) do |mh|
|
103
|
+
yield(mh)
|
104
|
+
end
|
105
|
+
else
|
106
|
+
rclass.redirect_handler(klass, recv, method_name, method_id, sandbox)
|
107
|
+
end
|
108
|
+
else
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def initialize
|
115
|
+
@allowed_objects = Hash.new
|
116
|
+
@allowed_kinds = Hash.new
|
117
|
+
@allowed_classes = Hash.new
|
118
|
+
@allowed_instances = Hash.new
|
119
|
+
@allowed_methods = Array.new
|
120
|
+
@allowed_klass_methods = Hash.new
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
def hash_entry(hash, key)
|
125
|
+
tmp = hash[key]
|
126
|
+
unless tmp
|
127
|
+
tmp = AllowedMethods.new
|
128
|
+
hash[key] = tmp
|
129
|
+
end
|
130
|
+
tmp
|
131
|
+
end
|
132
|
+
public
|
133
|
+
|
134
|
+
#
|
135
|
+
#Specifies the methods allowed for an specific object
|
136
|
+
#
|
137
|
+
#Example 1:
|
138
|
+
# privileges.object(Hash).allow :new
|
139
|
+
#
|
140
|
+
|
141
|
+
def object(obj)
|
142
|
+
hash_entry(@allowed_objects, obj.object_id)
|
143
|
+
end
|
144
|
+
|
145
|
+
#
|
146
|
+
#Specifies the methods allowed for the instances of a class
|
147
|
+
#
|
148
|
+
#Example 1:
|
149
|
+
# privileges.instances_of(Array).allow :each # allow calls of methods named "each" over instances of Array
|
150
|
+
#
|
151
|
+
#Example 2:
|
152
|
+
# privileges.instances_of(Array).allow :select, map # allow calls of methods named "each" and "map" over instances of Array
|
153
|
+
#
|
154
|
+
#Example 3:
|
155
|
+
# privileges.instances_of(Hash).allow_all # allow any method call over instances of Hash
|
156
|
+
|
157
|
+
def instances_of(klass)
|
158
|
+
hash_entry(@allowed_instances, klass.object_id)
|
159
|
+
end
|
160
|
+
|
161
|
+
#
|
162
|
+
#Specifies the methods allowed for an implementation in specific class
|
163
|
+
#
|
164
|
+
#Example 1:
|
165
|
+
# privileges.methods_of(X).allow :foo
|
166
|
+
#
|
167
|
+
# ...
|
168
|
+
# class X
|
169
|
+
# def foo # allowed :)
|
170
|
+
# end
|
171
|
+
# end
|
172
|
+
#
|
173
|
+
# class Y < X
|
174
|
+
# def foo # disallowed
|
175
|
+
# end
|
176
|
+
# end
|
177
|
+
#
|
178
|
+
# X.new.foo # allowed
|
179
|
+
# Y.new.foo # disallowed: SecurityError
|
180
|
+
# ...
|
181
|
+
#
|
182
|
+
def methods_of(klass)
|
183
|
+
hash_entry(@allowed_klass_methods, klass.object_id)
|
184
|
+
end
|
185
|
+
|
186
|
+
#allow the execution of method named method_name whereever
|
187
|
+
#
|
188
|
+
#Example:
|
189
|
+
# privileges.allow_method(:foo)
|
190
|
+
#
|
191
|
+
|
192
|
+
def allow_method(method_name)
|
193
|
+
@allowed_methods << method_name
|
194
|
+
end
|
195
|
+
|
196
|
+
def handle_redirection(klass, recv, method_id, sandbox)
|
197
|
+
if @last_allowed
|
198
|
+
|
199
|
+
if block_given?
|
200
|
+
@last_allowed.handle_redirection(klass, recv, method_id, sandbox) do |mh|
|
201
|
+
yield(mh)
|
202
|
+
end
|
203
|
+
else
|
204
|
+
@last_allowed.handle_redirection(klass, recv, method_id, sandbox)
|
205
|
+
end
|
206
|
+
else
|
207
|
+
nil
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
def allow?(klass, recv, method_name, method_id)
|
213
|
+
|
214
|
+
m = nil
|
215
|
+
m = klass.shadow.instance_method(method_name) if method_name
|
216
|
+
|
217
|
+
begin
|
218
|
+
return true if @allowed_methods.include?(method_name)
|
219
|
+
|
220
|
+
tmp = @allowed_objects[recv.object_id]
|
221
|
+
if tmp
|
222
|
+
if tmp.allowed?(method_name)
|
223
|
+
@last_allowed = tmp
|
224
|
+
return true
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
if m
|
229
|
+
tmp = @allowed_klass_methods[m.owner.object_id]
|
230
|
+
if tmp
|
231
|
+
if tmp.allowed?(method_name)
|
232
|
+
@last_allowed = tmp
|
233
|
+
return true
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
if recv.instance_of? Class
|
239
|
+
last_class = recv
|
240
|
+
|
241
|
+
while true
|
242
|
+
tmp = @allowed_classes[last_class.object_id]
|
243
|
+
if tmp
|
244
|
+
if tmp.allowed?(method_name)
|
245
|
+
@last_allowed = tmp
|
246
|
+
return true
|
247
|
+
end
|
248
|
+
end
|
249
|
+
if last_class
|
250
|
+
break if last_class == Object
|
251
|
+
last_class = last_class.superclass
|
252
|
+
else
|
253
|
+
break
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
last_class = recv.class
|
259
|
+
while true
|
260
|
+
tmp = @allowed_kinds[last_class.object_id]
|
261
|
+
if tmp
|
262
|
+
if tmp.allowed?(method_name)
|
263
|
+
@last_allowed = tmp
|
264
|
+
return true
|
265
|
+
end
|
266
|
+
end
|
267
|
+
if last_class
|
268
|
+
break if last_class == Object
|
269
|
+
last_class = last_class.superclass
|
270
|
+
else
|
271
|
+
break
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
tmp = @allowed_instances[recv.class.object_id]
|
276
|
+
if tmp
|
277
|
+
if tmp.allowed?(method_name)
|
278
|
+
@last_allowed = tmp
|
279
|
+
return true
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
false
|
284
|
+
rescue Exception => e
|
285
|
+
print "ERROR: #{e}\n"
|
286
|
+
print e.backtrace.join("\n")
|
287
|
+
false
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|
294
|
+
|
@@ -0,0 +1,28 @@
|
|
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 Shikashi
|
22
|
+
class Privileges
|
23
|
+
#Defines the permissions needed to declare classes within the sandbox
|
24
|
+
def allow_class_definitions
|
25
|
+
instances_of(Class).allow nil, :inherited, :method_added
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
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 Shikashi
|
22
|
+
class Privileges
|
23
|
+
#Define the permissions needed to raise exceptions within the sandbox
|
24
|
+
def allow_exceptions
|
25
|
+
allow_method :raise
|
26
|
+
methods_of(Exception).allow :backtrace, :set_backtrace, :exception
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|