shikashi 0.1.0
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.
- 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
|