I would like to get a clear answer on how to Sandbox execution Nashorn within a Java Application.
I have seen 'similar questions' (which I will refer to) but ultimately none of the answer seem to address my concerns.
Let me start with definitions.
Assume we start with this:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
engine.put("map",new HashMap());
engine.eval(jsCode); // jsCode can access 'map' only.
By "Sandboxing" I mean ensure that the JavaScript must not access any java object except the one added in the scope.
so the following evals should be fine.
engine.eval("map.toString()");
engine.eval("map.size()");
engine.eval("map.put('name','jeff'); ");
engine.eval("map.getClass()");
But the following evals will not:
engine.eval("var m = new java.util.HashMap();"); // <-- stop accessing Java
engine.eval("map.getClass().forName('java.io.File'); "); // stop. it's trying to be sneaky
Finally, I am not concerned about this:
engine.eval("while(1) {;}"); // this is impossible to detect. Maybe it's possible for this simple case... but sneaky users could make it impossible to detect... anyway this is not what I am asking. I am only concerned on accessing java objects.
So by sandboxing I intend to prevent jsCode to access java objects that I don't define.
I saw that this might be a potential solution:
jdk.nashorn.api.scripting.NashornScriptEngineFactory factory = new jdk.nashorn.api.scripting.NashornScriptEngineFactory();
ScriptEngine engine = factory.getScriptEngine(new jdk.nashorn.api.scripting.ClassFilter() {
public boolean exposeToScripts(String s) {
return false;
}
});
but is it 'safe' to access a package beginning with jdk.* directly ?
Another approach I saw is even more mysterious:
final ScriptEngine engine =
new NashornScriptEngineFactory().getScriptEngine(new String[] { "--no-java" });
I saw that one here:
Safely re-using sandboxed Nashorn containers
Can somebody let me know ?
You can use jdk.nashorn.api.scripting.* API if that would help in your application. javadoc for the same is here -> https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/
And yes, --no-java is the option for preventing java package access from script code.
Related
My application uses a ScriptEngine to offer plugin-ability to my end-users.
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByName("nashorn");
Whenever a user makes changes to his script, then the application replaces the engine instane by a new instance.
String newScript = ...;
engine = engineManager.getEngineByName("nashorn");
engine.eval(newScript);
Two closely related questions:
Should I try to reuse engines and perform some kind of clear() on them ?
If I just replace my engine with a new instance, should I dispose the previous instance in some way, to avoid memory leaks ? (e.g. I can imagine that the user could manage to create a script that starts a thread.)
The problem is, I cannot find any method that looks like a clear() or a dispose(). Does that mean that my current approach is correct ?
You can use a single engine instance but use separate Bindings objects. Bindings acts as a top-level program environment, so if you want to evaluate a script into what is basically a "new global scope" then you could do that. Look into javax.script API docs on how to do this. You can either use ScriptEngine.eval that takes a Bindings as second argument or the one that takes ScriptContext as second argument.
Even if there's no script code surviving from the previous evaluation, you'll save some initialization time as the script engine will already have predefined various JavaScript data-holder classes and property maps ("hidden classes").
Also: yes, everything is garbage collected. There's no need for an explicit "disposal" API.
I just wanted to share what I tested myself. It makes perfect sense, but for those still in doubt: Created threads do continue to run if you just replace engine instances:
public static void main(String[] args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
String script =
"new java.lang.Thread(function() {\n" +
" for(;;) {" +
" print('Here\\'s Johnny !');" +
" java.lang.Thread.sleep(1000);" +
" }\n" +
"}).start();";
ScriptEngine engine = manager.getEngineByName("nashorn");
try {
engine.eval(script);
} catch (ScriptException e) {
e.printStackTrace();
}
// replace engine
engine = manager.getEngineByName("nashorn");
engine.eval("print('please, make it stop!!!');");
// please collect !!!
System.gc();
}
Output:
Here's Johnny !
please, make it stop!!!
Here's Johnny !
Here's Johnny !
Here's Johnny !
...
I guess that the garbage collector can clean the scripts, but not their actions outside their context. I think created threads are not even linked to the scripts in any way (i.e. outside their scope). So, I think it's just impossible for the jvm to detect or decide that these threads are linked to a replaced script and may or may not be stopped.
But this leads us too far for one stackoverflow question. Let's just focus on the ability to dispose/clear the bindings (i.e. ScriptContext).
Block java threads in nashorn scripts:
A possible solution, is to narrow down the available functionality. Here follow a couple of ways to avoid the creation of threads:
The following disables all java functionality:
// the option -nj is short for --no-java
ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine("-nj");
But you can also disable specific classes, using a ClassFilter.
ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine((className) -> {
if ("java.lang.Thread".equals(className)) return false;
if ("java.lang.Runnable".equals(className)) return false;
if ("java.util.Timer".equals(className)) return false;
if (className.startsWith("java.util.concurrency")) return false;
if (className.startsWith("javafx")) return false;
if (className.startsWith("javax.swing")) return false;
if (className.startsWith("java.awt")) return false;
return true;
});
Note: as soon as you define a ClassFilter also reflection classes are blocked automatically. So, you don't have to block those packages explicitly.
I am using java jinput library to read data from joypad, and I have trouble reloading Controllers, I use this to load them:
public Controller[] findStickControllers() {
ControllerEnvironment ce =
ControllerEnvironment.getDefaultEnvironment();
Controller[] cs = ce.getControllers();
System.out.println(cs.length); //test
ArrayList<Controller> sel = new ArrayList<>();
for (Controller c: cs) {
if(c.getType() == Type.STICK) {
sel.add(c);
}
}
return sel.toArray(new Controller[]{});
}
This works fine, but if I disconnect my controller, calling this will find it again, and vice versa (connecting it after the first check will not find it at all).
I have tried to put sleep before the fist lookup, with these results:
Controllers are acctually scanned when this method is called first time (not at start of the program)
When called again, this always returns same controllers as it returned for the first time.
First call will also write warning bellow
Even when controller is connected (and works), then disconnected (it will still find it though) and reconnected, it will not work
Warning from point 3: (didn't format well in the list)
WARNING: Found unknown Windows version: Windows 8
Attempting to use default windows plug-in.
Loading: net.java.games.input.DirectAndRawInputEnvironmentPlugin
I am using Win 8, and had same problem on Win 7. I had also tried this with mouse, same results.
How can I acctually reload controllers for the 2nd, 3rd, and so on time?
I encountered the same problem. The reason is that the actual hardware scan happens only once for each DefaultControllerEnvironment object. Since the only accessible instantiation is a singleton, it never does another scan.
A simple way to force a hardware scan is to create a new object, but neither the class nor the constructor are public. You can however work around this limitation by calling the constructor via reflection.
Rescan
private static ControllerEnvironment createDefaultEnvironment() throws ReflectiveOperationException {
// Find constructor (class is package private, so we can't access it directly)
Constructor<ControllerEnvironment> constructor = (Constructor<ControllerEnvironment>)
Class.forName("net.java.games.input.DefaultControllerEnvironment").getDeclaredConstructors()[0];
// Constructor is package private, so we have to deactivate access control checks
constructor.setAccessible(true);
// Create object with default constructor
return constructor.newInstance();
}
Usage
// Be aware that creating a new environment is fairly expensive
Controller[] controllers = createDefaultEnvironment().getControllers();
Remove Windows 8 Warnings
/**
* Fix windows 8 warnings by defining a working plugin
*/
static {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
String os = System.getProperty("os.name", "").trim();
if (os.startsWith("Windows 8")) { // 8, 8.1 etc.
// disable default plugin lookup
System.setProperty("jinput.useDefaultPlugin", "false");
// set to same as windows 7 (tested for windows 8 and 8.1)
System.setProperty("net.java.games.input.plugins", "net.java.games.input.DirectAndRawInputEnvironmentPlugin");
}
return null;
}
});
}
If you use the accepted answer, you might want to consider killing the thread that was spawned by the previous environment before setting a new one because it won't be cleaned up otherwise. You can do so by calling something like:
final Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (final Thread thread : threadSet) {
final String name = thread.getClass().getName();
if (name.equals("net.java.games.input.RawInputEventQueue$QueueThread")) {
thread.interrupt();
try {
thread.join();
} catch (final InterruptedException e) {
thread.interrupt();
}
}
}
The warning is because the last time I updated that code windows 7 wasn't even out IIRC, I'll update it.
The controller reload is a feature that has been requested a number of times, but no-one deems it important enough to spend any time implementing it. If you submit a patch I'll take a look and see about committing it. Until someone finds it important enough to spend the time to write it, it's just a missing feature.
I had the same problem before.
I add the rescanning feature (for Windows back-end only) and post the patch on Java gaming forum but no ones seem interested in to integrate it.
So if you need it, apply my patch from here: http://www.java-gaming.org/topics/rescan-controllers/24782/msg/224604/view.html#msg224604
I currently know Java and Ruby, but have never used JRuby. I want to use some RAM- and computation-intensive Java code inside a Rack (sinatra) web application. In particular, this Java code loads about 200MB of data into RAM, and provides methods for doing various calculations that use this in-memory data.
I know it is possible to call Java code from Ruby in JRuby, but in my case there is an additional requirement: This Java code would need to be loaded once, kept in memory, and kept available as a shared resource for the sinatra code (which is being triggered by multiple web requests) to call out to.
Questions
Is a setup like this even possible?
What would I need to do to accomplish it? I am not even sure if this is a JRuby question per se, or something that would need to be configured in the web server. I have experience with Passenger and Unicorn/nginx, but not with Java servers, so if this does involve configuration of a Java server such as Tomcat, any info about that would help.
I am really not sure where to even start looking, or if there is a better way to be approaching this problem, so any and all recommendations or relevant links are appreciated.
Yes, a setup it's possibile ( see below about Deployment ) and to accomplish it I would suggest to use a Singleton
Singletons in Jruby
with reference to question: best/most elegant way to share objects between a stack of rack mounted apps/middlewares? I agree with Colin Surprenant's answer, namely singleton-as-module pattern which I prefer over using the singleton mixin
Example
I post here some test code you can use as a proof of concept:
JRuby sinatra side:
#file: sample_app.rb
require 'sinatra/base'
require 'java' #https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby
java_import org.rondadev.samples.StatefulCalculator #import you java class here
# singleton-as-module loaded once, kept in memory
module App
module Global extend self
def calc
#calc ||= StatefulCalculator.new
end
end
end
# you could call a method to load data in the statefull java object
App::Global.calc.turn_on
class Sample < Sinatra::Base
get '/' do
"Welcome, calculator register:#{App::Global.calc.display}"
end
get '/add_one' do
"added one to calculator register, new value:#{App::Global.calc.add(1)}"
end
end
You can start it in tomcat with trinidad or simply with rackup config.ru but you need:
#file: config.ru
root = File.dirname(__FILE__) # => "."
require File.join( root, 'sample_app' ) # => true
run Sample # ..in sample_app.rb ..class Sample < Sinatra::Base
something about the Java Side:
package org.rondadev.samples;
public class StatefulCalculator {
private StatelessCalculator calculator;
double register = 0;
public double add(double a) {
register = calculator.add(register, a);
return register;
}
public double display() {
return register;
}
public void clean() {
register = 0;
}
public void turnOff() {
calculator = null;
System.out.println("[StatefulCalculator] Good bye ! ");
}
public void turnOn() {
calculator = new StatelessCalculator();
System.out.println("[StatefulCalculator] Welcome !");
}
}
Please note that the register in here is only a double but in your real code you can have a big data structure in your real scenario
Deployment
You can deploy using Mongrel, Thin (experimental), Webrick (but who would do that?), and even Java-centric application containers like Glassfish, Tomcat, or JBoss. source: jruby deployments
with TorqueBox that is built on the JBoss Application Server.
JBoss AS includes high-performance clustering, caching and messaging functionality.
trinidad is a RubyGem that allows you to run any Rack based applet wrap within an embedded Apache Tomcat container
Thread synchronization
Sinatra will use Mutex#synchronize method to place a lock on every request to avoid race conditions among threads. If your sinatra app is multithreaded and not thread safe, or any gems you use is not thread safe, you would want to do set :lock, true so that only one request is processed at a given time. .. Otherwise by default lock is false, which means the synchronize would yield to the block directly.
source: https://github.com/zhengjia/sinatra-explained/blob/master/app/tutorial_2/tutorial_2.md
Here are some instructions for how to deploy a sinatra app to Tomcat.
The java code can be loaded once and reused if you keep a reference to the java instances you have loaded. You can keep a reference from a global variable in ruby.
One thing to be aware of is that the java library you are using may not be thread safe. If you are running your ruby code in tomact, multiple requests can execute concurrently, and those requests may all access your shared java library. If your library is not thread safe, you will have to use some sort of synchronization to prevent multiple threads accessing it.
Is it possible to use JavaScript in Android?? if so, how? Please provide some examples.
Thanks.
I am way late to the party here, but I had this exact need. iOS 7 now includes JavaScriptCore
natively and it is really easy to use (despite limited documentation). The problem is that
I didn't want to use it unless I could also use something similar on Android. So I created the AndroidJSCore project. It allows you to use your JavaScript code natively in Android without requiring a bulky WebView and injection. You can also seamlessly make asynchronous
calls between Java and Javascript.
Update 27 Mar 17: AndroidJSCore has been deprecated in favor of LiquidCore. LiquidCore is based on V8 rather than JavascriptCore, but works essentially same. See the documentation on using LiquidCore as a raw Javascript engine.
From the documentation:
... to get started, you need to create a JavaScript JSContext. The execution of JS code
occurs within this context, and separate contexts are isolated virtual machines which
do not interact with each other.
JSContext context = new JSContext();
This context is itself a JavaScript object. And as such, you can get and set its properties.
Since this is the global JavaScript object, these properties will be in the top-level
context for all subsequent code in the environment.
context.property("a", 5);
JSValue aValue = context.property("a");
double a = aValue.toNumber();
DecimalFormat df = new DecimalFormat(".#");
System.out.println(df.format(a)); // 5.0
You can also run JavaScript code in the context:
context.evaluateScript("a = 10");
JSValue newAValue = context.property("a");
System.out.println(df.format(newAValue.toNumber())); // 10.0
String script =
"function factorial(x) { var f = 1; for(; x > 1; x--) f *= x; return f; }\n" +
"var fact_a = factorial(a);\n";
context.evaluateScript(script);
JSValue fact_a = context.property("fact_a");
System.out.println(df.format(fact_a.toNumber())); // 3628800.0
You can also write functions in Java, but expose them to JavaScript:
JSFunction factorial = new JSFunction(context,"factorial") {
public Integer factorial(Integer x) {
int factorial = 1;
for (; x > 1; x--) {
factorial *= x;
}
return factorial;
}
};
This creates a JavaScript function that will call the Java method factorial when
called from JavaScript. It can then be passed to the JavaScript VM:
context.property("factorial", factorial);
context.evaluateScript("var f = factorial(10);")
JSValue f = context.property("f");
System.out.println(df.format(f.toNumber())); // 3628800.0
Do you mean something like making a native app using Javascript? I know there are tools like Titanium Mobile that let you make native apps using web tools/languages.
You could also make Web Apps. There are loads of resources and tutorials out there for that. Just search "Android Web App tutorial" or something similar.
Yes you can, just create a wrap up code that points to html page and includes your javascript and css.
There are different libraries that can help you with this:
http://www.phonegap.com/
http://www.sencha.com/products/touch/
http://jquerymobile.com/
Just posting this for posterity but React Native is a great solution in this space. You can write a complete app in JS using native views under the hood, or embed a JS component inside an existing Java app. https://reactnative.dev/
How can I use java to get a js file located on a web server, then execute the function in the js file and get the result and use the result in java.
Can you guys give me some code snippet? Great thanks.
You can use the scripting engine built into Java:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public static void main(String[] args) throws Exception {
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
Object result = engine.eval("my-java-script-code")
System.out.println("Result returned by Javascript is: " + result);
}
Here is a more elaborate example.
There's three steps to this process:
Fetch the JS file from the server.
Execute some JS function from the file.
Extract the result.
The first step is fairly simple, there are lots of HTTP libraries in Java that will do this - you effectively want to emulate the simple functionality of something like wget or curl. The exact manner in which you do this will vary depending on what format you want the JS file in for the next step, but the process to get hold of the byte stream is straightforward.
The second step will require executing the JS in a Javascript engine. Java itself cannot interpret Javascript, so you'd need to obtain an engine to run it in - Rhino is a common choice for this. Since you'd need to run this outside of Java, you'll likely have to spawn a process for execution in Rhino using ProcessBuilder. Additionally, depending on the format of the Javascript you might need to create your own "wrapper" javascript that functions like a main class in Java and calls the method in question.
Finally you need to get the result out - obviously you don't have direct access to JavaScript objects from your Java program. The easiest way is going to be for the JS program to print the result to standard out (possibly serialising as something like JSON depending on the complexity of the object), which is being streamed directly to your Java app due to the way you launched the Rhino process. This could be another job for your JS wrapper script, if any. Otherwise, if the JS function has observable side effects (creates a file/modifies a database) then you'll be able to query those directly from Java.
Job done.
I hope you realise this question is far too vague to get full answers. Asking the public to design an entire system goes beyond the point where you'll get useful, actionable responses.
There are plenty of examples on the web of how to download a file from a URL.
Suns version of the JDK and JRE includes the Mozilla Rhino scripting engine.
Assuming you have stored the contents of the javascript file in a string called 'script', you can execute scripts as follows
String result = null;
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");
try {
jsEngine.eval(script);
result = jsEngine.get("result")
} catch (ScriptException ex) {
ex.printStackTrace();
}
The result will be extracted from the engine and stored in the 'result' variable.
The is a tutorial on scripting in Java that might be useful.