GWT code splitting synchronous request - javascript

I´m using code splitting in GWT to reduce the size of the initial JavaScript.
While my application initializes, I want to prefetch the other (bigger) part of my code as explained in the docs (www.gwtproject.org/doc/latest/DevGuideCodeSplitting.html).
private void doSth(final boolean prefetch) {
GWT.runAsync(new RunAsyncCallback() {
public void onFailure(Throwable caught) {
Log.error("Loading the code failed!");
}
public void onSuccess() {
if(prefetch)
return; //do nothing. just a prefetch
//here is the loaded code
}
});
}
But I cannot recognize a performance improvement. As I analyzed the browser logs, I recognized, that the request for loading the JavaScript is not marked as XHR. Does GWT load the code of a split point synchronously?

The performance improvement is in the initial downloaded code, assuming nothing else references that code. If anything else does the work of //here is the loaded code, then there will be either very little or no code to break out into a separately downloaded JS file.
This feature can be disabled in several ways, including by using dev mode or setting a compiler flag to skip this process. In this case, yes, the split point runs synchronously, since it makes no sense to wait. Additionally, after the file has been loaded once, it does not need to be loaded the next time the code is invoked within the same page load.
If your server is set to cache correctly, then after the first visit the savings is even smaller since there is no download to do - you only save the time taken to parse that code into the browser's JS VM.
But beyond that, we're going to need more information.
Here's a quick demo showing how the split point can be written with a little more meat to it, and letting you use your browser to notice how the split point code was brought in separately.
public class SampleEntryPoint implements EntryPoint {
public void onModuleLoad() {
Label label = new Label("Hello, World!");
label.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
GWT.runAsync(new RunAsyncCallback() {
public void onFailure(Throwable var1) {/*ignore*/}
public void onSuccess() {
Window.alert("Clicked, and loaded in split point!");
}
});
}
});
RootPanel.get().add(label);
}
}
Code and sample:
https://viola.colinalworth.com/proj/755e224e7f48a047703d44eb6903d926/project/client/SampleEntryPoint.java
Standalone sample:
https://viola.colinalworth.com:444/compiled/755e224e7f48a047703d44eb6903f76c/
When you load this page, the nocache file loads, as does the initial download (as seen through Chrome's inspector's Network tab):
Then, when you click the Label widget, the onClick fires which triggers the runAsync and downloads the extra split point (plus the "leftover" fragment):
After those two new entries have been added to your Network tab, you see the alert message appear. Subsequent clicks do not result in this slight delay, nor do they force this extra JS to download again.
Also note that these are not loaded as AJAX/XHR calls, but as a script tag to be added to the page. Clicking on the details in the Initiator column (not pictured) leads to this (formatted for readability):
function fb(a) {
var b, c, d;
d = (bb(), window);
b = d.document;
c = b.createElement('script');
(!!a.a || a.b) && cb(c, a.a, a.b);
eb(c, a.c);
(b.head || b.getElementsByTagName('head')[0]).appendChild(c);
return c
}
Getting through the obfuscated code, we see that a <script> tag is created, and appended to the <head> of the page.
Digging in deeper, we can find that the AsyncFragmentLoader.LoadingStrategy interface describes how to go get this fragment, and that com/google/gwt/core/AsyncFragmentLoader.gwt.xml wires this by default to XhrLoadingStrategy. However, both the xs and xsiframe linkers change this, to CrossSiteLoadingStrategy and ScriptTagLoadingStrategy respectively. And as of recent versions of GWT (you didn't specify, so I'm assuming you are using a recent version), the xsiframe linker is the default. From Core.gwt.xml:
<add-linker name="xsiframe" />
We can customize this by switching to the old linker, or just replacing the strategy. Note that switching the an XHR strategy will prevent cross-domain loading from working correctly (such as SuperDevMode), so be careful with this.
Much as AsyncFragmentLoader.gwt.xml wired the interface to XhrLoadingStrategy, and CrossSiteIframeLinker.gwt.xml changed it to ScriptTagLoadingStrategy, we can change it back. We create a rule that replaces LoadingStrategy with XhrLoadingStrategy, and list it after our GWT inherits statements in our .gwt.xml file:
<replace-with class="com.google.gwt.core.client.impl.XhrLoadingStrategy">
<when-type-is class="com.google.gwt.core.client.impl.AsyncFragmentLoader.LoadingStrategy" />
</replace-with>
This is what the old default used to rely on as part of the std linker (com.google.gwt.core.linker.IFrameLinker), though this is no longer encouraged and may be removed in a later release.

