evaluateJavaScript in a WKWebView's iframe? - javascript

I have successfully set up a WKWebView ScriptMessageHandler to receive messages from inside my webview. I'm then using evaluateJavaScript to send responses back into the webview. This works fine when everything is executed on the main frame of the view.
However, when I try to do this inside an iFrame I run into difficulties. I still receive the message in the message handler (complete with WKFrameInfo to tell me where it came from) but I can't find any way to run evalateJavaScript targeting that frame. I could use a window.frames hack in my evaluated JavaScript, but if the iFrame is of a different origin than the parent frame then I'm going to run into cross-domain errors.
Is there any way to identify a frame inside WKWebview, and evaluate JS on it?

Three years later: iOS 14 will support this.
https://developer.apple.com/documentation/webkit/wkwebview/3656442-evaluatejavascript

Related

Cross-origin security error when moving an application to a subdomain (2018)

Background information: We have a platform which runs on https://system.example.com. This platform consists of 10 separate web applications (all written in PHP and JS). Each application has historically been in a sub-directory within the same subdomain:
https://system.example.com/app1/
https://system.example.com/app2/
...
https://system.example.com/app10/
We are in the process of rebuilding one of the applications, app2, and have decided to host this on a new separate subdomain, https://app2.example.com.
Part of the app2 application uses JavaScript to open a pop-up window for app10. Most functionality inside this popup works as expected. However, when attempting to use a "Save" button inside the popup my browser console was showing:
Uncaught DOMException: Blocked a frame with origin "https://app2.example.com" from accessing a cross-origin frame.
at https://system.example.com/app10/manage.php:1:334
I have read both SecurityError: Blocked a frame with origin from accessing a cross-origin frame and https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage but still unclear as to how to fix this.
The code and process I have is as follows:
The popup is opened from https://app2.example.com by a button which has an onclick event handler:
<button onclick="postToPopUp('https://system.example.com/app10/manage.php', 'fileManage', 'width=800px,height=600px', ['f_id', '123'], 'app2', 'filesCallbackManage')">Open app10</button>
The postToPopup() function is used to pass POST data from app2 into https://system.example.com/app10/manage.php based on Javascript window.open pass values using POST - this works fine.
The problem occurs when I click a "Save" button inside the popup which renders the following markup within the popup window:
<!doctype HTML><html><head><title>upload</title>
<script type="text/javascript" language="javascript" charset="utf-8">
var fileObject = {"files":{"0":{"f_id":"1784","f_title":"test07.pdf"},"f_id":123}};
window.opener.filesCallbackManage(fileObject);
window.close();
</script><body></body></html>
What this did originally - when everything was under the same subdomain - was called a js function filesCallbackManage() which resided in the code for https://system.example.com/app2. The function itself was passed an object, fileObject, which updated various parts of the UI inside app2. The popup was closed after clicking the Save button due to window.close();
Although I've read about using postMessage I don't understand how this fits in or whether this is even the correct solution to my problem? The data is being posted from the subdomain https://app2.example.com to https://system.example.com/app10 correctly. The problem is that filesCallbackManage() won't fire because of the cross origin restriction. Inside my code for https://app2.example.com I have a simple statement to see if it's firing:
function filesCallbackManage(data)
{
console.log('filesCallbackManage has fired');
}
This never fires because of the problem I have. I get the console error mentioned previously and a blank popup window (technically this is correct since there is nothing in the <body> tag in the above markup) but the window doesn't close and the callback isn't fired.
The example given on the Mozilla website isn't extensive enough to understand how it can be adapted to this type of scenario. Please can someone elaborate? Furthermore, the linked Stack Overflow post is four years old so I want to be sure anything I put on this is secure and up-to-date.
The postToPopup() function is used to pass POST data
Submitting a form across origins is fine. So you can do this.
The problem occurs when I click a "Save" button inside the popup
You're trying to access the DOM of the window across origins. This is forbidden.
Although I've read about using postMessage I don't understand how this fits in or whether this is even the correct solution to my problem?
postMessage is as close as you can get to accessing the DOM of a window across origins.
You can't do this.
var fileObject = {"files":{"0":{"f_id":"1784","f_title":"test07.pdf"},"f_id":123}};
window.opener.filesCallbackManage(fileObject);
Instead you have to send a message:
window.opener.postMessage(fileObject, "https://system.example.com");
And have code which listens for it:
addEventListener("message", receiveMessage);
function receiveMessage(event) {
if (event.origin !== "http://app2.example.com") { return false; }
filesCallbackManage(event.data);
}

Js - Capturing a 400 error event that appears in console

