MonoTouch - Can I call ShouldStartLoad with AJAX? - javascript

first of all, I want to thank miguel.de.icaza for this answer! Helped us a lot! But - here's the big BUT, here's our problem. In the UIWebView we start a "little" javascript App, created with SenchaTouch, that displays some charts. To give it a little look and feel, there's some interaction with the graphs. And sometime, we need to get some more data from the backend (e.g. for different chart types) using an AJAX request. But since the backend is saved with an self signed certificate, which doesn't work with the webView, as we know.
So, what we try to accieve is an AJAX request from our JS-app to the MonoTouch-App code, so that the Mono-app gets the data for the webview and passes it to a Javascript function, that updates the charts with the new data.
But as of right now, we're not able to get this to work, because as soon as we call the location.href = "app://get/chartData" we're logging a "about:blank" request, right before the "app://get/chartData" request, that - of course - blanks the webview and the current chart is gone. Using an simple AJAX request doesn't work for any reason. Meaning, the AJAX request doesn't call the ShouldLoadStart callback. Maybe, someone knows why?
Here's our MonoTouch code so far. This was just for testing the general workflow!! ;-)
NSUrl fileUrl = NSUrl.FromFilename("index.html");
NSUrlRequest req = new NSUrlRequest(fileUrl);
this.KPIWebView.LoadRequest(req);
this.KPIWebView.ShouldStartLoad = myHandler;
this.KPIWebView.LoadFinished += delegate {
indicator.StopAnimating ();
this.KPIWebView.Hidden = false;
};
bool myHandler(UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navType)
{
Console.WriteLine(request.Url.ToString());
if(request.Url.ToString() == "about:blank")
{return false;} // doesn't help to avoid loading the "about:blank"
if(request.Url.ToString() == "ttl://data/salesGrowth/global")
{
string strData = Connection.Login("http://[yourIP/path]/salesGrowth/global");
return false;
try{
this.KPIWebView.EvaluateJavascript("Util.loadStoreData("+strData+")");
return false;
}
catch(Exception ex)
{ Console.WriteLine(ex.ToString()); }
return true;
} }
Any comments, ideas and help is greatly appreciated.
Thanks!
Edit:
After some more googleling I found out, that the thing with the about:blank request is a known issue with Senach Touch http://www.sencha.com/forum/showthread.php?123284-What-s-up-with-the-about-blank-page.
Finally, we were able getting it to run by using our own url schema: location.href = "app://action?jsCallback=MonoCallback&jsErrorCallback=ErrorCallback&paramName1=name1&paramVal1=value1&..."
In the webview.ShouldStartLoad callback, we're using the System.Uri namespace to check for the app protocol and to get all the parameters and javascript callback function names. Now we can do our request from within the mono-app. After all the action, we can call the jsCallback function with webview.EvaluateJavascript(jsCallback+"("+strValues+")");So, everything works fine now, even asynchronous!
Hope some of you, struggeling the same workflow issue with a self signed certificate within the webview, find this description helpful. If you have more questions about our "workaround" feel free to contact me.
Thanks!

Related

Best (and secure) way to call javascript function (with arguments) using a url from another page

After reviewing dozens of Stack Overflow posts, I'm thoroughly confused. What I am trying to do is create a URL through an tag on one page that would open another webpage and run a function that requires two arguments. I thought this would be simple but I keep seeing references to "cross site scripting vulnerabilities" and I am not familiar with this potential security problem and feel like I am now playing with fire. I do not want to utilize something — even if the code works — if it opens up security risks. Could someone point me in the right direction with the correct (and most secure) way to do this? I can do my research (and learning) from there. Much appreciated.
For example you can append some parameter at the end of your URL
https://your-url/?parameter=hello
When this URL is opened on another webpage you can run JavaScript or a PHP function based on that URL query.
For JavaScript
getUrlParam(slug) {
let url = new URL(window.location);
let params = new URLSearchParams(url.search);
let param = params.get(slug);
if (param) {
return param;
} else {
return false;
}
}
console.log(getUrlParam('parameter'));
After that, you can run this function to check if any parameter is passed in that URL or not.
If this function returns that's given slug parameter you can run your custom code inside that if condition block

Redirecting XMLHTTP request - Javascript