Related

Does the browser persistently cache compiled versions of script elements?

In a web app that allows users to play with javascript I require them to have a function main() in their "program". There's a "run" button, and an "edit" button. When you press "run" text from a <textarea> is used to create a script block and insert it into the DOM. Then main() is called.
I catch window.onerror to display errors to the user. This generally works OK. If there is no main(), an appropriate error message is shown.
When you press "edit", the script block is set to blank (script.text = '';),and removed from the DOM.
Testing, I noticed that if I had "program" consisting of just:
function main() { printLn('main here'); }
it worked as expected, but when I changed that to:
function moon() { printLn('moon here'); }
instead of getting a message saying main() not defined, it still worked as before, despite the fact that the script block had the "moon" text. This continued to happen if I gave each created script block a distinctive ID, and if I changed the script block type to text/plain before removing it.
The problem occurs in current Firefox, Chrome, and Opera. You can see what happens here
The functions are still defined, even if you remove the script that defined it.
This is in stark contrast to CSS, where removing or modifying a stylesheet will remove or update the styles on the page accordingly.
There's a good reason for that, and that is that CSS is designed to be easily re-evaluated when changes are made. JavaScript on the other hand is far too complex for the browser to be able to understand what "removing a script" actually does.
So, provided you have run one function with main(), it will continue to exist even if you then delete it.
My suggestion would be to create a closure to run your script. You can do this with something like...
var input = "........"; // user's input
var runner = "if( typeof main === 'undefined') {"+
"showErrorMessage('No main() defined');"+ // or whatever your error function is
"} else { main(); }";
var func = new Function("(function() {"+input+runner+"})()");
func();
It's always worth noting that the global scope can still be accessed, such as if the user forgets to var their local variables, or if they outright access window.something. So long as it's only being run on the user's own machine, this isn't much of an issue, but if people can share their codes with others then you will need to be much more careful.

OnContextCreated() in Cef not being called

I have a similar problem to the person in this post; I'm trying to extend the cefsimple.exe app included with the chromium embedded framework binaries to include a V8 handler. I implemented the OnContextCreated() method and made sure to extend RenderProcessHandler in the SimpleHandler class. I'm trying to implement a simple window bound variable called test_string; here's what my code looks like;
void SimpleHandler::OnContextCreated(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context)
{
CefRefPtr<CefV8Value> object = context->GetGlobal();
object->SetValue("test_string", CefV8Value::CreateString("this is a test"), V8_PROPERTY_ATTRIBUTE_NONE);
}
But the program never arrives at any breakpoints I add within the method, and the variable is undefined on any webpages I load within the app. I saw that one of the solutions in the other thread is to enable the settings.single_process flag, which i've done, but my code still doesn't reach the breakpoint.
To be clear, I'm accessing the variable on pages with window.test_string.
Make sure that you are sending that CefApp to CefExecuteProcess.
CefRefPtr<SimpleApp> app(new SimpleApp);
// CEF applications have multiple sub-processes (render, plugin, GPU, etc)
// that share the same executable. This function checks the command-line and,
// if this is a sub-process, executes the appropriate logic.
int exit_code = CefExecuteProcess(main_args, app, sandbox_info);
if (exit_code >= 0) {
// The sub-process has completed so return here.
return exit_code;
}
Found this solution here
Have you read through the General Usage guide? Some key points below
https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-cefapp
https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-processes
The single_process mode is not supported so I've never used it. In general I'd avoid it. The multi process architecture means you need to attach the debugger to the process. The Chromium guide is relevant to CEF in this instance.
https://www.chromium.org/developers/how-tos/debugging-on-windows#TOC-Attaching-to-the-renderer
you need to ensure your App is derived from CefRenderProcessHandler
not SimpleHandler!!!
class SimpleApp : public CefApp
, public CefRenderProcessHandler
{
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) OVERRIDE;
valdemar-rudolfovich says you need to pass instance of SimpleApp in
CefExecuteProcess

