Eclipse allows you debug applets using sun.applet.AppletViewer. It will actually start the applet, run it and emulate complete browser runtime. If you have javascript manipulation code in your applet this will cause JSException because the present context is not a real JS enabled engine.
How would you solve this issue? I can see several possible paths:
Wrap the exception in try {} catch () and ignore it - Not good practice.
Pass and environment flag that would tell the code we are currently in debug mode, so that it won't try to execute JS code - OK but will need manual intervention from each developer.
Identify current context is not a browser - How?
Find another AppletViewer that can emulate a complete browser behavior, including JS - Is there ?
More?
Thank for your ideas.
Not a fail safe but a workable solution I've managed to come up with:
private void notifySelectionState(){
JSObject jsObject = null;
try {
jsObject = JSObject.getWindow(applet);
// An exception can be thrown here (hopefully) only is running in debug environment...
} catch (JSException e) {
// So actually what I'm doing here is checking (in a very lame fashion) for if I'm in a the browser
// content or in the AppletViewer
}
if (jsObject != null) {
jsObject.call(...);
}
}
On certain older browsers, JSObject will throw generic RuntimeExceptions instead of JSException. So you may want to throw your net a little bit wider and leave a good comment in your wrappers.
Related
I'm trying to mock the date on a CefSharp browser by injecting MockDate and setting it to some fixed date before every other script runs. Every window object, on any frame, at any time, should only have access to the mocked date, so the ideal would be to internally redefine the JavaScript Date object, but I don't think CefSharp or probably even Chromium has this option. I'm also going to mock some other functions like setTimeout and Math.rand, to prevent the browser from having any side effects (this is part of a larger project whose aim is to be able to record/replay browsing activity), so messing with OS's time wouldn't solve it.
I considered using RegisterJsObject since it can actually overwrite existing globals, but I don't think there is a way to pass a JavaScript constructor.
What I've tried so far is to handle the FrameLoadStart event:
private static string Inject = File.ReadAllText("Inject.js");
private void ChromeBrowser_FrameLoadStart(object sender, FrameLoadStartEventArgs e)
{
e.Frame.ExecuteJavaScriptAsync(Inject);
}
Where "Inject.js" contains the mock date code. But I've noticed that, randomly, sometimes it'll work and sometimes it won't. I guess because the function is async and the javascript context sometimes haven't been created, since according to the documentations you shouldn't run scripts here. The documentation recommends handling OnContextCreated instead, but it only runs for the main frame, which wouldn't let me inject the code on any iframe. So I wonder if I have any alternative.
In case anyone else need this, the solution was to modify the actual C++ CefSharp code by adding a line to the end of CefAppUnmanagedWrapper::OnContextCreated:
frame->ExecuteJavaScript(CodeToInject, "something://something", 1);
This won't work if injected on the C# side, I believe because these calls are async so you may be injecting it too late, after scripts on the page have already run.
If you can edit HTML entry points then you can just add window.Date = MockDate before any other scripts. For example:
<html>
<body>
<script src="mockdate.js"></script>
<script>
window.Date = MockDate
</script>
<script src="myscript.js"></script>
</body>
</html>
So the idea is you can tune script loading order in your HTML. It can be done in any browser.
If you can not or do not want to edit HTML then it's much trickier. You could use CefLoadHandler in CEF C++ or its alternative in CefSharp.
UPD
Actually i'm not sure about CefLoadHandler. The reliable way would be to implement your own CefRenderProcessHandler But you already mentioned it. If it doesn't work then it's a bug in CefSharp or CEF C++ itself. In that case it would be better to write about it on http://magpcss.org/ceforum/
I am sorry if this is an unclear title because I do not know all the terminology, so please bear with me.
So I am trying to create a controlled environment to run any JavaScript code in a Java application. Note: code is created by a user so I have to block/prevent code that is specifically trying to access/modify java variables that are not supposed to be at reach. (preferably by throwing a compile error for user feedback)
Edit 1: By the way I tried to use Rhino and Nashorn.
Here is a simple example.
public class ScriptRunner{
public Foo foo=new Foo();
//this is not supposed to be accessed by the script
public int money=0;
public Object run(){
return compiler.compile(STRING START (obtained from a file)
function main(someObject){
//this is not allowed
someObject.money=10000000000000000000000;
//or this
var someBlacklistedJavaObject=.....
someBlacklistedJavaObject.someFuncton();
//but this is allowed
someObject.foo.name="Bob";
return someObject.foo.someFunction();
}
STRING END).run("main",this);
}
}
Also I am not sure if this would be one of the possible solution but I can't use the built in java security class due to some unreachable code implementing it and not allowing to set the security object to anything else.
What comes to my mind is that an easy implementation of this would be to create wrapper Java classes in some package. Than check if a java object in script does not have that path and throw an error. But the problem is that I have no idea how to do that.
Here is a simple visualization of what I am trying to do.
Edit 2: It is desirable to maintain a low Java compatibility profile, but it's not 100% necessary.
Use a ClassFilter with Nashorn (note: requires Java >= 1.8.0_40)
I just started playing around with Windows Dev and please pardon me if this issue does not seem logical or legit to you.
I am trying these Chakra Host samples on Microsoft GitHub and when input js cond like console.log or alert, I get error like 'console' is undefined. Am I missing something obvious. I tried looking up but unfortunately could not find the relevant docs or code sample.
Any help/pointer is appreciated.
The console is a web browser (and Node) feature. It doesn't exist within JavaScript. So, you need to add it (or something similar).
There's an example in the Win32 Edge/Chakra host code on Github that demonstrates how to add a callback function to the global namespace.
Example callback for Echo
You should be able to do something similar. You can also expose existing Windows runtime namespaces to Chakra.
private static void DefineHostCallback(JavaScriptValue globalObject, string callbackName, JavaScriptNativeFunction callback, IntPtr callbackData)
{
var propertyId = JavaScriptPropertyId.FromString(callbackName);
// Create a function
var function = JavaScriptValue.CreateFunction(callback, callbackData);
// Set the property
globalObject.SetProperty(propertyId, function, true);
}
Well here's a problem.
I've got a website with large javascript backend. This backend talks to a server over a socket with a socket bridge using http://blog.deconcept.com/swfobject/
The socket "bridge" is a Flex/Flash .swf application/executable/plugin/thing for which the source is missing.
I've got to change it.
More facts:
file appExePluginThing.swf
appExePluginThing.swf Macromedia Flash data (compressed), version 9
I've used https://www.free-decompiler.com/flash/ to decompile the .swf file and I think I've sorted out what's the original code vs the libraries and things Flash/Flex built into it.
I've used FDT (the free version) to rebuild the decompiled code into MYappExePluginThing.swf so I can run it with the javascript code and see what happens.
I'm here because what happens isn't good. Basically, my javascript code (MYjavascript.js) gets to the point where it does
window.log("init()");
var so = new SWFObject("flash/MYappExePluginThing.swf"", socketObjectId, "0", "0", "9", "#FFFFFF");
window.log("init() created MYappExecPluginThing!!!");
so.addParam("allowScriptAccess", "always");
log("init() added Param!!");
so.write(elId);
log("init() wrote!");
IE9's console (yeah, you read that right) shows
init()
created MYappExecPluginThing!!!
init() added Param!!
init() wrote!
but none of the debugging i've got in MYappExePluginThing.as displays and nothing else happens.
I'm trying to figure out what I've screwed up/what's going on? Is MYappExePluginThing.as running? Is it waiting on something? Did it fail? Why aren't the log messages in MYappExePluginThing.as showing up?
The first most obvious thing is I'm using FDT which, I suspect, was not used to build the original. Is there some kind of magic "build javascript accessible swf thing" in FlashBuilder or some other IDE?
First noteworthy thing I find is:
file MYappExePluginThing.swf
MYappExePluginThing.swf Macromedia Flash data (compressed), version 14
I'm using Flex 4.6 which, for all I know, may have a completely different mechanism for allowing javascript communication than was used in appExePluginThing.swf
Does anyone know if that's true?
For example, when FDT runs this thing (I can compile but FDT does not create a .swf unless i run it) I get a warning in the following method:
private function init() : void
{
Log.log("console.log", "MYappExePluginThing init()");
//var initCallback:String = Application.application.parameters.initCallback?Application.application.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
var initCallback:String = FlexGlobals.topLevelApplication.parameters.initCallback?FlexGlobals.topLevelApplication.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
try
{
ExternalInterface.addCallback("method1Callback",method1);
ExternalInterface.addCallback("method2Callback",method2);
ExternalInterface.call(initCallback);
}
catch(err:Error)
{
Log.log("console.log", "MYappExePluginThing init() ERROR err="+err);
}
}
I got a warning that Application.application was deprecated and I should change:
var initCallback:String = Application.application.parameters.initCallback?Application.application.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
to:
var initCallback:String = FlexGlobals.topLevelApplication.parameters.initCallback?FlexGlobals.topLevelApplication.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
which I did but which had no effect on making the thing work.
(FYI Log.log() is something I added:
public class Log{
public static function log(dest:String, mssg:String):void{
if(ExternalInterface.available){
try{
ExternalInterface.call(dest, mssg);
}
catch(se:SecurityError){
}
catch(e:Error){
}
}
trace(mssg);
}
}
)
Additionally, in MYjavascript.js MYappExePluginThing_init looks like this:
this.MYappExePluginThing_init = function () {
log("MYjavascript.js - MYappExePluginThing_init:");
};
Its supposed to be executed when MYappExePluginThing finishes initializing itself.
Except its not. The message is NOT displaying on the console.
Unfortunately, I cannot find any references explaining how you allow javascript communication in Flex 4.6 so I can check if I've got this structured correctly.
Is it a built in kind of thing all Flex/Flash apps can do? Is my swf getting accessed? Is it having some kind of error? Is it unable to communicate back to my javascript?
Does anyone have any links to references?
If this was YOUR problem, what would you do next?
(Not a full solution but I ran out of room in the comment section.)
To answer your basic question, there's nothing special you should need to do to allow AS3-to-JS communication beyond what you've shown. However, you may have sandbox security issues on localhost; to avoid problems, set your SWFs as local-trusted (right-click Flash Player > Global Settings > Advanced > Trusted Location Settings). I'm guessing this not your problem, though, because you'd normally get a sandbox violation error.
More likely IMO is that something is broken due to decompilation and recompilation. SWFs aren't meant to do that, it's basically a hack made mostly possible due to SWF being an open format.
What I suggest is that you debug your running SWF. Using break-points and stepping through the code you should be able to narrow down where things are going wrong. You can also more easily see any errors your SWF is throwing.
Not really an answer, but an idea to get you started is to start logging everything on the Flash side to see where the breakage is.
Since you're using IE, I recommend getting the Debug flash player, installing it, then running Vizzy along side to show your traces.
Should give you a good idea of where the app is breaking down.
Vizzy
Debug Player
I have business logic that is written in JavaScript, this code is shared with other non-android apps.
What is the best way to use the functions in this piece of JavaScript from within a Service in Android.
AFAIK, there are 2 options?
V8 that is built into the standard WebView and superfast, no extra apk bloat.
Rhino, which is tricky to get going on Android?
Focusing on V8/Webview, when I attempt to access the WebView, with any function, I get;
All WebView methods must be called on the UI thread. Future versions of WebView may not support use on other threads.
The warning being noted, it doesn't even work now. When I set the webviewclient up, I get nothing after loading an URL.
My question is in 3 parts;
1) Has anyone had any success with running javascript in a webview without a UI thread?
2) How do I get results from the functions inside the javascript, does the webview interface "addJavascriptInterface " support loading a parameter and sending it back to the java?
3) If either of the above are impossible.. I guess I'll go get Rhino, any tips would be appreciated, I've only seen a few blogs complaining of issues with regards to getting it going on Android and wondering if there is a "go to" version for android maintained somewhere.
Couldn't find anything with regards to V8 from deep down in a service.
Ended up using Rhino, however a word of warning to anyone following down my footsteps, it's incredibly slow.
Just grab the jar from the official latest distribution of Rhino from
https://developer.mozilla.org/en-US/docs/Rhino/Download_Rhino?redirectlocale=en-US&redirectslug=RhinoDownload
js.jar is what you need in the zip. js-14 is a bigger java 1.4 compatible version you don't need.
Integration was a snap just chuck the jar into your libs folder.
Below is me scraping a webpage using javascript (turning the data into better formatted json). With the parse.js script I made coming from the assets folder.
Rhino doesn't come with DOM, and env.js crashes out with stackoverflow errors. Overall, I'd say this solution is slow and not well supported...
public static void sync(Context context, ){
String url = BASE_URL;
String html = Utils.inputStreamToString(Utils.getHTTPStream(url));
timeList.add(System.currentTimeMillis());
if(html == null){
Utils.logw("Could not get board list.");
return;
}
String parsingCode = null;
try {
parsingCode = Utils.inputStreamToString(context.getAssets().open("parse.js"));
} catch (IOException e) {
Utils.logw("Could not get board parser js");
return;
}
// Create an execution environment.
org.mozilla.javascript.Context cx = org.mozilla.javascript.Context.enter();
// Turn compilation off.
cx.setOptimizationLevel(-1);
try {
// Initialize a variable scope with bindnings for
// standard objects (Object, Function, etc.)
Scriptable scope = cx.initStandardObjects();
ScriptableObject.putProperty(
scope, "html", org.mozilla.javascript.Context.javaToJS(html, scope));
//load up the function
cx.evaluateString(scope, parsingCode,"parseFunction", 1 , null);
// Evaluate the script.
Object result = cx.evaluateString(scope, "myFunction()", "doit:", 1, null);
JSONArray jsonArray = new JSONArray(result.toString());