Accessing iframe context with Electron - javascript

I have an Electron app where I load external sites into a BrowswerView hosted in a BrowserWindow. Invariably each site has a video player on it using a <video> tag. Normally you can access the DOM using executeJavaScript and do things like this:
document.querySelectorAll('video').forEach(input => { input.pause() })
This would pause all the playing video on the site.
Problem is, one particular pesky site loads the video player into an iframe that is in a different sub domain.
Enter CORS. I cannot get to the video container without hitting the dreaded Blocked a frame with origin "https://www.whatever.com" from accessing a cross-origin frame.
Here is my question: In the chrome dev tools you can select the context from a drop down so clearly it is possible to choose the context from the client. As I am running this in Electron I would like to believe that there is a way to switch contexts. I am not looking to run the code cross origin but directly in the frame I just need a way to choose it.
I looked at mainFrame.frames but I don't see how you get to the sub frame's webContents.
Any clues on this?

I basically rubber ducky'd this thing. After typing this up, I figured it out.
I looked at the instance methods again and saw that executeJavascript is one of them so I don't need to get to webContents at all...
So this works and I thought I would share:
view.webContents.mainFrame.frames.forEach(frame => {
const url = new URL(frame.url)
if (url.host === 'sub.whatever.com') {
frame.executeJavaScript('myCodeHere')
}
})
I used the host name in my instance but you could use frame.processId instead.

Related

Cannot get reference to one page from another

I am working on a web app that needs to have two parts. The one is a controller and the other is a display. Something like Google Slides in presentation mode. The controller has a button to launch the display:
<script language="JavaScript">
function OpenMain()
{
var MainPage = window.open("TheUltraSignalLite.html");
TimerIMG = MainPage.document.getElementById("TimerIMG");
TimerIMG.src = "TM-Full-Blue.jpg";
}
</Script>
The call to window.open seems to return null. I have tried Chrome, Edge, Firefox, and Opera and they all have the result. These are all local files for now, but I might put in on a web server someday. I have seen some answers that want you to turn off security, but I cannot ask everyone who uses this app to turn off security. How do I get a valid reference to the display window?
Edit 1:
Yes, window.open from the local disk does cause a CORS restriction.
I tried this where both files are in the same AWS S3 Bucket, so the CORS should not be an issue. But I still get a null on the window.open. If I put a breakpoint on the first line, then everything worked. If I split the open and the rest of the code into two functions with two buttons, it works. So it looks like I have to find a way to run the open in an async way.
Edit 2
My solution to keep it simple was to put the window.open in the OnLoad event. This opens the child window and allows it to fully render and the value of MainPage is ready to use. (I changed the MainPage to a global variable.) I still have to run it from some type of web server, rather than loacl file, but that is not a big deal.
If you are not allowed to access the new window content, then the problem you are encountering is a basic security feature of web browsers. Citing mdn:
The returned reference can be used to access properties and methods of the new window as long as it complies with Same-origin policy security requirements
To read more about Same-origin policy
If your new window respects the Same-origin policy, then you can access the content of the new window with for example:
// Open index.html from the current origin
const newWindow = window.open('index.html')
const h1 = newWindow.document.querySelector('h1')
If you want to avoid asking users for pop-up permission, then you should probably use a link instead of a pop-up.

JavaScript problems when launching site in iframe