How to edit console using javascript [duplicate]

So apparently because of the recent scams, the developer tools is exploited by people to post spam and even used to "hack" accounts. Facebook has blocked the developer tools, and I can't even use the console.
How did they do that?? One Stack Overflow post claimed that it is not possible, but Facebook has proven them wrong.
Just go to Facebook and open up the developer tools, type one character into the console, and this warning pops up. No matter what you put in, it will not get executed.
How is this possible?
They even blocked auto-complete in the console:
I'm a security engineer at Facebook and this is my fault. We're testing this for some users to see if it can slow down some attacks where users are tricked into pasting (malicious) JavaScript code into the browser console.
Just to be clear: trying to block hackers client-side is a bad idea in general;
this is to protect against a specific social engineering attack.
If you ended up in the test group and are annoyed by this, sorry.
I tried to make the old opt-out page (now help page) as simple as possible while still being scary enough to stop at least some of the victims.
The actual code is pretty similar to #joeldixon66's link; ours is a little more complicated for no good reason.
Chrome wraps all console code in
with ((console && console._commandLineAPI) || {}) {
<code goes here>
}
... so the site redefines console._commandLineAPI to throw:
Object.defineProperty(console, '_commandLineAPI',
{ get : function() { throw 'Nooo!' } })
This is not quite enough (try it!), but that's the
main trick.
Epilogue: The Chrome team decided that defeating the console from user-side JS was a bug and fixed the issue, rendering this technique invalid. Afterwards, additional protection was added to protect users from self-xss.
I located the Facebook's console buster script using Chrome developer tools. Here is the script with minor changes for readability. I have removed the bits that I could not understand:
Object.defineProperty(window, "console", {
value: console,
writable: false,
configurable: false
});
var i = 0;
function showWarningAndThrow() {
if (!i) {
setTimeout(function () {
console.log("%cWarning message", "font: 2em sans-serif; color: yellow; background-color: red;");
}, 1);
i = 1;
}
throw "Console is disabled";
}
var l, n = {
set: function (o) {
l = o;
},
get: function () {
showWarningAndThrow();
return l;
}
};
Object.defineProperty(console, "_commandLineAPI", n);
Object.defineProperty(console, "__commandLineAPI", n);
With this, the console auto-complete fails silently while statements typed in console will fail to execute (the exception will be logged).
References:
Object.defineProperty
Object.getOwnPropertyDescriptor
Chrome's console.log function (for tips on formatting output)
I couldn't get it to trigger that on any page. A more robust version of this would do it:
window.console.log = function(){
console.error('The developer console is temp...');
window.console.log = function() {
return false;
}
}
console.log('test');
To style the output: Colors in JavaScript console
Edit Thinking #joeldixon66 has the right idea: Disable JavaScript execution from console « ::: KSpace :::
Besides redefining console._commandLineAPI,
there are some other ways to break into InjectedScriptHost on WebKit browsers, to prevent or alter the evaluation of expressions entered into the developer's console.
Edit:
Chrome has fixed this in a past release. - which must have been before February 2015, as I created the gist at that time
So here's another possibility. This time we hook in, a level above, directly into InjectedScript rather than InjectedScriptHost as opposed to the prior version.
Which is kind of nice, as you can directly monkey patch InjectedScript._evaluateAndWrap instead of having to rely on InjectedScriptHost.evaluate as that gives you more fine-grained control over what should happen.
Another pretty interesting thing is, that we can intercept the internal result when an expression is evaluated and return that to the user instead of the normal behavior.
Here is the code, that does exactly that, return the internal result when a user evaluates something in the console.
var is;
Object.defineProperty(Object.prototype,"_lastResult",{
get:function(){
return this._lR;
},
set:function(v){
if (typeof this._commandLineAPIImpl=="object") is=this;
this._lR=v;
}
});
setTimeout(function(){
var ev=is._evaluateAndWrap;
is._evaluateAndWrap=function(){
var res=ev.apply(is,arguments);
console.log();
if (arguments[2]==="completion") {
//This is the path you end up when a user types in the console and autocompletion get's evaluated
//Chrome expects a wrapped result to be returned from evaluateAndWrap.
//You can use `ev` to generate an object yourself.
//In case of the autocompletion chrome exptects an wrapped object with the properties that can be autocompleted. e.g.;
//{iGetAutoCompleted: true}
//You would then go and return that object wrapped, like
//return ev.call (is, '', '({test:true})', 'completion', true, false, true);
//Would make `test` pop up for every autocompletion.
//Note that syntax as well as every Object.prototype property get's added to that list later,
//so you won't be able to exclude things like `while` from the autocompletion list,
//unless you wou'd find a way to rewrite the getCompletions function.
//
return res; //Return the autocompletion result. If you want to break that, return nothing or an empty object
} else {
//This is the path where you end up when a user actually presses enter to evaluate an expression.
//In order to return anything as normal evaluation output, you have to return a wrapped object.
//In this case, we want to return the generated remote object.
//Since this is already a wrapped object it would be converted if we directly return it. Hence,
//`return result` would actually replicate the very normal behaviour as the result is converted.
//to output what's actually in the remote object, we have to stringify it and `evaluateAndWrap` that object again.`
//This is quite interesting;
return ev.call (is, null, '(' + JSON.stringify (res) + ')', "console", true, false, true)
}
};
},0);
It's a bit verbose, but I thought I put some comments into it
So normally, if a user, for example, evaluates [1,2,3,4] you'd expect the following output:
After monkeypatching InjectedScript._evaluateAndWrap evaluating the very same expression, gives the following output:
As you see the little-left arrow, indicating output, is still there, but this time we get an object. Where the result of the expression, the array [1,2,3,4] is represented as an object with all its properties described.
I recommend trying to evaluate this and that expression, including those that generate errors. It's quite interesting.
Additionally, take a look at the is - InjectedScriptHost - object. It provides some methods to play with and get a bit of insight into the internals of the inspector.
Of course, you could intercept all that information and still return the original result to the user.
Just replace the return statement in the else path by a console.log (res) following a return res. Then you'd end up with the following.
End of Edit
This is the prior version which was fixed by Google. Hence not a possible way anymore.
One of it is hooking into Function.prototype.call
Chrome evaluates the entered expression by calling its eval function with InjectedScriptHost as thisArg
var result = evalFunction.call(object, expression);
Given this, you can listen for the thisArg of call being evaluate and get a reference to the first argument (InjectedScriptHost)
if (window.URL) {
var ish, _call = Function.prototype.call;
Function.prototype.call = function () { //Could be wrapped in a setter for _commandLineAPI, to redefine only when the user started typing.
if (arguments.length > 0 && this.name === "evaluate" && arguments [0].constructor.name === "InjectedScriptHost") { //If thisArg is the evaluate function and the arg0 is the ISH
ish = arguments[0];
ish.evaluate = function (e) { //Redefine the evaluation behaviour
throw new Error ('Rejected evaluation of: \n\'' + e.split ('\n').slice(1,-1).join ("\n") + '\'');
};
Function.prototype.call = _call; //Reset the Function.prototype.call
return _call.apply(this, arguments);
}
};
}
You could e.g. throw an error, that the evaluation was rejected.
Here is an example where the entered expression gets passed to a CoffeeScript compiler before passing it to the evaluate function.
Netflix also implements this feature
(function() {
try {
var $_console$$ = console;
Object.defineProperty(window, "console", {
get: function() {
if ($_console$$._commandLineAPI)
throw "Sorry, for security reasons, the script console is deactivated on netflix.com";
return $_console$$
},
set: function($val$$) {
$_console$$ = $val$$
}
})
} catch ($ignore$$) {
}
})();
They just override console._commandLineAPI to throw security error.
This is actually possible since Facebook was able to do it.
Well, not the actual web developer tools but the execution of Javascript in console.
See this: How does Facebook disable the browser's integrated Developer Tools?
This really wont do much though since there are other ways to bypass this type of client-side security.
When you say it is client-side, it happens outside the control of the server, so there is not much you can do about it. If you are asking why Facebook still does this, this is not really for security but to protect normal users that do not know javascript from running code (that they don't know how to read) into the console. This is common for sites that promise auto-liker service or other Facebook functionality bots after you do what they ask you to do, where in most cases, they give you a snip of javascript to run in console.
If you don't have as much users as Facebook, then I don't think there's any need to do what Facebook is doing.
Even if you disable Javascript in console, running javascript via address bar is still possible.
and if the browser disables javascript at address bar, (When you paste code to the address bar in Google Chrome, it deletes the phrase 'javascript:') pasting javascript into one of the links via inspect element is still possible.
Inspect the anchor:
Paste code in href:
Bottom line is server-side validation and security should be first, then do client-side after.
Chrome changed a lot since the times facebook could disable console...
As per March 2017 this doesn't work anymore.
Best you can do is disable some of the console functions, example:
if(!window.console) window.console = {};
var methods = ["log", "debug", "warn", "info", "dir", "dirxml", "trace", "profile"];
for(var i=0;i<methods.length;i++){
console[methods[i]] = function(){};
}
My simple way, but it can help for further variations on this subject.
List all methods and alter them to useless.
Object.getOwnPropertyNames(console).filter(function(property) {
return typeof console[property] == 'function';
}).forEach(function (verb) {
console[verb] =function(){return 'Sorry, for security reasons...';};
});
However, a better approach is to disable the developer tool from being opened in any meaningful way
(function() {
'use strict';
Object.getOwnPropertyNames(console).filter(function(property) {
return typeof console[property] == 'function';
}).forEach(function (verb) {
console[verb] =function(){return 'Sorry, for security reasons...';};
});
window.addEventListener('devtools-opened', ()=>{
// do some extra code if needed or ...
// maybe even delete the page, I still like to add redirect just in case
window.location.href+="#";
window.document.head.innerHTML="";
window.document.body.innerHTML="devtools, page is now cleared";
});
window.addEventListener('devtools-closed', ()=>{
// do some extra code if needed
});
let verifyConsole = () => {
var before = new Date().getTime();
debugger;
var after = new Date().getTime();
if (after - before > 100) { // user had to resume the script manually via opened dev tools
window.dispatchEvent(new Event('devtools-opened'));
}else{
window.dispatchEvent(new Event('devtools-closed'));
}
setTimeout(verifyConsole, 100);
}
verifyConsole();
})();
Internally devtools injects an IIFE named getCompletions into the page, called when a key is pressed inside the Devtools console.
Looking at the source of that function, it uses a few global functions which can be overwritten.
By using the Error constructor it's possible to get the call stack, which will include getCompletions when called by Devtools.
Example:
const disableDevtools = callback => {
const original = Object.getPrototypeOf;
Object.getPrototypeOf = (...args) => {
if (Error().stack.includes("getCompletions")) callback();
return original(...args);
};
};
disableDevtools(() => {
console.error("devtools has been disabled");
while (1);
});
an simple solution!
setInterval(()=>console.clear(),1500);
I have a simple way here:
window.console = function () {}
I would go along the way of:
Object.defineProperty(window, 'console', {
get: function() {
},
set: function() {
}
});
In Firefox it dosen't do that, since Firefox is a developer browser, I think since the command WEBGL_debug_renderer_info is deprecated in Firefox and will be removed. Please use RENDERER and the error Referrer Policy: Less restricted policies, including ‘no-referrer-when-downgrade’, ‘origin-when-cross-origin’ and ‘unsafe-url’, will be ignored soon for the cross-site request: https://static.xx.fbcdn.net/rsrc.php/v3/yS/r/XDDAHSZfaR6.js?_nc_x=Ij3Wp8lg5Kz.
This is not a security measure for weak code to be left unattended. Always get a permanent solution to weak code and secure your websites properly before implementing this strategy
The best tool by far according to my knowledge would be to add multiple javascript files that simply changes the integrity of the page back to normal by refreshing or replacing content. Disabling this developer tool would not be the greatest idea since bypassing is always in question since the code is part of the browser and not a server rendering, thus it could be cracked.
Should you have js file one checking for <element> changes on important elements and js file two and js file three checking that this file exists per period you will have full integrity restore on the page within the period.
Lets take an example of the 4 files and show you what I mean.
index.html
<!DOCTYPE html>
<html>
<head id="mainhead">
<script src="ks.js" id="ksjs"></script>
<script src="mainfile.js" id="mainjs"></script>
<link rel="stylesheet" href="style.css" id="style">
<meta id="meta1" name="description" content="Proper mitigation against script kiddies via Javascript" >
</head>
<body>
<h1 id="heading" name="dontdel" value="2">Delete this from console and it will refresh. If you change the name attribute in this it will also refresh. This is mitigating an attack on attribute change via console to exploit vulnerabilities. You can even try and change the value attribute from 2 to anything you like. If This script says it is 2 it should be 2 or it will refresh. </h1>
<h3>Deleting this wont refresh the page due to it having no integrity check on it</h3>
<p>You can also add this type of error checking on meta tags and add one script out of the head tag to check for changes in the head tag. You can add many js files to ensure an attacker cannot delete all in the second it takes to refresh. Be creative and make this your own as your website needs it.
</p>
<p>This is not the end of it since we can still enter any tag to load anything from everywhere (Dependent on headers etc) but we want to prevent the important ones like an override in meta tags that load headers. The console is designed to edit html but that could add potential html that is dangerous. You should not be able to enter any meta tags into this document unless it is as specified by the ks.js file as permissable. <br>This is not only possible with meta tags but you can do this for important tags like input and script. This is not a replacement for headers!!! Add your headers aswell and protect them with this method.</p>
</body>
<script src="ps.js" id="psjs"></script>
</html>
mainfile.js
setInterval(function() {
// check for existence of other scripts. This part will go in all other files to check for this file aswell.
var ksExists = document.getElementById("ksjs");
if(ksExists) {
}else{ location.reload();};
var psExists = document.getElementById("psjs");
if(psExists) {
}else{ location.reload();};
var styleExists = document.getElementById("style");
if(styleExists) {
}else{ location.reload();};
}, 1 * 1000); // 1 * 1000 milsec
ps.js
/*This script checks if mainjs exists as an element. If main js is not existent as an id in the html file reload!You can add this to all js files to ensure that your page integrity is perfect every second. If the page integrity is bad it reloads the page automatically and the process is restarted. This will blind an attacker as he has one second to disable every javascript file in your system which is impossible.
*/
setInterval(function() {
// check for existence of other scripts. This part will go in all other files to check for this file aswell.
var mainExists = document.getElementById("mainjs");
if(mainExists) {
}else{ location.reload();};
//check that heading with id exists and name tag is dontdel.
var headingExists = document.getElementById("heading");
if(headingExists) {
}else{ location.reload();};
var integrityHeading = headingExists.getAttribute('name');
if(integrityHeading == 'dontdel') {
}else{ location.reload();};
var integrity2Heading = headingExists.getAttribute('value');
if(integrity2Heading == '2') {
}else{ location.reload();};
//check that all meta tags stay there
var meta1Exists = document.getElementById("meta1");
if(meta1Exists) {
}else{ location.reload();};
var headExists = document.getElementById("mainhead");
if(headExists) {
}else{ location.reload();};
}, 1 * 1000); // 1 * 1000 milsec
ks.js
/*This script checks if mainjs exists as an element. If main js is not existent as an id in the html file reload! You can add this to all js files to ensure that your page integrity is perfect every second. If the page integrity is bad it reloads the page automatically and the process is restarted. This will blind an attacker as he has one second to disable every javascript file in your system which is impossible.
*/
setInterval(function() {
// check for existence of other scripts. This part will go in all other files to check for this file aswell.
var mainExists = document.getElementById("mainjs");
if(mainExists) {
}else{ location.reload();};
//Check meta tag 1 for content changes. meta1 will always be 0. This you do for each meta on the page to ensure content credibility. No one will change a meta and get away with it. Addition of a meta in spot 10, say a meta after the id="meta10" should also be covered as below.
var x = document.getElementsByTagName("meta")[0];
var p = x.getAttribute("name");
var s = x.getAttribute("content");
if (p != 'description') {
location.reload();
}
if ( s != 'Proper mitigation against script kiddies via Javascript') {
location.reload();
}
// This will prevent a meta tag after this meta tag # id="meta1". This prevents new meta tags from being added to your pages. This can be used for scripts or any tag you feel is needed to do integrity check on like inputs and scripts. (Yet again. It is not a replacement for headers to be added. Add your headers aswell!)
var lastMeta = document.getElementsByTagName("meta")[1];
if (lastMeta) {
location.reload();
}
}, 1 * 1000); // 1 * 1000 milsec
style.css
Now this is just to show it works on all files and tags aswell
#heading {
background-color:red;
}
If you put all these files together and build the example you will see the function of this measure. This will prevent some unforseen injections should you implement it correctly on all important elements in your index file especially when working with PHP.
Why I chose reload instead of change back to normal value per attribute is the fact that some attackers could have another part of the website already configured and ready and it lessens code amount. The reload will remove all the attacker's hard work and he will probably go play somewhere easier.
Another note: This could become a lot of code so keep it clean and make sure to add definitions to where they belong to make edits easy in future. Also set the seconds to your preferred amount as 1 second intervals on large pages could have drastic effects on older computers your visitors might be using

