Fake User Agent for iframe - javascript

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

Related

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"
}), "*");

Detecting protocol handler with Javascript [duplicate]

I have created a custom URL protocol handler.
http://
mailto://
custom://
I have registered a WinForms application to respond accordingly. This all works great.
But I would like to be able to gracefully handle the case where the user doesn't have the custom URL protocol handler installed, yet.
In order to be able to do this I need to be able to detect the browser's registered protocol handlers, I would assume from JavaScript. But I have been unable to find a way to poll for the information. I am hoping to find a solution to this problem.
Thanks for any ideas you might be able to share.
This would be a very, very hacky way to do this... but would this work?
Put the link in as normal...
But attach an onclick handler to it, that sets a timer and adds an onblur handler for the window
(in theory) if the browser handles the link (application X) will load stealing the focus from the window...
If the onblur event fires, clear the timer...
Otherwise in 3-5seconds let your timeout fire... and notify the user "Hmm, looks like you don't have the Mega Uber Cool Application installed... would you like to install it now? (Ok) (Cancel)"
Far from bulletproof... but it might help?
There's no great cross-browser way to do this. In IE10+ on Win8+, a new msLaunchUri api enables you to launch a protocol, like so:
navigator.msLaunchUri('skype:123456',
function()
{
alert('success');
},
function()
{
alert('failed');
}
);
If the protocol is not installed, the failure callback will fire. Otherwise, the protocol will launch and the success callback will fire.
I discuss this topic a bit further here:
https://web.archive.org/web/20180308105244/https://blogs.msdn.microsoft.com/ieinternals/2011/07/13/understanding-protocols/
This topic is of recent (2021) interest; see https://github.com/fingerprintjs/external-protocol-flooding for discussion.
HTML5 defines Custom scheme and content handlers (to my knowledge Firefox is the only implementor so far), but unfortunately there is currently no way to check if a handler already exists—it has been proposed, but there was no follow-up. This seems like a critical feature to use custom handlers effectively and we as developers should bring attention to this issue in order to get it implemented.
There seems to be no straightforward way via javascript to detect the presence of an installed app that has registered a protocol handler.
In the iTunes model, Apple provides urls to their servers, which then provide pages that run some javascript:
http://ax.itunes.apple.com/detection/itmsCheck.js
So the iTunes installer apparently deploys plugins for the major browsers, whose presence can then be detected.
If your plugin is installed, then you can be reasonably sure that redirecting to your app-specific url will succeed.
What seams the most easy solution is to ask the user the first time.
Using a Javascript confirm dialog per example:
You need this software to be able to read this link. Did you install it ?
if yes: create a cookie to not ask next time; return false and the link applies
if false: window.location.href = '/downloadpage/'
If you have control of the program you're trying to run (the code), one way to see if the user was successful in running the application would be to:
Before trying to open the custom protocol, make an AJAX request to a server script that saves the user's intent in a database (for example, save the userid and what he wanted to do).
Try to open the program, and pass on the intent data.
Have the program make a request to the server to remove the database entry (using the intent data to find the correct row).
Make the javascript poll the server for a while to see if the database entry is gone. If the entry is gone, you'll know the user was successful in opening the application, otherwise the entry will remain (you can remove it later with cronjob).
I have not tried this method, just thought it.
I was able to finally get a cross-browser (Chrome 32, Firefox 27, IE 11, Safari 6) solution working with a combination of this and a super-simple Safari extension. Much of this solution has been mentioned in one way or another in this and this other question.
Here's the script:
function launchCustomProtocol(elem, url, callback) {
var iframe, myWindow, success = false;
if (Browser.name === "Internet Explorer") {
myWindow = window.open('', '', 'width=0,height=0');
myWindow.document.write("<iframe src='" + url + "'></iframe>");
setTimeout(function () {
try {
myWindow.location.href;
success = true;
} catch (ex) {
console.log(ex);
}
if (success) {
myWindow.setTimeout('window.close()', 100);
} else {
myWindow.close();
}
callback(success);
}, 100);
} else if (Browser.name === "Firefox") {
try {
iframe = $("<iframe />");
iframe.css({"display": "none"});
iframe.appendTo("body");
iframe[0].contentWindow.location.href = url;
success = true;
} catch (ex) {
success = false;
}
iframe.remove();
callback(success);
} else if (Browser.name === "Chrome") {
elem.css({"outline": 0});
elem.attr("tabindex", "1");
elem.focus();
elem.blur(function () {
success = true;
callback(true); // true
});
location.href = url;
setTimeout(function () {
elem.off('blur');
elem.removeAttr("tabindex");
if (!success) {
callback(false); // false
}
}, 1000);
} else if (Browser.name === "Safari") {
if (myappinstalledflag) {
location.href = url;
success = true;
} else {
success = false;
}
callback(success);
}
}
The Safari extension was easy to implement. It consisted of a single line of injection script:
myinject.js:
window.postMessage("myappinstalled", window.location.origin);
Then in the web page JavaScript, you need to first register the message event and set a flag if the message is received:
window.addEventListener('message', function (msg) {
if (msg.data === "myappinstalled") {
myappinstalledflag = true;
}
}, false);
This assumes the application which is associated with the custom protocol will manage the installation of the Safari extension.
In all cases, if the callback returns false, you know to inform the user that the application (i.e., it's custom protocol) is not installed.
You say you need to detect the browser's protocol handlers - do you really?
What if you did something like what happens when you download a file from sourceforge? Let's say you want to open myapp://something. Instead of simply creating a link to it, create a link to another HTML page accessed via HTTP. Then, on that page, say that you're attempting to open the application for them. If it doesn't work, they need to install your application, which they can do by clicking on the link you'll provide. If it does work, then you're all set.
This was a recommended approach for IE by Microsoft support
http://msdn.microsoft.com/en-us/library/ms537503%28VS.85%29.aspx#related_topics
"If you have some control over the binaries being installed on a user’s machine, checking the UA in script seems like a relevant approach:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\User Agent\Post Platform
" -- By M$ support
Every web page has access to the userAgent string and if you drop a custom post platform value, detecting this in javascript using navigator.userAgent is quite simple.
Fortunately, other major browsers like Firefox and Chrome (barring Safari :( ), do not throw "page not found" errors when a link with a custom protocol is clicked and the protocol is not installed on the users machine. IE is very unforgiving here, any trick to click in a invisible frame or trap javascript errors does not work and ends up with ugly "webpage cannot be displayed" error. The trick we use in our case is to inform users with browser specific images that clicking on the custom protocol link will open an application. And if they do not find the app opening up, they can click on an "install" page. In terms of XD this wprks way better than the ActiveX approach for IE.
For FF and Chrome, just go ahead and launch the custom protocol without any detection. Let the user tell you what he sees.
For Safari, :( no answers yet
I'm trying to do something similar and I just discovered a trick that works with Firefox. If you combine it with the trick for IE you can have one that works on both main browsers (I'm not sure if it works in Safari and I know it doesn't work in Chrome)
if (navigator.appName=="Microsoft Internet Explorer" && document.getElementById("testprotocollink").protocolLong=="Unknown Protocol") {
alert("No handler registered");
} else {
try {
window.location = "custom://stuff";
} catch(err) {
if (err.toString().search("NS_ERROR_UNKNOWN_PROTOCOL") != -1) {
alert("No handler registered");
}
}
}
In order for this to work you also need to have a hidden link somewhere on the page, like this:
<a id="testprotocollink" href="custom://testprotocol" style="display: none;">testprotocollink</a>
It's a bit hacky but it works. The Firefox version unfortunately still pops up the default alert that comes up when you try to visit a link with an unknown protocol, but it will run your code after the alert is dismissed.
You can try something like this:
function OpenCustomLink(link) {
var w = window.open(link, 'xyz', 'status=0,toolbar=0,menubar=0,height=0,width=0,top=-10,left=-10');
if(w == null) {
//Work Fine
}
else {
w.close();
if (confirm('You Need a Custom Program. Do you want to install?')) {
window.location = 'SetupCustomProtocol.exe'; //URL for installer
}
}
}
This is not a trivial task; one option might be to use signed code, which you could leverage to access the registry and/or filesystem (please note that this is a very expensive option). There is also no unified API or specification for code signing, so you would be required to generate specific code for each target browser. A support nightmare.
Also, I know that Steam, the gaming content delivery system, doesn't seem to have this problem solved either.
Here's another hacky answer that would require (hopefully light) modification to your application to 'phone home' on launch.
User clicks link, which attempts to launch the application. A unique
identifier is put in the link, so that it's passed to the
application when it launches. Web app shows a spinner or something of that nature.
Web page then starts checking for a
'application phone home' event from an app with this same unique ID.
When launched, your application does an HTTP post to your web app
with the unique identifier, to indicate presence.
Either the web page sees that the application launched, eventually, or moves on with a 'please download' page.

Override window.open inside an IFrame

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.

How to filter out iframes in an Add-on SDK extension?

The main problem is that my extension is loading into every iframes on a target webpage. It puts buttons that appear inside the iframes as well. I want them to disappear. The window and document objects are shown as the parent's window and document objects. So it's impossible to check the document location for example because it shows the parent's location instead of the iframe's location.
You could write a user script which uses the #noframes metadata header key and include the user script in to your Jetpack with this user script package for the addon sdk.
Writing user scripts is much easier than writing Page Mods too.
Edit: now (Add-on SDK version 1.11 released) pagemod supports what you are looking for. See the docs and the new attachTo option.
The following information is outdated (can be used if you build against Add-on SDK 1.10 or previous:
Unfortunately pagemod injects your script in all the frames of the page, and not just once per page on the top frame as what you achieve with Chrome's content scripts. Of course, there are workarounds for stopping the execution of the script (see the other answers).
But if you really want to inject your script only once per page, on the top frame, you have to use tabs. With this solution you script only gets injected when it has to.
Bellow I provide and example for porting from pagemod to tabs, keeping all the message reception system with port working. It can easily be modified if you need to not just receive, but also send messages using that same port object. The script gets injected when we are in the domain youtube.com:
Old pagemod way:
var self = require("self");
var pagemod = require("page-mod");
pagemod.PageMod(
{
include: "*.youtube.com",
contentScriptFile: self.data.url("myContentScript.js"),
onAttach: function(worker)
{
worker.port.on("myMessageId", function(payload)
{
console.log("Message received: " + payload);
});
}
});
New tabs way:
var self = require("self");
var tabs = require("tabs");
tabs.on("ready", function(tab)
{
if (tab != undefined && tab.url != undefined && tab.url.split("/")[2] != undefined)
{
var domain = "youtube.com";
var host = tab.url.split("/")[2];
if (host == domain || host.substr(host.length - domain.length - 1) == "." + domain)
{
var worker = tab.attach({ contentScriptFile: self.data.url("myContentScript.js") });
worker.port.on("myMessageId", function(payload)
{
console.log("Message received: " + payload);
});
}
}
});
One workaround is to put something like this in your content script:
if (window.frameElement === null){
// I'm in the topmost window
// Add buttons and things to the page.
}else{
// I'm in an iFrame... do nothing!
}
The content script will still be added to every page, but it's a relatively simple and lightweight check for iFrames.

Categories