I have a web page that has a too much content and javascript. When the page loads it makes multiple requests using Ajax and XMLHttp to load data. Is there a way to hook up all these requests and direct them to a different server.
For example the webpage fetches data from www.apple.com/data and www.mango.com/data after it is loaded. Is is possible to insert a script somewhere in the webpage which automatically changes any request made to www.orange.com/data.
Waiting for answer. Thanks
You can add a global handler to the ajaxSend event, the event will be triggered right before the ajax request being sent out. So you can check the request uri, apply some filtering logic, and then redirect the request by abort the original and resend it.
Below is an example
$(document).ajaxSend(function(e, xhr, opt) {
if (opt.url.indexOf("www.apple.com") !== -1) {
// abort the request
xhr.abort();
// change the uri to www.orange.com
opt.url = opt.url.replace("www.apple.com", "www.orange.com");
$.ajax(opt);
}
});
Ok. So I followed Anthony C's answer and it did actually work. But the problem with his solution is that it only works with Ajax requests not XMLHttpRequests (I am not sure why, I am a beginner at this topic.) However digging on his idea of creating a hook I came across a similar post here How to get the URL of a xmlhttp request (AJAX). The code provided a way to fetch the requested URL for each request. So by a little tweak to the code I managed to come up with this:-
XMLHttpRequest.prototype.open = (function(open) {
return function(method,url,async) {
var uri=getLocation(url);// use get location function to convert requested url string into readable url
if(uri.hostname!="orange.com"){
url="https://orange.com" + url;
}
open.apply(this,arguments);
};
})(XMLHttpRequest.prototype.open);
var getLocation = function(href) {
var l = document.createElement("a");
l.href = href;
return l;
};
This code at top of the page allows me to change the host name of all XMLHttpRequests that are not directed towards orange.com. Though I am sure there are better ways to write this code as well but since I am not an expert over javascript this will suffice my need for the time.

How to Handle redirects in Node.JS with HorsemanJs and PhantomJS

I´ve recently started using horseman.js to scrap a page with node. I can´t figure out how exactly it works and I can´t find good examples on the internet.
My main goal is to log on a platform and extract some data. I´ve managed to do this with PhantomJS, but know I want to learn how to do it with horseman.JS.
My code should open the login page, fill the login and password inputs and click on the "login" button. Pretty easy so far. However, after clicking on the "login" button the site makes 2 redirects before loading the actual page where I want to work.
My problem is that I don´t know how to make my code wait for that page.
With phantomJS I had a workaround with the page URL. The following code shows how I´ve managed to do it with phantomJS and it works just fine:
var page = require('webpage').create();
var urlHome = 'http://akna.com.br/site/montatela.php?t=acesse&header=n&footer=n';
var fillLoginInfo = function(){
$('#cmpLogin').val('mylogin');
$('#cmpSenha').val('mypassword');
$('.btn.btn-default').click();
};
page.onLoadFinished = function(){
var url = page.url;
console.log("Page Loaded: " + url);
if(url == urlHome){
page.evaluate(fillLoginInfo);
return;
}
// After the redirects the url has a "sid" parameter, I wait for that to apear when the page loads.
else if(url.indexOf("sid=") >0){
//Keep struggling with more codes!
return;
}
}
page.open(urlHome);
However, I can´t find a way to handle the redirects with horseman.JS.
Here is what I´ve been trying with horseman.JS without any success:
var Horseman = require("node-horseman");
var horseman = new Horseman();
var urlHome = 'http://akna.com.br/site/montatela.php?t=acesse&header=n&footer=n';
var fillLoginInfo = function(){
$('#cmpLogin').val('myemail');
$('#cmpSenha').val('mypassword');
$('.btn.btn-default').click();
}
var okStatus = function(){
return horseman.status();
}
horseman
.open(urlHome)
.type('input[name="cmpLogin"]','myemail')
.type('input[name="cmpSenha"]','mypassword')
.click('.btn-success')
.waitFor(okStatus, 200)
.screenshot('image.png')
.close();
How do I handle the redirects?
I'm currently solving the same problem, and my best solution so far is to use the waitForSelector method to target something on the final page.
E.g.
horseman
.open(urlHome)
.type('input[name="cmpLogin"]','myemail')
.type('input[name="cmpSenha"]','mypassword')
.click('.btn-success')
.waitForSelector("#loginComplete")
.screenshot('image.png')
.close();
Of course you have to know the page you're waiting for to do this.
If you know there are two redirects, you can use the approach of .waitForNextPage() twice. A naive approach if you didn't know how many redirects to expect would be to chain these until a timeout is reached (I don't recommend this as it will be slow!),
Perhaps a cleverer way, you can also use on events to capture redirects, like .on('navigationRequested') or .on('urlChanged').
Although it doesn't answer your question directly, this link may help: https://github.com/ariya/phantomjs/issues/11507

Is it possible for the admin to get the full sourcecode of my js-file if I redirect a Javascript file to a local modified Javascript file?

