Skip to content

Commit

Permalink
Issue 45: Added support for Trireme to consult an optional extra Clas…
Browse files Browse the repository at this point in the history
…sShutter.

This will allow Trireme embedders the ability to open up Rhino for passing/using
Java objects in their script environments.
  • Loading branch information
whitlockjc committed Mar 7, 2014
1 parent 266cb55 commit 35b6a51
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ private void initialize()
contextFactory.setJsVersion(DEFAULT_JS_VERSION);
contextFactory.setOptLevel(optLevel);
contextFactory.setCountOperations(scriptTimeLimit > 0L);
contextFactory.setExtraClassShutter(getSandbox() == null ? null : getSandbox().getExtraClassShutter());

contextFactory.call(new ContextAction()
{
Expand Down
19 changes: 19 additions & 0 deletions core/src/main/java/io/apigee/trireme/core/Sandbox.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/
package io.apigee.trireme.core;

import org.mozilla.javascript.ClassShutter;
import org.mozilla.javascript.Scriptable;

import java.io.InputStream;
Expand Down Expand Up @@ -51,6 +52,7 @@ public class Sandbox
private SubprocessPolicy processPolicy;
private List<Map.Entry<String, String>> mounts;
private boolean hideOsDetails;
private ClassShutter extraClassShutter;

/**
* Create a new sandbox that will not affect anything in any way.
Expand Down Expand Up @@ -78,6 +80,7 @@ public Sandbox(Sandbox parent)
this.networkPolicy = parent.networkPolicy;
this.processPolicy = parent.processPolicy;
this.hideOsDetails = parent.hideOsDetails;
this.extraClassShutter = parent.extraClassShutter;
if (parent.mounts != null) {
this.mounts = new ArrayList<Map.Entry<String, String>>(parent.mounts);
}
Expand Down Expand Up @@ -239,4 +242,20 @@ public Sandbox setHideOSDetails(boolean obscure) {
public boolean isHideOSDetails() {
return hideOsDetails;
}

/**
* Attach an <b>extra</b> {@link ClassShutter} that can allow Trireme embedders the ability to expose
* extra Java classes to JavaScript code.
*
* <b>WARNING:</b> This must be used with care as passing Java objects disallowed by the default
* Trireme ClassShutter can result in unknown consequences.
*/
public Sandbox setExtraClassShutter(ClassShutter extraClassShutter) {
this.extraClassShutter = extraClassShutter;
return this;
}

public ClassShutter getExtraClassShutter() {
return extraClassShutter;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.RhinoException;

import java.util.HashSet;

Expand All @@ -35,9 +34,11 @@ public class RhinoContextFactory
{
private static final int DEFAULT_INSTRUCTION_THRESHOLD = 100000;

private final ClassShutter defaultClassShutter = new OpaqueClassShutter();
private int jsVersion = NodeEnvironment.DEFAULT_JS_VERSION;
private int optLevel = NodeEnvironment.DEFAULT_OPT_LEVEL;
private boolean countOperations;
private ClassShutter extraClassShutter;

@Override
protected Context makeContext()
Expand All @@ -49,7 +50,7 @@ protected Context makeContext()
if (countOperations) {
c.setInstructionObserverThreshold(DEFAULT_INSTRUCTION_THRESHOLD);
}
c.setClassShutter(OpaqueClassShutter.INSTANCE);
c.setClassShutter(defaultClassShutter);
return c;
}

Expand Down Expand Up @@ -114,16 +115,22 @@ public void setCountOperations(boolean countOperations)
this.countOperations = countOperations;
}

public ClassShutter getExtraClassShutter() {
return this.extraClassShutter;
}

public void setExtraClassShutter(ClassShutter extraClassShutter) {
this.extraClassShutter = extraClassShutter;
}

/**
* Don't allow access to Java code at all from inside Node code. However, Rhino seems to depend on access
* to certain internal classes, at least for error handing, so we will allow the code to have access
* to them.
*/
private static final class OpaqueClassShutter
private final class OpaqueClassShutter
implements ClassShutter
{
static final OpaqueClassShutter INSTANCE = new OpaqueClassShutter();

private final HashSet<String> whitelist = new HashSet<String>();

private OpaqueClassShutter()
Expand Down Expand Up @@ -152,7 +159,7 @@ private OpaqueClassShutter()
@Override
public boolean visibleToScripts(String s)
{
return (whitelist.contains(s));
return (whitelist.contains(s)) || (extraClassShutter != null && extraClassShutter.visibleToScripts(s));
}
}
}
29 changes: 29 additions & 0 deletions core/src/test/java/io/apigee/trireme/core/test/SandboxingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
import io.apigee.trireme.core.ScriptFuture;
import io.apigee.trireme.core.ScriptStatus;
import org.junit.Test;
import org.mozilla.javascript.ClassShutter;

import static org.junit.Assert.*;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -168,4 +170,31 @@ public void testStdoutSharing()
env.close();
}
}

/**
* Verify the support for an extra {@link ClassShutter} works as expected.
*/
@Test
public void testExtraClassShutter()
throws NodeException, ExecutionException, InterruptedException, IOException
{
NodeEnvironment env = new NodeEnvironment();

env.setSandbox(new Sandbox().setExtraClassShutter(new ClassShutter() {
@Override
public boolean visibleToScripts(String fullClassName) {
return true;
}
}));

File scriptFile = new File("./target/test-classes/tests/extraclassshuttertest.js");
NodeScript script = env.createScript(scriptFile.getName(),
scriptFile,
new String[] {
scriptFile.getCanonicalPath()
});
ScriptStatus status = script.execute().get();
assertEquals(0, status.getExitCode());
script.close();
}
}
8 changes: 8 additions & 0 deletions core/src/test/resources/tests/extraclassshuttertest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
var assert = require('assert');
var actualFilePath = new java.io.File(__filename).getCanonicalPath();
var expectedFilePath = process.argv[2];

assert (actualFilePath.equals(expectedFilePath));

// We have to use "==" here because Rhino thinks actualFilePath is an object instead of a string
assert (actualFilePath == expectedFilePath);

0 comments on commit 35b6a51

Please sign in to comment.