Cannot access iframe DOM elements without first selecting it with developer tools - javascript

I'm making a chrome extension which accesses the video elements on web pages. This is the iframe and child video element.
When attempting to get access to the iframe DOM using (this is in the content script running on the page):
function GetIframeDocument(){
var iframe = document.getElementById("vilos-player");
var doc = iframe.contentWindow.document;
var videoElement = doc.getElementByid("player_html5_api");
}
I get the error:
Uncaught DOMException: Blocked a frame with origin "https://www.crunchyroll.com" from accessing a cross-origin frame.
at <anonymous>:1:21
However, if I go into chrome developer tools and make the video element a global variable (like this). I can then apply javascript to the element in the console without running into the cross-origin frame error (as seen here).
How can I access the video element in my script without running into the error? If I can access it in the console and it can be seen in the page elements in developer tools.

I do not know what you need to do, but obviously get a link to the video.
Recommend that you inject your javascript using a chrome extension. During the creation of the extension, set the parameter
all_frames = true
https://developer.chrome.com/extensions/content_scripts
then your code will be on all pages and on iframe too.

As we can read in docs
The HTML Inline Frame element () represents a nested browsing context, embedding another HTML page into the current one.
So, iframe element has its own window object, and for access it you can use predefined method contentWindow().
See method description and W3Schools example.

Related

Webpage with iFrames

I am experimenting with making a website where I have two iframes with other webpages side by side, and would only like to show a certain part of these websites.
Trying to edit the innerHTML of these websites throws errors regarding cross-page security problems.
How can I run Javascript inside these iFrames in a safe manner? If this is not possible, is there a good atlernative for iFrames where I can have to websites side-by-side?
It's not important for me to be able to edit both iFrames, only one of them need to be editable.
An iframe is just a 'hole' in your page that displays another web page inside of it. The contents of the iframe are not in any shape or form part of your parent page.
If your iframe is loaded from the same domain as your parent, then you can access the DOM of the document in the iframe from the parent.
Considering the iframe is from the same domain, Try using the below code and see if it works. The below code will add CSS changes to the iframe. If this works for you, then you can run javascript as well.
<script>
var iframe = document.getElementById("frame1");
$('iframe').load( function() {
$('iframe').contents().find("head")
.append($("<style type='text/css'> .lt{display:none;} </style>"));
});
</script>
If you are getting "permission denied type errors.", I think what you are doing is subject to the same-origin policy. This should be the reason why you are getting permission denied type errors.
Here you can check the possible solutions.
Unable to access iframe content (same-origin policy)

How to switch JS contexts(to iframe context of different domain) programatically using Puppeteer or Chrome console

I want to use Puppeteer to get data from selectors that are placed inside an iframe on a page which runs on a different domain from it's parent's frame domain.
I am not the owner of any of the domains therefore - can't use frame.postMessage.
tried to refer to the selector with
document.querySelector('#selector_inside_iframe')
but since the selector inside an iframe - it is invisible from the main context. When tried to use
document.querySelector('#selector_inside_iframe').contentWindow.document
because the iframe uses different domain - it is blocked by CORS.
It works when changing manually the JS context in the JS contexts dropdown on the console tab of Chrome, however, it need to be done using Puppeteer.
I expect to get reference to node '#selector_inside_iframe' but getting the following error if not changing context inside Chrome dev-tools:
'Uncaught DOMException: Blocked a frame with origin "https://blah.some_domain.com" from accessing a cross-origin frame'
I was able to solve it by using Puppeter's ElementHandle.contentFrame() .
first get reference to the iframe selector as ElementHandle object using
const iframeHandle = await page.$('iframe')
then refer to the iframe context with ElementHandle.contentFrame() like this:
const contentFrame = await iframeHandle.contentFrame()
Now to query the html/css selectors inside the iframe just use the contentFrame
such as the following:
contentFrame.$('.data_class')

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.

When does a web browser request the src content of a dynamically created iframe?

Let's say I dynamically create an iframe node by using js, then set the src attribute (1) and finally append the node to the DOM (2).
When is the src content requested by the browser? After (1)? After (2)? Or is it unpredictable? Does it depend on the browser?
The specification states:
When an iframe element is first inserted into a document,
the user agent must create a nested browsing context, and then
process the iframe attributes for the first time.
Using the following snippet and a local server, I've tested the behaviour in many browsers.
var f = document.createElement('iframe');
f.src = '/?';
The resource is never fetched (I've only shown the lowest and highest tested browser version):
IE 6 - 9
FF 3.6 - 12.0
Chrome 1 - 18
Opera 10.00 - 12.00
Safari 4.0 - 5.1.5
So, it the request is only sent once the frame is appended to the document.
After (2). Before that it's just JS. The browser won't act upon it until it's attached to the DOM.
Well, I'm not going to test every browser for you but I would always expect elements with src and href attributes that link to or load contents of some kind to always load after they're actually appended since when/where an iframe or a js file falls in the document hits on a ton of security and general implementation concerns. It would be critical fail on a browser vendor's part to do it any other way and I can see for a fact that chrome does it that way with a little experimentation.
The only exception I can think of is images which can be loaded before insertion.
In my experience it has always been when the node is added to the DOM. You can load up Firebug, or some other dev console, and see when this occurs. Throw in a couple alerts to be sure about the timing like this:
<script type="text/javascript">
ifrm = document.createElement("IFRAME");
ifrm.setAttribute("src", "http://blah.com/");
alert('SRC SET');
ifrm.style.width = 640+"px";
ifrm.style.height = 480+"px";
document.body.appendChild(ifrm);
alert('ADDED TO DOM');
</script>
Run something like that and watch the "Net" tab in Firebug to see when the page is requested. I believe it will only be requested after the appendChild is called.
After (2)!! take a look at this: http://jsfiddle.net/lbstr/td7DD/
Open up firebug or chrome's console and look at the net tab. You will see google loading. Then, comment out the third line and run it again. You won't see google loading.

How to access DOM (and /or window.document object) of a popup in Chrome extension script?

I'm working on a Google Chrome 'context' script
From the Chrome console, or a 'normal' tag, I can do :
win1 = window.open('some url');
b1 = win1.document.body.innerHTML;
But from a chrome 'context' script, it fails with
Uncaught TypeError: Cannot read property 'document' of undefined
What is the "magic incantation" I need ?
This seems to be close to what I need, but it doesn't show where to put code to have the popup return a dom element
Get DOM elements of a popup for jQuery manipulation
I don't fully understand the code there (nested scopes and things), so
I'm trying to figure out where I'd put something like:
var getStuff = $('#baz').html();
Mike
You can only do what you propose IF both urls are in the same domain.
Otherwise you have cross domain issues and chrome (and most other browsers) do not allow for it.

Categories