I created a google-chrome-extension which redirects all requests of a javascript-file on a website to a modified version of this file which is on my harddrive.
It works and I do it simplified like this:
... redirectUrl: chrome.extension.getURL("modified.js") ...
Modified.js is the same javascript file except that I modified a line in the code.
I changed something that looks like
var message = mytext.value;
to var message = aes.encrypt(mytext.value,"mysecretkey");
My question is now is it possible for the admin of this website where I redirect the javascript-file to modify his webpage that he can obtain "mysecretkey". (The admin knows how my extension works and which line is modified but doesn't know the used key)
Thanks in advance
Yes, the "admin" can read the source code of your code.
Your method is very insecure. There are two ways to read "mysecretkey".
Let's start with the non-trivial one: Get a reference to the source. Examples, assume that your aes.encrypt method looks like this:
(function() {
var aes = {encrypt: function(val, key) {
if (key.indexOf('whatever')) {/* ... */}
}};
})();
Then it can be compromised using:
(function(indexOf) {
String.prototype.indexOf = function(term) {
if (term !== 'known') (new Image).src = '/report.php?t=' + term;
return indexOf.apply(this, arguments);
};
})(String.prototype.indexOf);
Many prototype methods result in possible leaking, as well as arguments.callee. If the "admin" wants to break your code, he'll surely be able to achieve this.
The other method is much easier to implement:
var x = new XMLHttpRequest();
x.open('GET', '/possiblymodified.js');
x.onload = function() {
console.log(x.responseText); // Full source code here....
};
x.send();
You could replace the XMLHttpRequest method, but at this point, you're just playing the cat and mouse game. Whenever you think that you've secured your code, the other will find a way to break it (for instance, using the first described method).
Since the admin can control any aspect of the site, they could easily modify aes.encrypt to post the second argument to them and then continue as normal. Therefore your secret key would be immediately revealed.
No. The Web administrator would have no way of seeing what you set it to before it could get sent to the server where he could see it.

why is javascript-function just executed if an alert() is put at the beginning?

var callback = function(result){
//alert(result);
var json = eval('('+result+')');
if(json.criticalerror==true) dialogCriticalError(json.errormessage);
else{
if(json.error==true) dialogError(json.errormessage);
else{
// Do something else
}
}
};
When this callback-function is executed the "Do something else" part is called without problems. But in the case the json.error is true the dialogError-function is not executed. I've checked the transmitted JSON in Firebug. Everything is ok. The result is a JSON string as it should be.
The interesting thing is, that it actually is executed if i call the JSON-response with an alert() function at the beginning of the callback function. I'm new to JavaScript and probably missing something obvious but i just can't figure it out. Where's the bug?
EDIT:
It seems the problem is the time. If i put a 100ms delay between the JSON-result and the actual callback, everything works perfectly. But this can't be right... I'm kind of clueless.
(Oh and by the way: the communication is done by JBoss Seam Remoting)
The whole function looks like that:
function nextNode() {
var callback = function(result){
var json = JSON.parse(result);
if (json.criticalerror==true) {
dialogCriticalError(json.errormessage);
}else if (json.error==true) {
dialogError(json.errormessage);
}else {
document.getElementById('currentTree').innerHTML = json.state;
document.getElementById('countTrees').innerHTML = json.amountSteps;
document.getElementById('iframe').contentWindow.importGraph(json.tree);
document.getElementById('relevantnode').innerHTML = json.node;
createNodeBar(json);
}
};
manager.nextNode(callback);
}
The manager object is provided by the Seam Framework through the following function:
var manager = Seam.Component.getInstance("solverTreeStructure");
LAST EDIT:
Okay now i got the definite source of the problem. Its not not the Seam Remoting but the dialogError() function and the library it uses to display the dialog.
The dialogError() function looks like that:
function dialogError(error){
TINY.box.show({html:error,width:250,height:100,close:true,mask:true,opacity:20,topsplit:3})
}
It uses a small dialog library called TINYBOX. Now this library offers a variety of parameters to configure the dialog boxes. The 'mask' parameter caused all the trouble. It is resposible for darkening the background of the dialog box. If its turned on, TINYBOX needs a start-delay in order to work with the callback function. (i have NO idea why)
But for those who like riddles:
Thats the library. Its very small and clear. Unfortunately my JavaScript skills are not yet sophisticated enough to understand it.
http://www.scriptiny.com/2011/03/javascript-modal-windows/
Thats the answer. Have a nice day folks! ;)
Just a general advice: do not mix blocks with and without {}. The following form is much more readable and you can pinpoint your problem quicker.
console.log(json);
if (json.criticalerror == true) {
console.log("criticalerror");
dialogCriticalError(json.errormessage);
} else if (json.error == true) {
console.log("error");
dialogError(json.errormessage);
} else {
console.log("something else");
// Do something else
}
It seems the problem is the time. If i
put a 100ms delay between the
JSON-result and the actual callback,
everything works perfectly. But this
can't be right... I'm kind of
clueless.
Sounds like your doing asynchronous (ajax) communication. WHere is the rest of your code that asks the server for some data. Your handling the result before the server gives it to you. This explains the delay.

Categories

Resources