xplenty-jruby_sandbox 0.2.4-java

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d06b08e73589246267426b4e93121d583a168c01
4
+ data.tar.gz: b72fcac1cc5956601d781cde42d74bae26516cf6
5
+ SHA512:
6
+ metadata.gz: cc6380715019cb8f27918bca1f673e7164d90631495ae1821fdf57ed31707cf16575dfc7c69c288cc01517447a1866e91a61f69de907c633c3238cfc1c7e7eca
7
+ data.tar.gz: d0ae61acb863f50a86df5dca25eb9630c74ceee64bbe6487aef1d54629ef890a045a796014dc4779b461b373e36a112d5964dc1dad1227ff7f1feb8634c06a3b
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ *.gem
2
+ .bundle
3
+ .ruby-gemset
4
+ Gemfile.lock
5
+ lib/sandbox/sandbox.jar
6
+ pkg/*
7
+ tags
8
+ tmp
9
+ .DS_Store
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ jruby-1.7.9
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - jruby-19mode
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # JRuby Sandbox Changelog
2
+
3
+ ## 0.2.3 (April 24, 2014)
4
+
5
+ * [SECURITY] Remove access to Object#java\_import.
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in jruby_sandbox.gemspec
4
+ gemspec
5
+
6
+ # this fork has some recent work done for 1.9, like File.foreach
7
+ gem 'fakefs', :git => 'git://github.com/codeschool/fakefs.git', :require => 'fakefs/safe', :ref => "6ae3212e3dab013b4b5e290d1aceba6466b30dec"
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2006 Ola Bini <ola@ologix.com>
2
+ Copyright (c) 2011 Dray Lacy and Eric Allam
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ JRuby Sandbox
2
+ =============
3
+
4
+ [![Build Status](https://travis-ci.org/omghax/jruby-sandbox.png?branch=master)](https://travis-ci.org/omghax/jruby-sandbox)
5
+
6
+ The JRuby sandbox is a reimplementation of \_why's freaky freaky sandbox
7
+ in JRuby, and is heavily based on [javasand][1] by Ola Bini, but updated
8
+ for JRuby 1.7.
9
+
10
+ ## Prerequisites
11
+
12
+ This gem was developed against JRuby 1.7.6, and is known to work with 1.7.8,
13
+ but has not been tested against other versions, so proceed at your own risk.
14
+ The Travis CI configuration specifies the `jruby-19mode` target, which floats
15
+ between exact versions of JRuby. At the time of writing, this is currently
16
+ JRuby 1.7.8. You can see a list of Travis CI's provided rubies [here][2]. As
17
+ long as the build is green you should be good to go.
18
+
19
+ Installing JRuby is simple with RVM:
20
+
21
+ rvm install jruby-1.7.6
22
+
23
+ ## Building
24
+
25
+ To build the JRuby extension, run `rake compile`. This will build the
26
+ `lib/sandbox/sandbox.jar` file, which `lib/sandbox.rb` loads.
27
+
28
+ ## Basic Usage
29
+
30
+ Sandbox gives you a self-contained JRuby interpreter in which to eval
31
+ code without polluting the host environment.
32
+
33
+ >> require "sandbox"
34
+ => true
35
+ >> sand = Sandbox::Full.new
36
+ => #<Sandbox::Full:0x46377e2a>
37
+ >> sand.eval("x = 1 + 2") # we've defined x in the sandbox
38
+ => 3
39
+ >> sand.eval("x")
40
+ => 3
41
+ >> x # but it hasn't leaked out into the host interpreter
42
+ NameError: undefined local variable or method `x' for #<Object:0x11cdc190>
43
+
44
+ There's also `Sandbox::Full#require`, which lets you invoke `Kernel#require`
45
+ directly for the sandbox, so you can load any trusted core libraries. Note that
46
+ this is a direct binding to `Kernel#require`, so it will only load ruby stdlib
47
+ libraries (i.e. no rubygems support yet).
48
+
49
+ ## Sandbox::Safe usage
50
+
51
+ Sandbox::Safe exposes an `#activate!` method which will lock down the sandbox,
52
+ removing unsafe methods. Before calling `#activate!`, Sandbox::Safe is the same
53
+ as Sandbox::Full.
54
+
55
+ >> require 'sandbox'
56
+ => true
57
+ >> sand = Sandbox.safe
58
+ => #<Sandbox::Safe:0x17072b90>
59
+ >> sand.eval %{`echo HELLO`}
60
+ => "HELLO\n"
61
+ >> sand.activate!
62
+ >> sand.eval %{`echo HELLO`}
63
+ Sandbox::SandboxException: NoMethodError: undefined method ``' for main:Object
64
+
65
+ Sandbox::Safe works by whitelisting methods to keep, and removing the rest.
66
+ Checkout sandbox.rb for which methods are kept.
67
+
68
+ Sandbox::Safe.activate! will also isolate the sandbox environment from the
69
+ filesystem using FakeFS.
70
+
71
+ >> require 'sandbox'
72
+ => true
73
+ >> s = Sandbox.safe
74
+ => #<Sandbox::Safe:0x3fdb8a73>
75
+ >> s.eval('Dir["/"]')
76
+ => ["/"]
77
+ >> s.eval('Dir["/*"]')
78
+ => ["/Applications", "/bin", "/cores", "/dev", etc.]
79
+ > s.activate!
80
+ >> s.eval('Dir["/*"]')
81
+ => []
82
+ > Dir['/*']
83
+ => ["/Applications", "/bin", "/cores", "/dev", etc.]
84
+
85
+ ## Known Issues / TODOs
86
+
87
+ * There is currently no timeout support, so it's possible for a
88
+ sandbox to loop indefinitely and block the host interpreter.
89
+
90
+ [1]: http://ola-bini.blogspot.com/2006/12/freaky-freaky-sandbox-has-come-to-jruby.html
91
+ [2]: http://about.travis-ci.org/docs/user/ci-environment/#Ruby-(aka-common)-VM-images
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/javaextensiontask'
5
+
6
+ Rake::JavaExtensionTask.new('sandbox') do |ext|
7
+ jruby_home = RbConfig::CONFIG['prefix']
8
+ ext.ext_dir = 'ext/java'
9
+ ext.lib_dir = 'lib/sandbox'
10
+ jars = ["#{jruby_home}/lib/jruby.jar"] + FileList['lib/*.jar']
11
+ ext.classpath = jars.map { |x| File.expand_path(x) }.join(':')
12
+ end
13
+
14
+ require 'rspec/core/rake_task'
15
+
16
+ RSpec::Core::RakeTask.new(:spec) do |t|
17
+ t.pattern = 'spec/**/*_spec.rb'
18
+ t.rspec_opts = ['--backtrace']
19
+ end
20
+
21
+ # Make sure the jar is up to date before running specs
22
+ task :spec => :compile
23
+
24
+ task :default => :spec
@@ -0,0 +1,35 @@
1
+ package sandbox;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyClass;
5
+ import org.jruby.anno.JRubyClass;
6
+ import org.jruby.anno.JRubyMethod;
7
+ import org.jruby.runtime.builtin.IRubyObject;
8
+ import org.jruby.runtime.Block;
9
+
10
+ @JRubyClass(name="BoxedClass")
11
+ public class BoxedClass {
12
+ protected static RubyClass createBoxedClassClass(final Ruby runtime) {
13
+ RubyClass cObject = runtime.getObject();
14
+ RubyClass cBoxedClass = runtime.defineClass("BoxedClass", cObject, cObject.getAllocator());
15
+ cBoxedClass.defineAnnotatedMethods(BoxedClass.class);
16
+
17
+ return cBoxedClass;
18
+ }
19
+
20
+ @JRubyMethod(module=true, rest=true)
21
+ public static IRubyObject method_missing(IRubyObject recv, IRubyObject[] args, Block block) {
22
+ IRubyObject[] args2 = new IRubyObject[args.length - 1];
23
+ System.arraycopy(args, 1, args2, 0, args2.length);
24
+ String name = args[0].toString();
25
+
26
+ SandboxFull box = (SandboxFull) SandboxFull.getLinkedBox(recv);
27
+ return box.runMethod(recv, name, args2, block);
28
+ }
29
+
30
+ @JRubyMethod(name="new", meta=true, rest=true)
31
+ public static IRubyObject _new(IRubyObject recv, IRubyObject[] args, Block block) {
32
+ SandboxFull box = (SandboxFull) SandboxFull.getLinkedBox(recv);
33
+ return box.runMethod(recv, "new", args, block);
34
+ }
35
+ }
@@ -0,0 +1,317 @@
1
+ package sandbox;
2
+
3
+ import java.util.Collection;
4
+ import java.util.Map;
5
+
6
+ import org.jruby.Ruby;
7
+ import org.jruby.RubyClass;
8
+ import org.jruby.RubyInstanceConfig;
9
+ import org.jruby.RubyKernel;
10
+ import org.jruby.RubyModule;
11
+ import org.jruby.RubyObject;
12
+ import org.jruby.CompatVersion;
13
+ import org.jruby.anno.JRubyClass;
14
+ import org.jruby.anno.JRubyMethod;
15
+ import org.jruby.internal.runtime.methods.DynamicMethod;
16
+ import org.jruby.runtime.Block;
17
+ import org.jruby.runtime.ObjectAllocator;
18
+ import org.jruby.runtime.builtin.IRubyObject;
19
+ import org.jruby.common.IRubyWarnings;
20
+ import org.jruby.exceptions.RaiseException;
21
+ import org.jruby.runtime.DynamicScope;
22
+
23
+
24
+ @JRubyClass(name="Sandbox::Full")
25
+ public class SandboxFull extends RubyObject {
26
+ protected static ObjectAllocator FULL_ALLOCATOR = new ObjectAllocator() {
27
+ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
28
+ return new SandboxFull(runtime, klass);
29
+ }
30
+ };
31
+
32
+ private Ruby wrapped;
33
+ private DynamicScope currentScope;
34
+
35
+ protected SandboxFull(Ruby runtime, RubyClass type) {
36
+ super(runtime, type);
37
+ reload();
38
+ }
39
+
40
+ @JRubyMethod
41
+ public IRubyObject reload() {
42
+ RubyInstanceConfig cfg = new RubyInstanceConfig();
43
+ cfg.setObjectSpaceEnabled(getRuntime().getInstanceConfig().isObjectSpaceEnabled());
44
+ cfg.setInput(getRuntime().getInstanceConfig().getInput());
45
+ cfg.setOutput(getRuntime().getInstanceConfig().getOutput());
46
+ cfg.setError(getRuntime().getInstanceConfig().getError());
47
+ cfg.setCompatVersion(CompatVersion.RUBY1_9);
48
+ cfg.setScriptFileName("(sandbox)");
49
+
50
+ SandboxProfile profile = new SandboxProfile(this);
51
+ cfg.setProfile(profile);
52
+
53
+ wrapped = Ruby.newInstance(cfg);
54
+ currentScope = wrapped.getCurrentContext().getCurrentScope();
55
+
56
+ BoxedClass.createBoxedClassClass(wrapped);
57
+
58
+ return this;
59
+ }
60
+
61
+ @JRubyMethod(required=1)
62
+ public IRubyObject eval(IRubyObject str) {
63
+ try {
64
+ IRubyObject result = wrapped.evalScriptlet(str.asJavaString(), currentScope);
65
+ return unbox(result);
66
+ } catch (RaiseException e) {
67
+ String msg = e.getException().callMethod(wrapped.getCurrentContext(), "message").asJavaString();
68
+ String path = e.getException().type().getName();
69
+ RubyClass eSandboxException = (RubyClass) getRuntime().getClassFromPath("Sandbox::SandboxException");
70
+ throw new RaiseException(getRuntime(), eSandboxException, path + ": " + msg, false);
71
+ } catch (Exception e) {
72
+ e.printStackTrace();
73
+ getRuntime().getWarnings().warn(IRubyWarnings.ID.MISCELLANEOUS, "NativeException: " + e);
74
+ return getRuntime().getNil();
75
+ }
76
+ }
77
+
78
+ @JRubyMethod(name="import", required=1)
79
+ public IRubyObject _import(IRubyObject klass) {
80
+ if (!(klass instanceof RubyModule)) {
81
+ throw getRuntime().newTypeError(klass, getRuntime().getClass("Module"));
82
+ }
83
+ String name = ((RubyModule) klass).getName();
84
+ importClassPath(name, false);
85
+ return getRuntime().getNil();
86
+ }
87
+
88
+ @JRubyMethod(required=1)
89
+ public IRubyObject ref(IRubyObject klass) {
90
+ if (!(klass instanceof RubyModule)) {
91
+ throw getRuntime().newTypeError(klass, getRuntime().getClass("Module"));
92
+ }
93
+ String name = ((RubyModule) klass).getName();
94
+ importClassPath(name, true);
95
+ return getRuntime().getNil();
96
+ }
97
+
98
+ private RubyModule importClassPath(String path, final boolean link) {
99
+ RubyModule runtimeModule = getRuntime().getObject();
100
+ RubyModule wrappedModule = wrapped.getObject();
101
+
102
+ if (path.startsWith("#")) {
103
+ throw getRuntime().newArgumentError("can't import anonymous class " + path);
104
+ }
105
+
106
+ for (String name : path.split("::")) {
107
+ runtimeModule = (RubyModule) runtimeModule.getConstantAt(name);
108
+ // Create the module when it did not exist yet...
109
+ if (wrappedModule.const_defined_p(wrapped.getCurrentContext(), wrapped.newString(name)).isFalse()) {
110
+ // The BoxedClass takes the place of Object as top of the inheritance
111
+ // hierarchy. As a result, we can intercept all new instances that are
112
+ // created and all method_missing calls.
113
+ RubyModule sup = wrapped.getClass("BoxedClass");
114
+ if (!link && runtimeModule instanceof RubyClass) {
115
+ // If we're importing a class, recursively import all of its
116
+ // superclasses as well.
117
+ sup = importClassPath(runtimeModule.getSuperClass().getName(), true);
118
+ }
119
+
120
+ RubyClass klass = (RubyClass) sup;
121
+ if (wrappedModule == wrapped.getObject()) {
122
+
123
+ if (link || runtimeModule instanceof RubyClass) { // if this is a ref and not an import
124
+ wrappedModule = wrapped.defineClass(name, klass, klass.getAllocator());
125
+ } else {
126
+ wrappedModule = wrapped.defineModule(name);
127
+ }
128
+
129
+ } else {
130
+ if (runtimeModule instanceof RubyClass) {
131
+ wrappedModule = wrappedModule.defineClassUnder(name, klass, klass.getAllocator());
132
+ } else {
133
+ wrappedModule = wrappedModule.defineModuleUnder(name);
134
+ }
135
+
136
+ }
137
+ } else {
138
+ // ...or just resolve it, if it was already known
139
+ wrappedModule = (RubyModule) wrappedModule.getConstantAt(name);
140
+ }
141
+
142
+ // Check the consistency of the hierarchy
143
+ if (runtimeModule instanceof RubyClass) {
144
+ if (!link && !runtimeModule.getSuperClass().getName().equals(wrappedModule.getSuperClass().getName())) {
145
+ throw getRuntime().newTypeError("superclass mismatch for class " + runtimeModule.getSuperClass().getName());
146
+ }
147
+ }
148
+
149
+ if (link || runtimeModule instanceof RubyClass) {
150
+ linkObject(runtimeModule, wrappedModule);
151
+ } else {
152
+ copyMethods(runtimeModule, wrappedModule);
153
+ }
154
+ }
155
+
156
+ return runtimeModule;
157
+ }
158
+
159
+ private void copyMethods(RubyModule from, RubyModule to) {
160
+ to.getMethodsForWrite().putAll(from.getMethods());
161
+ to.getSingletonClass().getMethodsForWrite().putAll(from.getSingletonClass().getMethods());
162
+ }
163
+
164
+ @JRubyMethod(required=2)
165
+ public IRubyObject keep_methods(IRubyObject className, IRubyObject methods) {
166
+ RubyModule module = wrapped.getModule(className.asJavaString());
167
+ if (module != null) {
168
+ keepMethods(module, methods.convertToArray());
169
+ }
170
+ return methods;
171
+ }
172
+
173
+ @JRubyMethod(required=2)
174
+ public IRubyObject keep_singleton_methods(IRubyObject className, IRubyObject methods) {
175
+ RubyModule module = wrapped.getModule(className.asJavaString()).getSingletonClass();
176
+ if (module != null) {
177
+ keepMethods(module, methods.convertToArray());
178
+ }
179
+ return methods;
180
+ }
181
+
182
+ private void keepMethods(RubyModule module, Collection retain) {
183
+ for (Map.Entry<String, DynamicMethod> methodEntry : module.getMethods().entrySet()) {
184
+ String methodName = methodEntry.getKey();
185
+ if (!retain.contains(methodName)) {
186
+ removeMethod(module, methodName);
187
+ }
188
+ }
189
+ }
190
+
191
+ @JRubyMethod(required=2)
192
+ public IRubyObject remove_method(IRubyObject className, IRubyObject methodName) {
193
+ RubyModule module = wrapped.getModule(className.asJavaString());
194
+ if (module != null) {
195
+ removeMethod(module, methodName.asJavaString());
196
+ }
197
+ return getRuntime().getNil();
198
+ }
199
+
200
+ @JRubyMethod(required=2)
201
+ public IRubyObject remove_singleton_method(IRubyObject className, IRubyObject methodName) {
202
+ RubyModule module = wrapped.getModule(className.asJavaString()).getSingletonClass();
203
+ if (module != null) {
204
+ removeMethod(module, methodName.asJavaString());
205
+ }
206
+ return getRuntime().getNil();
207
+ }
208
+
209
+ private void removeMethod(RubyModule module, String methodName) {
210
+ // System.err.println("removing method " + methodName + " from " + module.inspect().asJavaString());
211
+ module.removeMethod(wrapped.getCurrentContext(), methodName);
212
+ }
213
+
214
+ @JRubyMethod(required=1)
215
+ public IRubyObject load(IRubyObject str) {
216
+ try {
217
+ wrapped.getLoadService().load(str.asJavaString(), true);
218
+ return getRuntime().getTrue();
219
+ } catch (RaiseException e) {
220
+ e.printStackTrace();
221
+ return getRuntime().getFalse();
222
+ }
223
+ }
224
+
225
+ @JRubyMethod(required=1)
226
+ public IRubyObject require(IRubyObject str) {
227
+ try {
228
+ IRubyObject result = RubyKernel.require(wrapped.getKernel(), wrapped.newString(str.asJavaString()), Block.NULL_BLOCK);
229
+ return unbox(result);
230
+ } catch (RaiseException e) {
231
+ e.printStackTrace();
232
+ return getRuntime().getFalse();
233
+ }
234
+ }
235
+
236
+ private IRubyObject unbox(IRubyObject obj) {
237
+ return box(obj);
238
+ }
239
+
240
+ private IRubyObject rebox(IRubyObject obj) {
241
+ return box(obj);
242
+ }
243
+
244
+ private IRubyObject box(IRubyObject obj) {
245
+ if (obj.isImmediate()) {
246
+ return cross(obj);
247
+ } else {
248
+ // If this object already existed and was returned from the wrapped
249
+ // runtime on an earlier occasion, it will already contain a link to its
250
+ // brother in the regular runtime and we can safely return that link.
251
+ IRubyObject link = getLinkedObject(obj);
252
+ if (!link.isNil()) {
253
+ IRubyObject box = getLinkedBox(obj);
254
+ if (box == this) return link;
255
+ }
256
+
257
+ // Is the class already known on both sides of the fence?
258
+ IRubyObject klass = constFind(obj.getMetaClass().getRealClass().getName());
259
+ link = getRuntime().getNil();
260
+ if (!klass.isNil()) {
261
+ link = getLinkedObject(klass);
262
+ }
263
+
264
+ if (link.isNil()) {
265
+ return cross(obj);
266
+ } else {
267
+ IRubyObject v = ((RubyClass)klass).allocate();
268
+ linkObject(obj, v);
269
+ return v;
270
+ }
271
+ }
272
+ }
273
+
274
+ private IRubyObject cross(IRubyObject obj) {
275
+ IRubyObject dumped = wrapped.getModule("Marshal").callMethod(wrapped.getCurrentContext(), "dump", obj);
276
+ return getRuntime().getModule("Marshal").callMethod(getRuntime().getCurrentContext(), "load", dumped);
277
+ }
278
+
279
+ protected static IRubyObject getLinkedObject(IRubyObject arg) {
280
+ IRubyObject object = arg.getRuntime().getNil();
281
+ if (arg.getInstanceVariables().hasInstanceVariable("__link__")) {
282
+ object = (IRubyObject) arg.getInstanceVariables().getInstanceVariable("__link__");
283
+ }
284
+ return object;
285
+ }
286
+
287
+ protected static IRubyObject getLinkedBox(IRubyObject arg) {
288
+ IRubyObject object = arg.getRuntime().getNil();
289
+ if (arg.getInstanceVariables().hasInstanceVariable("__box__")) {
290
+ object = (IRubyObject) arg.getInstanceVariables().getInstanceVariable("__box__");
291
+ }
292
+ return object;
293
+ }
294
+
295
+ private void linkObject(IRubyObject runtimeObject, IRubyObject wrappedObject) {
296
+ wrappedObject.getInstanceVariables().setInstanceVariable("__link__", runtimeObject);
297
+ wrappedObject.getInstanceVariables().setInstanceVariable("__box__", this);
298
+ }
299
+
300
+ private IRubyObject constFind(String path) {
301
+ try {
302
+ return wrapped.getClassFromPath(path);
303
+ } catch (Exception e) {
304
+ return wrapped.getNil();
305
+ }
306
+ }
307
+
308
+ protected IRubyObject runMethod(IRubyObject recv, String name, IRubyObject[] args, Block block) {
309
+ IRubyObject[] args2 = new IRubyObject[args.length];
310
+ for (int i = 0; i < args.length; i++) {
311
+ args2[i] = unbox(args[i]);
312
+ }
313
+ IRubyObject recv2 = unbox(recv);
314
+ IRubyObject result = recv2.callMethod(getRuntime().getCurrentContext(), name, args2, block);
315
+ return rebox(result);
316
+ }
317
+ }
@@ -0,0 +1,39 @@
1
+ package sandbox;
2
+
3
+ import org.jruby.Profile;
4
+ import org.jruby.Ruby;
5
+ import org.jruby.RubyClass;
6
+ import org.jruby.RubyModule;
7
+ import org.jruby.anno.JRubyClass;
8
+ import org.jruby.anno.JRubyMethod;
9
+ import org.jruby.runtime.builtin.IRubyObject;
10
+
11
+ public class SandboxModule {
12
+ /**
13
+ * Create the Sandbox module and add it to the Ruby runtime.
14
+ */
15
+ public static RubyModule createSandboxModule(final Ruby runtime) {
16
+ RubyModule mSandbox = runtime.defineModule("Sandbox");
17
+ mSandbox.defineAnnotatedMethods(SandboxModule.class);
18
+
19
+ RubyClass cObject = runtime.getObject();
20
+ RubyClass cSandboxFull = mSandbox.defineClassUnder("Full", cObject, SandboxFull.FULL_ALLOCATOR);
21
+ cSandboxFull.defineAnnotatedMethods(SandboxFull.class);
22
+ RubyClass cStandardError = runtime.getStandardError();
23
+ RubyClass cSandboxException = mSandbox.defineClassUnder("SandboxException", cStandardError, cStandardError.getAllocator());
24
+
25
+ return mSandbox;
26
+ }
27
+
28
+ @JRubyClass(name="Sandbox::SandboxException", parent="StandardError")
29
+ public static class SandboxException {}
30
+
31
+ @JRubyMethod(name="current", meta=true)
32
+ public static IRubyObject s_current(IRubyObject recv) {
33
+ Profile prof = recv.getRuntime().getProfile();
34
+ if (prof instanceof SandboxProfile) {
35
+ return ((SandboxProfile) prof).getSandbox();
36
+ }
37
+ return recv.getRuntime().getNil();
38
+ }
39
+ }
@@ -0,0 +1,22 @@
1
+ package sandbox;
2
+
3
+ import org.jruby.Profile;
4
+ import org.jruby.runtime.builtin.IRubyObject;
5
+
6
+ public class SandboxProfile implements Profile {
7
+ private IRubyObject sandbox;
8
+
9
+ public SandboxProfile(IRubyObject sandbox) {
10
+ this.sandbox = sandbox;
11
+ }
12
+
13
+ public IRubyObject getSandbox() {
14
+ return sandbox;
15
+ }
16
+
17
+ public boolean allowBuiltin(String name) { return true; }
18
+ public boolean allowClass(String name) { return true; }
19
+ public boolean allowModule(String name) { return true; }
20
+ public boolean allowLoad(String name) { return true; }
21
+ public boolean allowRequire(String name) { return true; }
22
+ }
@@ -0,0 +1,17 @@
1
+ package sandbox;
2
+
3
+ import java.io.IOException;
4
+
5
+ import org.jruby.Ruby;
6
+ import org.jruby.runtime.load.BasicLibraryService;
7
+
8
+ public class SandboxService implements BasicLibraryService {
9
+ public boolean basicLoad(Ruby runtime) throws IOException {
10
+ init(runtime);
11
+ return true;
12
+ }
13
+
14
+ private void init(Ruby runtime) {
15
+ SandboxModule.createSandboxModule(runtime);
16
+ }
17
+ }
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "sandbox/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "xplenty-jruby_sandbox"
7
+ s.version = Sandbox::VERSION
8
+ s.platform = "java"
9
+ s.authors = ["Dray Lacy", "Eric Allam", "Moty Michaely"]
10
+ s.email = ["dray@envylabs.com", "eric@envylabs.com", "moty.mi@gmail.com"]
11
+ s.homepage = "http://github.com/xplenty/jruby-sandbox"
12
+ s.summary = "Sandbox support for JRuby"
13
+ s.description = "A version of _why's Freaky Freaky Sandbox for JRuby."
14
+
15
+ s.rubyforge_project = "jruby_sandbox"
16
+
17
+ s.files = `git ls-files`.split("\n") + ["lib/sandbox/sandbox.jar"]
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "fakefs"
23
+
24
+ s.add_development_dependency "rake"
25
+ s.add_development_dependency "rake-compiler"
26
+ s.add_development_dependency "rspec"
27
+ s.add_development_dependency "yard"
28
+ end
@@ -0,0 +1,19 @@
1
+ # Alternate "safer" versions of Ruby methods. Mostly non-blocking.
2
+ [Fixnum, Bignum, Float].each do |klass|
3
+ klass.class_eval do
4
+ # A very weak version of pow, it doesn't work on Floats, but it's gonna
5
+ # fill the most common uses for now.
6
+ def **(x)
7
+ case x
8
+ when 0; 1
9
+ when 1; self
10
+ else
11
+ y = 1
12
+ while 0 <= (x -= 1) do
13
+ y *= self
14
+ end
15
+ y
16
+ end
17
+ end
18
+ end
19
+ end