* remove "sandbox" feature which isn't used and probably wouldn't work that well anyhow

This commit is contained in:
Reinhard Pointner 2014-04-14 12:51:01 +00:00
parent dc6cc5e9c1
commit 86cb93c040
5 changed files with 53 additions and 157 deletions

View File

@ -14,7 +14,6 @@ import java.net.URI;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.security.AccessController;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.MissingResourceException;
@ -27,7 +26,6 @@ import javax.script.SimpleBindings;
import net.sourceforge.filebot.Analytics;
import net.sourceforge.filebot.MediaTypes;
import net.sourceforge.filebot.StandardRenameAction;
import net.sourceforge.filebot.cli.ScriptShell.Script;
import net.sourceforge.filebot.cli.ScriptShell.ScriptProvider;
import net.sourceforge.filebot.web.CachedResource;
@ -88,7 +86,7 @@ public class ArgumentProcessor {
Bindings bindings = new SimpleBindings();
bindings.put("args", args.getFiles(false));
DefaultScriptProvider scriptProvider = new DefaultScriptProvider(args.trustScript);
DefaultScriptProvider scriptProvider = new DefaultScriptProvider();
URI script = scriptProvider.getScriptLocation(args.script);
if (!scriptProvider.isInlineScheme(script.getScheme())) {
@ -105,7 +103,7 @@ public class ArgumentProcessor {
}
}
ScriptShell shell = new ScriptShell(cli, args, AccessController.getContext(), scriptProvider);
ScriptShell shell = new ScriptShell(scriptProvider, args.bindings);
shell.runScript(script, bindings);
}
@ -124,14 +122,8 @@ public class ArgumentProcessor {
public static class DefaultScriptProvider implements ScriptProvider {
private final boolean trustRemoteScript;
private URI baseScheme;
public DefaultScriptProvider(boolean trustRemoteScript) {
this.trustRemoteScript = trustRemoteScript;
}
public void setBaseScheme(URI baseScheme) {
this.baseScheme = baseScheme;
}
@ -145,19 +137,14 @@ public class ArgumentProcessor {
}
public boolean isInlineScheme(String scheme) {
return "g".equals(scheme) || "system".equals(scheme);
return "g".equals(scheme);
}
@Override
public URI getScriptLocation(String input) throws Exception {
try {
return new URL(input).toURI();
} catch (Exception _) {
// system:in
if (input.equals("system:in")) {
return new URI("system", "in", null);
}
} catch (Exception e) {
// g:println 'hello world'
if (input.startsWith("g:")) {
return new URI("g", input.substring(2), null);
@ -185,31 +172,18 @@ public class ArgumentProcessor {
}
@Override
public Script fetchScript(URI uri) throws IOException {
public String fetchScript(URI uri) throws IOException {
if (uri.getScheme().equals("file")) {
return new Script(readAll(new InputStreamReader(new FileInputStream(new File(uri)), "UTF-8")), true);
}
if (uri.getScheme().equals("system")) {
return new Script(readAll(new InputStreamReader(System.in)), true);
return readAll(new InputStreamReader(new FileInputStream(new File(uri)), "UTF-8"));
}
if (uri.getScheme().equals("g")) {
return new Script(uri.getSchemeSpecificPart(), true);
return uri.getSchemeSpecificPart();
}
// remote script
String url;
boolean trusted;
String resolver = getResourceTemplate(uri.getScheme());
if (resolver != null) {
url = String.format(resolver, uri.getSchemeSpecificPart());
trusted = true;
} else {
url = uri.toString();
trusted = trustRemoteScript;
}
String url = (resolver != null) ? String.format(resolver, uri.getSchemeSpecificPart()) : uri.toString();
// fetch remote script only if modified
CachedResource<String> script = new CachedResource<String>(url, String.class, CachedResource.ONE_DAY) {
@ -219,7 +193,7 @@ public class ArgumentProcessor {
return Charset.forName("UTF-8").decode(data).toString();
}
};
return new Script(script.get(), trusted);
return script.get();
}
}

View File

@ -16,8 +16,8 @@ import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
@ -164,10 +164,10 @@ public class GroovyPad extends JFrame {
protected ScriptShell createScriptShell() {
try {
DefaultScriptProvider scriptProvider = new DefaultScriptProvider(true);
DefaultScriptProvider scriptProvider = new DefaultScriptProvider();
scriptProvider.setBaseScheme(new URI("fn", "%s", null));
return new ScriptShell(new CmdlineOperations(), ArgumentBean.parse(new String[0]), AccessController.getContext(), scriptProvider);
return new ScriptShell(scriptProvider, new HashMap<String, Object>());
} catch (Exception e) {
throw new RuntimeException(e);
}
@ -232,15 +232,15 @@ public class GroovyPad extends JFrame {
@Override
public void run() {
try {
result = shell.evaluate(script, new SimpleBindings(), true);
result = shell.evaluate(script, new SimpleBindings());
// print result and make sure to flush Groovy output
SimpleBindings binding = new SimpleBindings();
binding.put("result", result);
if (result != null) {
shell.evaluate("print('Result: '); println(result);", binding, true);
shell.evaluate("print('Result: '); println(result);", binding);
} else {
shell.evaluate("println();", binding, true);
shell.evaluate("println();", binding);
}
} catch (ScriptException e) {
while (e.getCause() instanceof ScriptException) {

View File

@ -2,35 +2,18 @@ package net.sourceforge.filebot.cli;
import groovy.lang.GroovyClassLoader;
import java.awt.AWTPermission;
import java.io.File;
import java.io.FilePermission;
import java.io.InputStreamReader;
import java.lang.management.ManagementPermission;
import java.lang.reflect.ReflectPermission;
import java.net.SocketPermission;
import java.net.URI;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Permissions;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.PropertyPermission;
import java.util.ResourceBundle;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import javax.script.SimpleScriptContext;
import net.sourceforge.filebot.format.ExpressionFormat;
import net.sourceforge.filebot.format.PrivilegedInvocation;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.customizers.ImportCustomizer;
@ -42,16 +25,26 @@ public class ScriptShell {
private final ScriptEngine engine;
private final ScriptProvider scriptProvider;
public ScriptShell(CmdlineInterface cli, ArgumentBean args, AccessControlContext acc, ScriptProvider scriptProvider) throws ScriptException {
public ScriptShell(ScriptProvider scriptProvider, Map<String, ?> globals) throws ScriptException {
this.engine = createScriptEngine();
this.scriptProvider = scriptProvider;
// setup bindings
Bindings bindings = engine.createBindings();
bindings.putAll(globals);
// bind API objects
// TODO remove
bindings.put("_cli", new CmdlineOperations());
bindings.put("_shell", this);
// setup script context
ScriptContext context = new SimpleScriptContext();
context.setBindings(initializeBindings(cli, args, acc), ScriptContext.GLOBAL_SCOPE);
context.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
engine.setContext(context);
// import additional functions into the shell environment
// TODO remove
engine.eval(new InputStreamReader(ExpressionFormat.class.getResourceAsStream("ExpressionFormat.lib.groovy")));
engine.eval(new InputStreamReader(ScriptShell.class.getResourceAsStream("ScriptShell.lib.groovy")));
}
@ -74,22 +67,22 @@ public class ScriptShell {
return new GroovyScriptEngineImpl(classLoader);
}
public Object evaluate(final String script, final Bindings bindings) throws Throwable {
try {
return engine.eval(script, bindings);
} catch (Throwable e) {
while (e.getClass() == ScriptException.class && e.getCause() != null) {
e = e.getCause();
}
throw StackTraceUtils.deepSanitize(e); // make Groovy stacktrace human-readable
}
}
public static interface ScriptProvider {
public URI getScriptLocation(String input) throws Exception;
public Script fetchScript(URI uri) throws Exception;
}
public static class Script {
public final String code;
public final boolean trusted;
public Script(String code, boolean trusted) {
this.code = code;
this.trusted = trusted;
}
public String fetchScript(URI uri) throws Exception;
}
public Object runScript(String input, Bindings bindings) throws Throwable {
@ -97,90 +90,7 @@ public class ScriptShell {
}
public Object runScript(URI resource, Bindings bindings) throws Throwable {
Script script = scriptProvider.fetchScript(resource);
return evaluate(script.code, bindings, script.trusted);
}
public Object evaluate(final String script, final Bindings bindings, boolean trustScript) throws Throwable {
try {
if (trustScript) {
return engine.eval(script, bindings);
}
try {
return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws ScriptException {
return engine.eval(script, bindings);
}
}, getSandboxAccessControlContext());
} catch (PrivilegedActionException e) {
throw e.getException();
}
} catch (Throwable e) {
while (e.getClass() == ScriptException.class && e.getCause() != null) {
e = e.getCause();
}
throw StackTraceUtils.deepSanitize(e); // make Groovy stack human-readable
}
}
protected Bindings initializeBindings(CmdlineInterface cli, ArgumentBean args, AccessControlContext acc) {
Bindings bindings = new SimpleBindings();
// bind external parameters
if (args.bindings != null) {
for (Entry<String, String> it : args.bindings.entrySet()) {
bindings.put(it.getKey(), it.getValue());
}
}
// bind API objects
bindings.put("_cli", PrivilegedInvocation.newProxy(CmdlineInterface.class, cli, acc));
bindings.put("_script", args.script);
bindings.put("_args", args);
bindings.put("_shell", this);
Map<String, String> defines = new LinkedHashMap<String, String>();
if (args.bindings != null) {
for (Entry<String, String> it : args.bindings.entrySet()) {
defines.put(it.getKey(), it.getValue());
}
}
bindings.put("_def", defines);
return bindings;
}
protected AccessControlContext getSandboxAccessControlContext() {
Permissions permissions = new Permissions();
permissions.add(new RuntimePermission("createClassLoader"));
permissions.add(new RuntimePermission("accessClassInPackage.*"));
permissions.add(new RuntimePermission("modifyThread"));
permissions.add(new FilePermission("<<ALL FILES>>", "read"));
permissions.add(new SocketPermission("*", "connect"));
permissions.add(new PropertyPermission("*", "read"));
permissions.add(new RuntimePermission("getenv.*"));
permissions.add(new RuntimePermission("getFileSystemAttributes"));
permissions.add(new ManagementPermission("monitor"));
// write permissions for temp and cache folders
permissions.add(new FilePermission(new File(System.getProperty("ehcache.disk.store.dir")).getAbsolutePath() + File.separator + "-", "write, delete"));
permissions.add(new FilePermission(new File(System.getProperty("java.io.tmpdir")).getAbsolutePath() + File.separator + "-", "write, delete"));
// AWT / Swing permissions
permissions.add(new AWTPermission("accessEventQueue"));
permissions.add(new AWTPermission("toolkitModality"));
permissions.add(new AWTPermission("showWindowWithoutWarningBanner"));
// this is probably a security problem but nevermind
permissions.add(new RuntimePermission("accessDeclaredMembers"));
permissions.add(new ReflectPermission("suppressAccessChecks"));
permissions.add(new RuntimePermission("modifyThread"));
return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, permissions) });
return evaluate(scriptProvider.fetchScript(resource), bindings);
}
}

View File

@ -1,3 +1,3 @@
scriptBaseClass: net.sourceforge.filebot.cli.ScriptShellBaseClass
starImport: net.sourceforge.filebot, net.sourceforge.filebot.util, net.sourceforge.filebot.web, net.sourceforge.filebot.media, net.sourceforge.filebot.mediainfo, net.sourceforge.filebot.hash, net.sourceforge.filebot.similarity, groovy.io, groovy.xml, groovy.json, org.jsoup, java.nio.file, java.nio.file.attribute, java.util.regex
starImport: net.sourceforge.filebot, net.sourceforge.filebot.hash, net.sourceforge.filebot.media, net.sourceforge.filebot.mediainfo, net.sourceforge.filebot.similarity, net.sourceforge.filebot.subtitle, net.sourceforge.filebot.torrent, net.sourceforge.filebot.web, net.sourceforge.filebot.util, groovy.io, groovy.xml, groovy.json, org.jsoup, java.nio.file, java.nio.file.attribute, java.util.regex
starStaticImport: net.sourceforge.filebot.WebServices, net.sourceforge.filebot.media.MediaDetection, java.nio.file.Files

View File

@ -1,10 +1,12 @@
package net.sourceforge.filebot.cli;
import static net.sourceforge.filebot.Settings.*;
import static net.sourceforge.filebot.cli.CLILogging.*;
import groovy.lang.Closure;
import groovy.lang.Script;
import java.io.Console;
import java.util.Map;
import java.util.logging.Logger;
import net.sourceforge.filebot.MediaTypes;
@ -30,6 +32,16 @@ public abstract class ScriptShellBaseClass extends Script {
return null;
}
// define global variable: _args
public ArgumentBean get_args() {
return getApplicationArguments();
}
// define global variable: _def
public Map<String, String> get_def() {
return getApplicationArguments().bindings;
}
// define global variable: _system
public AssociativeScriptObject get_system() {
return new AssociativeScriptObject(System.getProperties());