diff --git a/README.md b/README.md index 597b0d0..8975e6c 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ This code will raise a ScriptCPUAbuseException. org.javadelight delight-nashorn-sandbox - 0.0.5 + 0.0.6 Find out latest version [here](http://modules.appjangle.com/delight-nashorn-sandbox/latest/project-summary.html). diff --git a/pom.xml b/pom.xml index 6aba05d..45fdbc5 100644 --- a/pom.xml +++ b/pom.xml @@ -70,10 +70,10 @@ - + --> diff --git a/src/main/java/delight/nashornsandbox/internal/NashornSandboxImpl.java b/src/main/java/delight/nashornsandbox/internal/NashornSandboxImpl.java index 652e3ac..23c65a6 100644 --- a/src/main/java/delight/nashornsandbox/internal/NashornSandboxImpl.java +++ b/src/main/java/delight/nashornsandbox/internal/NashornSandboxImpl.java @@ -13,6 +13,8 @@ import java.util.Random; import java.util.Set; import java.util.concurrent.ExecutorService; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.script.ScriptEngine; import javax.script.ScriptException; import jdk.nashorn.api.scripting.NashornScriptEngineFactory; @@ -61,70 +63,76 @@ public void assertScriptEngine() { } String _xifexpression = null; if ((!this.allowPrintFunctions)) { - _xifexpression = (("" + - "quit = function() {};\n") + - "exit = function() {};\n"); + _xifexpression = (("" + "quit = function() {};\n") + "exit = function() {};\n"); } else { _xifexpression = ""; } String _plus = ("\n" + _xifexpression); - String _plus_1 = (_plus + - "\n"); + String _plus_1 = (_plus + "\n"); String _xifexpression_1 = null; if ((!this.allowPrintFunctions)) { - _xifexpression_1 = (("" + - "print = function() {};\n") + - "echo = function() {};\n"); + _xifexpression_1 = (("" + "print = function() {};\n") + "echo = function() {};\n"); } else { _xifexpression_1 = ""; } String _plus_2 = (_plus_1 + _xifexpression_1); - String _plus_3 = (_plus_2 + - "\n"); + String _plus_3 = (_plus_2 + "\n"); String _xifexpression_2 = null; if ((!this.allowReadFunctions)) { - _xifexpression_2 = (("" + - "readFully = function() {};\n") + - "readLine = function() {};\n"); + _xifexpression_2 = (("" + "readFully = function() {};\n") + "readLine = function() {};\n"); } else { _xifexpression_2 = ""; } String _plus_4 = (_plus_3 + _xifexpression_2); - String _plus_5 = (_plus_4 + - "\n"); + String _plus_5 = (_plus_4 + "\n"); String _xifexpression_3 = null; if ((!this.allowLoadFunctions)) { - _xifexpression_3 = (("" + - "load = function() {};\n") + - "loadWithNewGlobal = function() {};\n"); + _xifexpression_3 = (("" + "load = function() {};\n") + "loadWithNewGlobal = function() {};\n"); } else { _xifexpression_3 = ""; } String _plus_6 = (_plus_5 + _xifexpression_3); - String _plus_7 = (_plus_6 + - "\n"); + String _plus_7 = (_plus_6 + "\n"); String _xifexpression_4 = null; if ((!this.allowGlobalsObjects)) { - _xifexpression_4 = ((((((("" + - "$ARG = null;\n") + - "$ENV = null;\n") + - "$EXEC = null;\n") + - "$OPTIONS = null;\n") + - "$OUT = null;\n") + - "$ERR = null;\n") + - "$EXIT = null;\n"); + _xifexpression_4 = ((((((("" + "$ARG = null;\n") + "$ENV = null;\n") + "$EXEC = null;\n") + "$OPTIONS = null;\n") + + "$OUT = null;\n") + "$ERR = null;\n") + "$EXIT = null;\n"); } else { _xifexpression_4 = ""; } String _plus_8 = (_plus_7 + _xifexpression_4); - String _plus_9 = (_plus_8 + - "\n"); + String _plus_9 = (_plus_8 + "\n"); this.scriptEngine.eval(_plus_9); } catch (Throwable _e) { throw Exceptions.sneakyThrow(_e); } } + private static String replaceGroup(final String str, final String regex, final String replacementForGroup2) { + final Pattern pattern = Pattern.compile(regex); + final Matcher matcher = pattern.matcher(str); + final StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + matcher.appendReplacement(sb, ("$1" + replacementForGroup2)); + } + matcher.appendTail(sb); + return sb.toString(); + } + + private static String injectInterruptionCalls(final String str, final int randomToken) { + String _xblockexpression = null; + { + String res = str.replaceAll(";\\n", ((";intCheckForInterruption" + Integer.valueOf(randomToken)) + "();\n")); + String _replaceGroup = NashornSandboxImpl.replaceGroup(res, "(while \\([^\\)]*)(\\) \\{)", ((") {intCheckForInterruption" + Integer.valueOf(randomToken)) + "();\n")); + res = _replaceGroup; + String _replaceGroup_1 = NashornSandboxImpl.replaceGroup(res, "(for \\([^\\)]*)(\\) \\{)", ((") {intCheckForInterruption" + Integer.valueOf(randomToken)) + "();\n")); + res = _replaceGroup_1; + String _replaceAll = res.replaceAll("\\} while \\(", (("\nintCheckForInterruption" + Integer.valueOf(randomToken)) + "();\n\\} while \\(")); + _xblockexpression = res = _replaceAll; + } + return _xblockexpression; + } + @Override public Object eval(final String js) { try { @@ -188,9 +196,8 @@ public void run() { _builder.newLine(); _builder.append("};"); _builder.newLine(); - String _replaceAll = beautifiedJs.replaceAll(";\\n", ((";intCheckForInterruption" + Integer.valueOf(randomToken)) + "();\n")); - String _replace = _replaceAll.replace(") {", ((") {intCheckForInterruption" + Integer.valueOf(randomToken)) + "();\n")); - final String securedJs = (_builder.toString() + _replace); + String _injectInterruptionCalls = NashornSandboxImpl.injectInterruptionCalls(beautifiedJs, randomToken); + final String securedJs = (_builder.toString() + _injectInterruptionCalls); final Thread mainThread = Thread.currentThread(); Thread _currentThread = Thread.currentThread(); monitorThread.setThreadToMonitor(_currentThread); diff --git a/src/main/xtend/delight/nashornsandbox/internal/NashornSandboxImpl.xtend b/src/main/xtend/delight/nashornsandbox/internal/NashornSandboxImpl.xtend index 7544802..57273ac 100644 --- a/src/main/xtend/delight/nashornsandbox/internal/NashornSandboxImpl.xtend +++ b/src/main/xtend/delight/nashornsandbox/internal/NashornSandboxImpl.xtend @@ -4,11 +4,11 @@ import delight.async.Value import delight.nashornsandbox.NashornSandbox import delight.nashornsandbox.exceptions.ScriptCPUAbuseException import java.util.HashMap -import java.util.HashSet import java.util.Map import java.util.Random -import java.util.Set import java.util.concurrent.ExecutorService +import java.util.regex.Matcher +import java.util.regex.Pattern import javax.script.ScriptEngine import javax.script.ScriptException import jdk.nashorn.api.scripting.NashornScriptEngineFactory @@ -46,39 +46,45 @@ class NashornSandboxImpl implements NashornSandbox { for (entry : globalVariables.entrySet) { scriptEngine.put(entry.key, entry.value) } - - scriptEngine.eval("\n" + - (if (!this.allowPrintFunctions) "" + - "quit = function() {};\n" + - "exit = function() {};\n" - else "") + - "\n" + - (if (!this.allowPrintFunctions) "" + - "print = function() {};\n" + - "echo = function() {};\n" - else "") + - "\n" + - (if (!this.allowReadFunctions) "" + - "readFully = function() {};\n" + - "readLine = function() {};\n" - else "") + - "\n" + - (if (!this.allowLoadFunctions) "" + - "load = function() {};\n" + - "loadWithNewGlobal = function() {};\n" - else "") + - "\n" + - (if (!this.allowGlobalsObjects) "" + - "$ARG = null;\n" + - "$ENV = null;\n" + - "$EXEC = null;\n" + - "$OPTIONS = null;\n" + - "$OUT = null;\n" + - "$ERR = null;\n" + - "$EXIT = null;\n" - else "") + - "\n") - + + scriptEngine.eval( + "\n" + (if (!this.allowPrintFunctions) + "" + "quit = function() {};\n" + "exit = function() {};\n" + else + "") + "\n" + (if (!this.allowPrintFunctions) + "" + "print = function() {};\n" + "echo = function() {};\n" + else + "") + "\n" + (if (!this.allowReadFunctions) + "" + "readFully = function() {};\n" + "readLine = function() {};\n" + else + "") + "\n" + (if (!this.allowLoadFunctions) + "" + "load = function() {};\n" + "loadWithNewGlobal = function() {};\n" + else + "") + "\n" + + (if (!this.allowGlobalsObjects) + "" + "$ARG = null;\n" + "$ENV = null;\n" + "$EXEC = null;\n" + "$OPTIONS = null;\n" + + "$OUT = null;\n" + "$ERR = null;\n" + "$EXIT = null;\n" + else + "") + "\n") + + } + + private def static String replaceGroup(String str, String regex, String replacementForGroup2) { + val Pattern pattern = Pattern.compile(regex); + val Matcher matcher = pattern.matcher(str); + val StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + matcher.appendReplacement(sb, "$1" + replacementForGroup2); + } + matcher.appendTail(sb); + return sb.toString() + } + + private def static String injectInterruptionCalls(String str, int randomToken) { + var res = str.replaceAll(';\\n', ';intCheckForInterruption' + randomToken + '();\n') + res = replaceGroup(res, "(while \\([^\\)]*)(\\) \\{)", ') {intCheckForInterruption' + randomToken + '();\n') + res = replaceGroup(res, "(for \\([^\\)]*)(\\) \\{)", ') {intCheckForInterruption' + randomToken + '();\n') + res = res.replaceAll("\\} while \\(", "\nintCheckForInterruption" + randomToken + "();\n\\} while \\(") } override Object eval(String js) { @@ -123,10 +129,10 @@ class NashornSandboxImpl implements NashornSandbox { throw new Error('InterruptedĀ«randomTokenĀ»') } }; - ''' + - beautifiedJs.replaceAll(';\\n', ';intCheckForInterruption' + randomToken + '();\n'). - replace(') {', ') {intCheckForInterruption' + randomToken + '();\n') - + ''' + injectInterruptionCalls(beautifiedJs, randomToken) + + + val mainThread = Thread.currentThread monitorThread.threadToMonitor = Thread.currentThread @@ -241,7 +247,7 @@ class NashornSandboxImpl implements NashornSandbox { override ExecutorService getExecutor() { this.exectuor } - + override get(String variableName) { assertScriptEngine scriptEngine.get(variableName) @@ -266,13 +272,11 @@ class NashornSandboxImpl implements NashornSandbox { override allowGlobalsObjects(boolean v) { this.allowGlobalsObjects = v } - + new() { this.sandboxClassFilter = new SandboxClassFilter() this.globalVariables = new HashMap allow(InterruptTest) } - - } diff --git a/src/test/java/delight/nashornsandbox/tests/TestLimitCPU.java b/src/test/java/delight/nashornsandbox/tests/TestLimitCPU.java index 634b5c3..760d3c8 100644 --- a/src/test/java/delight/nashornsandbox/tests/TestLimitCPU.java +++ b/src/test/java/delight/nashornsandbox/tests/TestLimitCPU.java @@ -109,4 +109,25 @@ public void test_while_plus_iteration() { _executor.shutdown(); } } + + @Test(expected = ScriptCPUAbuseException.class) + public void test_do_while() { + final NashornSandbox sandbox = NashornSandboxes.create(); + try { + sandbox.setMaxCPUTime(50); + ExecutorService _newSingleThreadExecutor = Executors.newSingleThreadExecutor(); + sandbox.setExecutor(_newSingleThreadExecutor); + StringConcatenation _builder = new StringConcatenation(); + _builder.append("do {"); + _builder.newLine(); + _builder.append("\t"); + _builder.newLine(); + _builder.append("} while (true);"); + _builder.newLine(); + sandbox.eval(_builder.toString()); + } finally { + ExecutorService _executor = sandbox.getExecutor(); + _executor.shutdown(); + } + } } diff --git a/src/test/java/delight/nashornsandbox/tests/TestSwitch.java b/src/test/java/delight/nashornsandbox/tests/TestSwitch.java new file mode 100644 index 0000000..864a583 --- /dev/null +++ b/src/test/java/delight/nashornsandbox/tests/TestSwitch.java @@ -0,0 +1,59 @@ +package delight.nashornsandbox.tests; + +import delight.nashornsandbox.NashornSandbox; +import delight.nashornsandbox.NashornSandboxes; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import org.eclipse.xtend2.lib.StringConcatenation; +import org.junit.Test; + +@SuppressWarnings("all") +public class TestSwitch { + @Test + public void test() { + final NashornSandbox sandbox = NashornSandboxes.create(); + try { + sandbox.allowPrintFunctions(true); + sandbox.setMaxCPUTime(50); + ExecutorService _newSingleThreadExecutor = Executors.newSingleThreadExecutor(); + sandbox.setExecutor(_newSingleThreadExecutor); + StringConcatenation _builder = new StringConcatenation(); + _builder.append("var expr = \"one\";"); + _builder.newLine(); + _builder.newLine(); + _builder.append("switch (expr) {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("case \"one\":"); + _builder.newLine(); + _builder.append(" "); + _builder.append("// ok"); + _builder.newLine(); + _builder.append(" "); + _builder.append("break;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("case \"two\":"); + _builder.newLine(); + _builder.append(" "); + _builder.append("// ok"); + _builder.newLine(); + _builder.append(" "); + _builder.append("break;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("default:"); + _builder.newLine(); + _builder.append(" "); + _builder.append("print(\"Unknown expression\");"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + sandbox.eval(_builder.toString()); + } finally { + ExecutorService _executor = sandbox.getExecutor(); + _executor.shutdown(); + } + } +} diff --git a/src/test/xtend/delight/nashornsandbox/tests/TestLimitCPU.xtend b/src/test/xtend/delight/nashornsandbox/tests/TestLimitCPU.xtend index 4f0d064..feabae2 100644 --- a/src/test/xtend/delight/nashornsandbox/tests/TestLimitCPU.xtend +++ b/src/test/xtend/delight/nashornsandbox/tests/TestLimitCPU.xtend @@ -93,6 +93,24 @@ class TestLimitCPU { } } + @Test(expected=ScriptCPUAbuseException) + def void test_do_while() { + val sandbox = NashornSandboxes.create() + try { + + sandbox.maxCPUTime = 50 + sandbox.executor = Executors.newSingleThreadExecutor + + sandbox.eval(''' + do { + + } while (true); + ''') + } finally { + sandbox.executor.shutdown() + } + } + } \ No newline at end of file diff --git a/src/test/xtend/delight/nashornsandbox/tests/TestSwitch.xtend b/src/test/xtend/delight/nashornsandbox/tests/TestSwitch.xtend new file mode 100644 index 0000000..5d5a904 --- /dev/null +++ b/src/test/xtend/delight/nashornsandbox/tests/TestSwitch.xtend @@ -0,0 +1,37 @@ +package delight.nashornsandbox.tests + +import delight.nashornsandbox.NashornSandboxes +import java.util.concurrent.Executors +import org.junit.Test + +class TestSwitch { + + @Test + def void test() { + val sandbox = NashornSandboxes.create() + try { + sandbox.allowPrintFunctions(true) + sandbox.maxCPUTime = 50 + sandbox.executor = Executors.newSingleThreadExecutor + sandbox.eval(''' + var expr = "one"; + + switch (expr) { + case "one": + // ok + break; + case "two": + // ok + break; + default: + print("Unknown expression"); + } + + ''') + } finally { + sandbox.executor.shutdown() + } + + } + +}