WebView hides soft keyboard during loadUrl(), which means a keyboard cannot stay open while calling javascript

Since the way you call javascript on a WebView is through loadUrl("javascript: ... "); The keyboard cannot stay open.
The loadUrl() method calls loadUrlImpl() , which calls a method called clearHelpers() which then calls clearTextEntry(), which then calls hideSoftKeyboard() and then we become oh so lonely as the keyboard goes away.
As far as I can see all of those are private and cannot be overridden.
Has anyone found a workaround for this? Is there a way to force the keyboard to stay open or to call the javascript directly without going through loadUrl()?
Is there anyway to override the WebView in a way to prevent (the private method) clearTextEntry() from being called?
Update
KitKat added a public method for invoking javascript directly: evaluateJavascript()
For older apis, you could try a solution like below, but if I had to do this again I'd look at just building an compatibility method that on KitKat uses the above method and on older devices, uses reflection to drill down to a inner private method: BrowserFrame.stringByEvaluatingJavaScriptFromString()
Then you could call javascript directly without having to deal with loadUrl and adding "javascript: " to the script.
Old Answer
As requested by Alok Kulkarni, I'll give a rough overview of a possible workaround I thought of for this. I haven't actually tried it but in theory it should work. This code is going to be rough and is just to serve as an example.
Instead of sending the calls down through loadUrl(), you queue your javascript calls and then have javascript pull them down. Some thing like:
private final Object LOCK = new Object();
private StringBuilder mPendingJS;
public void execJS(String js) {
synchronized(LOCK) {
if (mPendingJS == null) {
mPendingJS = new StringBuilder();
mPendingJS.append("javascript: ");
}
mPendingJS
.append(js)
.append("; ");
}
}
Instead of calling loadUrl() call that method. (For making this simple I used a synchronized block, but this might be better suited to a different route. Since javascript runs on its own thread, this will need to be thread safe in some way or another).
Then your WebView would have an interface like this:
public class JSInterface {
public String getPendingJS() {
synchronized(LOCK) {
String pendingCommands = mPendingJS.toString();
mPendingJS.setLength(0);
mPendingJS.append("javascript: ");
return pendingCommands;
}
}
}
That returns a String with the pending commands and clears them so they don't get returned again.
You would add it to the WebView like this:
mWebView.addJavascriptInterface(new JSInterface(), "JSInterface");
Then in your javascript you would set some interval in which to flush the pending commands. On each interval it would call JSInterface.getPendingJS() which would return a String of all of the pending commands and then you could execute them.
You could further improve this by adding a check in the execJS method to see if a EditText field exists in the WebView and is in focus. If there is one, then you would use this queueing method, but if there wasn't one in focus then you could just call loadUrl() like normal. That way it only uses this workaround when it actually needs to.
Regarding older APIs (pre 19), I used a similar method to the excepted answer, but slightly different.
First, I keep track of if the keyboard is displayed by using javascript in the webview roughly like so:
document.addEventListener( "focus", function(e){
var el = e.target;
reportKeyboardDisplayedToJava( isInputElement( el ) );
}, true);
document.addEventListener( "blur", function(e){
reportKeyboardDisplayedToJava( false );
}, true);
If the keyboard is displayed, and a js injection is attempted by the Android Java layer – I “defer” that injection. I add it to a string list, allow the user to finish up their input, and then upon the keyboard disappearing, I detect that and execute the backlog of injections.
I could implement cottonBallPaws's idea to use the internals of WebView with reflection, and got it to work for my 4.2 device. There are gracious fallbacks for Android versions older than KitKat.
The code is written in Xamarin, but it should be easily adaptable to native Java code.
/// <summary>
/// Executes a JavaScript on an Android WebView. This method offers fallbacks for older
/// Android versions, to avoid closing of the soft keyboard when executing JavaScript.
/// </summary>
/// <param name="webView">The WebView to run the JavaScript.</param>
/// <param name="script">The JavaScript code.</param>
private static void ExecuteJavaScript(Android.Webkit.WebView webView, string script)
{
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
{
// Best way for Android level 19 and above
webView.EvaluateJavascript(script, null);
}
else
{
try
{
// Try to do with reflection
CompatExecuteJavaScript(webView, script);
}
catch (Exception)
{
// Fallback to old way, which closes any open soft keyboard
webView.LoadUrl("javascript:" + script);
}
}
}
private static void CompatExecuteJavaScript(Android.Webkit.WebView androidWebView, string script)
{
Java.Lang.Class webViewClass = Java.Lang.Class.FromType(typeof(Android.Webkit.WebView));
Java.Lang.Reflect.Field providerField = webViewClass.GetDeclaredField("mProvider");
providerField.Accessible = true;
Java.Lang.Object webViewProvider = providerField.Get(androidWebView);
Java.Lang.Reflect.Field webViewCoreField = webViewProvider.Class.GetDeclaredField("mWebViewCore");
webViewCoreField.Accessible = true;
Java.Lang.Object mWebViewCore = webViewCoreField.Get(webViewProvider);
Java.Lang.Reflect.Method sendMessageMethod = mWebViewCore.Class.GetDeclaredMethod(
"sendMessage", Java.Lang.Class.FromType(typeof(Message)));
sendMessageMethod.Accessible = true;
Java.Lang.String javaScript = new Java.Lang.String(script);
Message javaScriptCodeMsg = Message.Obtain(null, 194, javaScript);
sendMessageMethod.Invoke(mWebViewCore, javaScriptCodeMsg);
}