I'm creating a chrome extension for Facebook that runs a script in the page.
Facebook in its normal operation sometimes shows the following message in the Chrome console (with red):
kZLAjcLHBWC.js:26 GET https://www.facebook.com/ufi/reaction/profile/browser/fetch/?limit=50&shown…=o&__req=9w&__be=-1&__pc=PHASED%3ADEFAULT&__rev=2661965&__srp_t=1478186873 400 ()
I want to create any js function that will determine when this event is happening (the 400 GET error).
It's going to be challenging to catch from a content script; since it's not a JS error that bubbles up, it has to be caught in the page's own code, and there are barriers to that. They can be overcome, but then you're operating in the possibly hostile environment of the page's code.
An alternative is to use webRequest API, specifically chrome.webRequest.onErrorOccurred event. This will allow you to detect errors on specific requests.
However, this can't be done from a content script. You'd need a background script that messages the content script when the event happens.

Access javascript method inside different domain iframe

I am looking for the way to call the javascript method inside with a different domain iframe.
For example, app.facebook.com contains iframe yyy.com inside.
I would like to call the yyyMethod() inside iframe yyy.com.
app.facebook.com
|__iframe src="yyy.com" name="yyy"
|__yyyMethod();
I tried window.frames["yyy"].contentWindow.yyyMethod(), but it return exception saying that we could not call method across domain.
Restrictions are
1) Adding/Modifying content in both app.facebook.com and yyy.com are prohibited, since I am not the site owner.
2) Execute from browser javascript console is one way to do, but I want to write plug the yyyMethod() caller with some javascipt code. Therefore, execute from browser javascript console may not be a good idea.
Any idea how to do this ? Not sure whether we can call from the chrome extension, bookmarklet, or something else ??

HTML5 - Cross Browser Iframe postmessage - parent to child communication

I wrote a content script that injects an iframe to any website (therefore different domain).
I need the parent website to send some information to the child iframe, however I couldn't find a way to do it.
The code
var targetFrame = $('#myIframe')[0];
targetFrame.contentWindow.postMessage('the message', '*');
Doesn't work somehow and i get a Cannot call method 'postMessage' of undefined error.
But then when I tried the same code directly in Chrome's console, it worked.
I had no trouble sending a postMessage from the child to the parent though but just need a way for the parent to send messages to the child iframe.
I recently wrote code that did postMessage to an iframe and I encountered quite a similar issue where it said contentWindow is undefined.
In my case, my iframe was not yet part of the DOM tree, it was a variable created by document.createElement('iframe').
Once I put it hidden (width and height 0px, visibility hidden) into the body of the page, contentWindow was no longer undefined and everything worked as expected.
I found the Mozilla Developer Network page for postMessage extremely useful when I was working on my project.
I've had success using the following library:
http://easyxdm.net/wp/
It doesn't require any flash/silverlight, only javascript. And it is compatible as far back as as IE6.
It took a little doing to get it up and running, but once it was things ran very smoothly.
Keep in mind that if the iFrame you're opening on the other domain uses a different protocol (HTTP vs. HTTPS) the browser will kick out a warning which prevents your script from running (unless the user says they will accept the risk). If you have access to both protocols it may be wise to host the contents of the iFrame on both HTTP and HTTPS and load the appropriate script accordingly.
Good luck!
You don't need to target contentWindow. Try this:
var targetFrame = $('#myIframe')[0];
targetFrame.postMessage('the message', '*');

JS security issue with Opera 11.01, after moving from server A to B

I have a outer HTML-document (subdomain1.server-a.de) with an iFrame and inner HTML-document (subdomain2.server-a.de). The inner script should send & receive AJAX-requests to subdomain2.server-a.de. I've set the document.domain-value for both documents to "server-a.de" - so far, so good, works well in all tested browsers (FF/Chrome/Opera). Now I move the scripts to server-b.de with same subdomains and set the document.domain on both documents to "server-b.de". That still works in FF and Chrome, but Opera gives me a "Security error: attempted to read protected variable: xy" when trying to call my AJAX function from the outer document.
My conclusion so far: I can't violate the same domain policy, because then FF and Chrome wouldn't communicate with the inner document from outside either. I've also tried the solution from Focus with Cross-domain Ajax in Opera with the interval function, same issue.
Thanks a lot in advance for every hint.
UPDATE: I have set up a testing site for this. If you go to this site, you'll see, it works even with Opera (a dialog pops up with "Test called" after a few seconds). Now, if you copy the outer frame files "operatest.html" and jquery to another server - so it has to work in my case - you'll see, that FF and Chrome don't have a problem, but Opera has.
Is Opera comparing server details in order to fulfill the same origin policy? Or will it deny access, if ip adresses of both subdomains don't match?
Sounds like it might be a timing issue, i.e. the outer document tries to initiate the request before the inner document has run the script that sets document.domain?? Or perhaps Opera has cached the IFRAME contents and you initially loaded a version where the script inside the IFRAME was wrong and didn't set document.domain correctly?
I suggest you forget the document.domain approach and use window.postMessage() (AKA HTML5-style cross-document messaging) instead.
http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#web-messaging
Had the same absurd issue with JS calls between parent and an iframe on a different subdomain - worked everywhere, but failed under Opera with the above mentioned error.
Removing ~/.opera folder (Opera settings folder in Linux) solved this, and another one very weird problem.
Cheers.

Categories

Resources