Override window.open inside an IFrame - javascript

I'm using an IFrame that contains a remote page on a different domain (that I have no control of), and it sometimes tries to pop a window using window.open.
Instead of popping the window - I want to dynamically add another IFrame to the page with the URL that the first IFrame was trying to open.
Is there a way to override the IFrame's window.open so I'll be able to 'catch' the URL it tries to pop?
I've tried:
var myFrame = document.getElementById("ifrm"); // 'ifrm' is the iframe's ID
myFrame.contentWindow.open = function (url, name, features) {
alert(url);
};
But it didn't work (no alert, and the iframe still tried to pop the new window)...
Any ideas?

Try:
function bindings(newDoc){
try
{
newDoc.contentWindow.window.open = function (url, name, features,
replace) {
alert(url);
};
}
catch( e )
{
console.log(e.message);
}
}
While calling the iFrame, use onload event:
<iframe onload="bindings(this)" ... />
It throws the error:
Permission denied to access property 'open' in Firefox
LOG: Permission denied in Internet Explorer
Apparently Dan F was right.. UA will deny access to the remote (cross-domain) document loaded via iframe.

Related

Is it possible to send window messages to an embedded website?

I'm creating a script that runs on every website (using temperMonkey). On a shortcut I inject a form into the page. So if I am in stackoveflow, I pres cmd+esc and I embed a local vuejs page
Step 1: Inject an iframe to (say) stack overflow and send a message to the embedded site**
var iframe = document.createElement("iframe");
iframe.type="text/html"
iframe.src="http://localhost:8080/webhighlights"
iframe.id="localFrame"
var data = {title: document.title, url: window.location,}
iframe.onload= function(){
var t = document.getElementById('localFrame');
t.contentWindow.postMessage({
data
}, 'http://localhost:8080/webhighlights');
}
Step 2: get the message from the site that has embedded me:
mounted: function () {
/* eslint-disable */
window.top.addEventListener('message',receiveMessage, false);
function receiveMessage (event) {
console.log('event data: ', event)
}
}
The message doesn't come through. The error I get in the console is Failed to execute 'postMessage' on 'Window': Location object could not be cloned. at HTMLIFrameElement.iframe.onload
You are sending a message to your iframe's context, so from this iframe you don't want to listen for top's messages, but only for this iframe's window ones.
Change
window.top.addEventListener('message',...
to
window.addEventListener('message',...
If you want to understand better how messaging works, I invite you to read this answer of mine.
Baiscally with an iframe, one port is in the main context, under HTMLIframeElement.contentWindow, and the other one is in the iframe's context, under window. To communicate between both contexts, each context should listen to and talk in their own port.
When this is fixed you will face a new issue that the location object can't be cloned. Since apparently you only want to send the current URL of the main page, then only send this:
var data = {title: document.title, url: window.location.href };

Get url from iframe when origin is not the same

I want to get the URL from an iframe when the user redirects by clicking links in the iframe. The source of the iframe is not the same as the web application.
For example:
<iframe src="startingUrl" class="embed-responsive-item" id="iframe" sandbox="" allowfullscreen</iframe>
I add a load listener on the iframe to detect when the user redirects to other urls in this iframe:
const iframe = document.getElementById("iframe");
iframe.addEventListener("load", (evt) => {
const location = iframe.contentWindow.location;
console.log(location); // this gives me a Location object where I can see the href property
console.log(location.href); // this gives me a SecurityError: Permission denied to get property "href" on cross-origin object, I also tried to get a copy of the object but that doesn't work either.
});
I know what causes this problem and I also know it is not possible. But I need to find a way to get the current URL of the page. If this is a no go then I want that the user who uses this web application can copy the url of the iframe and put it in an input field.
Now they can do "View frame source" in chrome and This frame: view frame source or info in Firefox. But this is too complicated for the user. Is there a way they can see the URL in the iFrame or a way for the user to get the URL simpler.
The site in the iFrame is not mine.
All help is much appreciated!
Short answer: This is a no go, unless you have the support of the other site in your iframe and they are willing to add the code in #박상수 answer.
Longer answer: You could set up a proxy server to inject the required code to make this work, but then you will run into legal and ethical difficulties, so I am not going to explain how to do that in depth.
Another approach might be to create a browser extension and have your users install that. Again I should point out FaceBook has in the past ran into ethical difficulties taking this approach.
Ultimately their are very good security reasons why the browser stops you doing this and you should probably respect those reasons and not do it.
If you don't see the code below, check the link below.
console.log(iframe.src);
Check out this link
SecurityError: Blocked a frame with origin from accessing a cross-origin frame
let frame = document.getElementById('your-frame-id');
frame.contentWindow.postMessage(/*any variable or object here*/, 'http://your-second-site.com');
window.addEventListener('message', event => {
// IMPORTANT: check the origin of the data!
if (event.origin.startsWith('http://your-first-site.com')) {
// The data was sent from your site.
// Data sent with postMessage is stored in event.data:
console.log(event.data);
} else {
// The data was NOT sent from your site!
// Be careful! Do not use it. This else branch is
// here just for clarity, you usually shouldn't need it.
return;
}
});
You will want to override the error being automatically thrown:
const iframe = document.getElementById('iframe');
iframe.addEventListener('load', evt => {
const loc = iframe.contentWindow.location;
try{
loc.href;
}
catch(e){
if(e.name === 'SecurityError'){
console.log(iframe.src);
}
}
});
<iframe src='https://example.com' class='embed-responsive-item' id='iframe' sandbox='' allowfullscreen></iframe>

How to access location.href of a nested frame in IE8 on same domain?

My main page contains an <iframe> which points to an HTML file that contains a <frameset>. It looks similarly to the following (simplified for readability):
<html>
<body>
<iframe id="content" src="/same/domain/url" />
</body>
</html>
The <iframe> contents look like this:
<html>
<body>
<frameset>
<frame name="menu" src="/same/domain/menu/url" />
<frame name="main" src="/same/domain/initial/main/url" />
</frameset>
</body>
</html>
I am trying to read the current location href of the main frame from the main page.
$("#content").contents().find("frame[name=main]")[0].contentWindow.location.href
Unfortunately, on IE8 it gives me the "Permission denied" error. This looks like cross-domain scripting prevention mechanism, but all URLs come from the same domain/protocol/port. For the same javascript code Chrome gives me the correct value (surprise, surprise).
Please note that:
I can't use the frame's src attribute as the user might have already used the "menu" frame to navigate to another page (still, same domain).
I have no control over the contents of the iframe pages, these are supplied by another part of the application and are unmodifiable from my perspective
How do I get around this?
A way to do this would be to use postMessage api which allows for message passing between different windows / frames.
On the root window, listen for messages
window.attachEvent("onmessage", (e) => {
// handle message
});
Post a message to a child frame (iframe is a dom node).
iframe.contentWindow.postMessage({}, "*");
Within the child
window.parent.postMessage({}, "*");
This allows a simplistic event-driven communication scheme where you dispatch actions in the form of messages and receive response laters
as onmessage events.
In your case you would have something along:
// within child iframe
window.attachEvent("message", function (e) {
// IE8 does not support object passing, only strings
var message = JSON.parse(e.data);
// wait for a GET_HREF message
// and respond to it with the
// data.
if (message.type === "GET_HREF") {
window.parent.postMessage(JSON.stringify({
type: "GET_HREF",
data: $("frame")
.map(function () {
return this.href;
})
.get()
}));
}
});
// within parent window
window.attachEvent("message", function (e) {
// IE8 does not support object passing, only strings
var message = JSON.parse(e.data);
// wait for a GET_HREF message
if (message.type === "GET_HREF") {
updateHref(message.data);
}
});
iframe.contentWindow.postMessage(JSON.stringify({
type: "GET_HREF"
}), "*");

Open window in tab of new window

I want to open a tab inside an opened window. Something like this
(it should open a new window with "google.co.uk" with a new tab "google.de"
newWindow = window.open('http://www.google.co.uk', '', 'width=10');
newWindowTab = newWindow.open('http://www.google.de', '_blank');
but this opens "newWindowTab" only in the window, where this code is.
I have also tried this, to give the window time to load, until it (should) open the new tab:
newWindow = window.open('http://www.google.co.uk', '', 'width=10');
setTimeout(function() {
newWindowTab = newWindow.open('http://www.google.de', '_blank');
}, 500);
But then I get:
Error: Permission denied to access property "open"
I have used firefox. I heard that it might be possible to do in Chrome, but I want to use this script in Firefox.
This is not possible, unless the window being opened is from the same origin (ie the same domain). MDN says this:
The reference can be used to access properties and methods of the new
window provided it complies with Same origin policy security
requirements.

Fake User Agent for iframe

I'm new to Javascript. I have found this code to change user agent using Javascript.
var __originalNavigator = navigator;
navigator = new Object();
navigator.__defineGetter__('userAgent', function () {
return 'Custom';
});
var iframe='<iframe id="frame" name="widget" src ="http://www.useragentstring.com/" width="100%" height="400" marginheight="0" marginwidth="0" frameborder="no" scrolling="no"></iframe>';
document.write("User-agent header sent: " + navigator.userAgent + iframe);
This code works & returns fake user agent, Though how will I set same fake user agent for iframe ?
Here is fiddle of what I'm up to : http://jsfiddle.net/ufKBE/1/
I already answer the same question at <Load iframe content with different user agent>
For your convenient, I copied and paste the answer here:
First of all, you must create a function to change the user agent string:
function setUserAgent(window, userAgent) {
if (window.navigator.userAgent != userAgent) {
var userAgentProp = { get: function () { return userAgent; } };
try {
Object.defineProperty(window.navigator, 'userAgent', userAgentProp);
} catch (e) {
window.navigator = Object.create(navigator, {
userAgent: userAgentProp
});
}
}
}
Then you need to target the iframe element:
setUserAgent(document.querySelector('iframe').contentWindow, 'MANnDAaR Fake Agent');
You may also set an ID to the iframe and target the ID instead of all iframe elements on the page.
That is not the right way to switch your user agent to the faked one. window.navigator = {userAgent:Custom_User_Agent} is just a javascript execution. It will simply be ignored as you refresh the page, either it is on window or within the iframe, and then the default user agent which will be sent to the server instead. If you really want to switch your user agent, it has to be the browser setting you deal with. Some browsers allow this on their settings, and some others include user agent switcher or support some kind of plugin that do this
http://www.howtogeek.com/113439/how-to-change-your-browsers-user-agent-without-installing-any-extensions/
The alternatives are, you can also try to access the website from the server or build your own web accessing application. These ways, you can freely alter your header or use your own customized user agent
Another way is by using AJAX. but of course it is limited by cross-origin-policy

Categories