Monitor ajax calls from IE BHO

I'm trying to find a way to detect changes on a page from a BHO. For the Firefox version of the plugin I'm using DomNodeInserted, but this isn't available in IE. I've also looked at using onpropertychange, but this only allows you to monitor a single element (not children).
I'm now wondering if it's possible to monitor when AJAX requests are called. If so, I can make the changes to the page after the AJAX request has completed. Only problem is, I can't find a way to do it.
Here's my attempt so far, based on jeffamaphone's suggestions, it doesn't work but maybe it'll jog someone's memory.
public class ChangeMonitor : IHTMLChangeSink {
public void Notify()
{
Trace.WriteLine("notified");
}
}
void registerMonitor()
{
HTMLDocument document = _webBrowser2.Document;
ChangeMonitor monitor = new ChangeMonitor();
IHTMLChangeSink changeSink = monitor;
IHTMLChangeLog changeLog = null;
((IMarkupContainer2)document).CreateChangeLog(changeSink, out changeLog, 1, 1);
}
For IE, onreadystatechange will work as an equivalent to DomNodeInserted. A DHTML behavior must be attached to the element via htc, but the htc file does not have to exist:
document.documentElement.addBehavior("foo.htc");
document.documentElement.attachEvent("onreadystatechange", Notify);
The BHO can inject the script to handle the event.
I've never done it, but my theory is you can use IMarkupContainer2::CreateChangeLog().

Categories