I have set up an Articulate Storyline course (a Flash version accessed using the page "story.html" and an HTML5 version accessed using "story_html5.html"). It works fine when run directly, however, when I try to run everything in an iframe on the company server (linking to the course files on my personal server) I get JavaScript errors:
The course uses player.GetVar("HTML5spelaren") to access a variable called HTML5spelaren, which is located on the story_html5.html page itself. When running in an iframe I get a "Permission denied to access property 'HTML5spelaren'".
Finally the course uses the JavaScript var newWin=document.window.open("report.html", "Kursintyg"); to display a course completion certificate in a new window. When running in an iframe however this results in a "Permission denied to access property 'open'".
Is there a way to rewrite the JavaScripts to get around this? I need to be able to detect if the course is running in Flash or HTML5 mode (that's what I use the variable in story_html5.html for), as well as being able to use JavaScript to open a new page from within the iframe when clicking on a link.
Page structure:
https://dl.dropboxusercontent.com/u/11131031/pagestructure.png
/Andreas
There's a way for different domains to speak to one another via javascript. You can use postMessage: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
In your case, in story.html or story_html5.html could use something like:
parent.postMessage(HTML5spelaren, parent_domain);
and you add an event listener in the company page:
window.addEventListener("message", receiveMessage, false);
And in receiveMessage function you retrieve the data that you need. Something like:
function receiveMessage(event){
your_variable = event.data
}
Same logic can be probably be applied to your popup.
You can post from child to parent or from parent to child.
My guess is that content you're linking to in the iFrame is on a different server/domain. If so, the error is a security feature to stop cross-site scripting (XSS) attacks.
Consider putting both the parent iFrame and the articulate content (child) on the same server. This should eliminate the problem.

node-webkit running a function from external source

I am loading a remote page with an iframe in node-webkit app.
I would like to run a function from the node.js app from the webpage.
In app.js i have
var xxx = function(){ console.log('test'); }
and in http://www.test.com/index.html i have tried:
window.xxx();
xxx();
global.xxx();
But nothing seems to work.
How can i do that?
Many thanks
If I understand correctly, you want to access a function that's defined in the remote page that you are including as an iframe in your current page, right?
There are two separate issue here, I think.
First, you need to have a handle on the iframe, then access that window's environment through the 'contentWindow' property of the iframe dom element, i.e. given an iframe with id foo, that points to a page with a function named bar, you could do this:
x = document.getElementById('foo');
x.bar();
This works fine for me with a local page, but the other issue is that you might find some difficulty with running a remote page in an iframe and still having access. If it's a page under your control, that might work, but some pages don't like to be run in iframes, so then you have to sandbox to some extent, which may interfere with your ability to access it in this way. It's been a while since I played with sandboxing, so I'm not sure, but if it's a page you control, you should be able to set it up so it's not a problem.

Change Page Title on Canvas App

This is a shot in the dark, but is it possible to update the page title of a canvas app using Javascript? While the page title does seem to reflect the app, is it possible to update it once the page has rendered?
I'd like to be able to add an active counter to the title (e.g. "(0) Title", "(1) Title", "(2) Title") based on what's happening in the app, which doesn't seem possible from within an iframe.
[edit]
Document.title obviously doesn't work since it's applied to my page. But I've also tried parent.document.title and that doesn't work either.
To access the parent window you need something like: parent.document.title
But this is NOT allowed for obvious reasons:
Facebook won't allow you to access their page (document)
Read about Cross Domain Communications & Same origin policy (there are suggested workarounds but I don't think Facebook will allow them either)
Anyway, if you try the code above you'll get (as expected):
Permission denied to access property 'document'

Need to change #src of a parent iframe from within child iframe

I have the following HTML markup (don't ask....)
- document //main site
- <iframe> //my site
- <iframe> //site within my site
- <frame>
- <a onclick="JavaScript:parent.parent.location.href='http://bla.com;return false;'">
Basically, main site is calling my site in an iframe. I, in turn, also have an iframe on my site where I'm calling 3rd site. The third site has a frameset with a frame in it that has a link. When clicking on this link, it has to change the url of my site. My site and my child site are on the same domain. When I'm running my site as "stand-alone" (not in iframe) the above code works fine in all browsers.
Once I open my site in an iframe of the main site, it looks like the above code is trying to change the source of the main site. In FireFox I get a console message "Access to property denied". In IE it opens up a new window with my site not in the main site anymore.
What is the correct JavaScript to change the #src attribute on my site when I'm within an iframe?
You are banging your head against the wall that is the same origin policy here. This is XSS country and strictly forbidden, no way around it, unless both domains agree to talk together.
You can read more about cross domain communication using iframes, but again, unless the different domain agree to talk together, you are out of luck.
Although this might seem frustrating, be glad of this rule next time you use homebanking ;)
Can you try something like this
<document> //main site
<iframe id="my_iframe"> //your site
<iframe> //site within your site
<frame>
<a onclick="JavaScript:Top.document.getElementById('my_iframe').location.href='http://bla.com;return false;'">
Top refers to the main window, and then getElementById('my_iframe') will give you your iframe element.
I believe that you're trying to do communication between different pages.
You may take a look this API: HTML5 Cross Document Messaging
Basically, if you want to tell the parent iframe to navigate to a certain url, you can do this:
In the site within my site html:
// onclick of your anchor, post message (an event) with an expected origin
window.postMessage("http://bla.com", "www.sitewithinmysite.com");
In my site html:
// listen to the event "message"
window.addEventListener("message", messageHandler, true);
function messageHandler(e) {
// only recognize message from this origin
if (e.origin === "www.sitewithinmysite.com") {
// then you can navigate your page with the link passed in
window.location = e.data;
}
}
You might want to have the pages communicate using AJAX. Have the site that needs to change its URL listen by long polling to to a node.js server.

Categories