PasswordCheck/js/ReferrerKiller.js
2014-09-13 17:28:59 -05:00

248 lines
7.8 KiB
JavaScript

/**
* @Project: ReferrerKiller.
* @Licence: The MIT License.
* @Author: Juan Pablo Guereca.
* @Description: Crossbrowser referrer killing solution.
* It's a hack that prevents the browser of sending the http referrer in the following cases:
* - Link: You can have a link in your website being sure that the destiny won't know about your site.
* - Image: You can display an image from another site being sure the other site won't know your website is displaying it.
* Other interesting use is displaying an image without blocking the rest of the content, this way in case the image fails
* it allows the rest of the page to load normally.
* Uses:
* - Load static content in parallel.
* - Provide privacy to your web users.
* - Saving bandwidth, considering you safe the extra bytes of the http referrer.
* Abuses:
* - Stilling bandwidth, using some other site contents (hotlinking, http://en.wikipedia.org/wiki/Inline_linking).
* @Compatibility:
* It's been tested successfully on:
* - Chrome 24.
* - Firefox 15.
* - Safari 6.
* - Opera 12: it sends the referrer in the case of anchors if the target is an iframe, not if it opens in other window
* or the same one, for images it never sends the referrer even without using the hack.
* - IE 6, 7, 8.
* - IE 9: it works for images but not links, that's why in that oogle's url redirection is used for this browser, in this case
* there is an intermediate page.
* @Interface:
* - ReferrerKiller.linkHtml(url, [innerHtml], [anchorParams], [iframeAttributes]). Returns a string.
* - ReferrerKiller.linkNode(url, [innerHtml], [anchorParams], [iframeAttributes]). Returns an Html Node.
* - ReferrerKiller.imageHtml(url, [imgParams], [iframeAttributes]). Returns a string.
* - ReferrerKiller.imageNode(url, [imgParams], [iframeAttributes]). Returns an Html Node.
*/
/**
* @module ReferrerKiller
*/
var ReferrerKiller = (function () {
var URL_REDIRECTION = "https://www.google.com/url?q=", // You can use another service if you use https protocol no referrer will be sent.
PUB = {},
IE_GT_8 = (function () {
/*- Detecting if it's IE greater than 8 -*/
var trident,
match = navigator.userAgent.match(/Trident\/(\d)+/);
if (null === match) {
return false;
}
trident = parseInt(match[1], 10);
if (isNaN(trident)) {
return false;
}
return trident > 4;
})();
/**
* Escapes double quotes in a string.
*
* @private
* @param {string} str
* @return {string}
*/
function escapeDoubleQuotes(str) {
return str.split('"').join('\\"');
}
/**
* Given a html string returns an html node.
*
* @private
* @param {string} html
* @return {Node}
*/
function htmlToNode(html) {
var container = document.createElement('div');
container.innerHTML = html;
return container.firstChild;
}
/**
* Converts object to html attributes string.
*
* @private
* @param {object} obj
* @return {string}
*/
function objectToHtmlAttributes(obj) {
var attributes = [],
value;
for (var name in obj) {
value = obj[name];
attributes.push(name + '="' + escapeDoubleQuotes(value) + '"');
}
return attributes.join(' ');
}
/**
* It applies the hack to kill the referrer to some html.
*
* @public
* @param {string} html.
* @param {object} [iframeAttributes]
* @return {string} html.
*/
function htmlString(html, iframeAttributes) {
var iframeAttributes = iframeAttributes || {},
defaultStyles = 'border:none; overflow:hidden; ',
id;
/*-- Setting default styles and letting the option to add more or overwrite them --*/
if ('style' in iframeAttributes) {
iframeAttributes.style = defaultStyles + iframeAttributes.style;
} else {
iframeAttributes.style = defaultStyles;
}
id = '__referrer_killer_' + (new Date).getTime() + Math.floor(Math.random()*9999);
/*-- Returning html with the hack wrapper --*/
return '<iframe \
style="border 1px solid #ff0000" \
scrolling="no" \
frameborder="no" \
allowtransparency="true" ' +
/*-- Adding style attribute --*/
objectToHtmlAttributes( iframeAttributes ) +
'id="' + id + '" ' +
' src="javascript:\'\
<!doctype html>\
<html>\
<head>\
<meta charset=\\\'utf-8\\\'>\
<style>*{margin:0;padding:0;border:0;}</style>\
</head>' +
/*-- Function to adapt iframe's size to content's size --*/
'<script>\
function resizeWindow() {\
var elems = document.getElementsByTagName(\\\'*\\\'),\
width = 0,\
height = 0,\
first = document.body.firstChild,\
elem;\
if (first.offsetHeight && first.offsetWidth) {\
width = first.offsetWidth;\
height = first.offsetHeight;\
} else {\
for (var i in elems) {\
elem = elems[i];\
if (!elem.offsetWidth) {\
continue;\
}\
width = Math.max(elem.offsetWidth, width);\
height = Math.max(elem.offsetHeight, height);\
}\
}\
var ifr = parent.document.getElementById(\\\'' + id + '\\\');\
ifr.height = height;\
ifr.width = width;\
}\
</script>' +
'<body onload=\\\'resizeWindow()\\\'>\' + decodeURIComponent(\'' +
/*-- Content --*/
encodeURIComponent(html) +
'\') +\'</body></html>\'"></iframe>';
}
/*-- Public interface --*/
/**
* It creates a link without referrer.
*
* @public
* @param {string} url
* @param {string} innerHTML
* @param {object} [anchorParams]
* @param {object} [iframeAttributes]
* @return {string} html
*/
function linkHtml(url, innerHTML, anchorParams, iframeAttributes) {
var html,
urlRedirection = '';
innerHTML = innerHTML || false;
/*-- If there is no innerHTML use the url as innerHTML --*/
if (!innerHTML) {
innerHTML = url;
}
anchorParams = anchorParams || {};
/*-- Making sure there is a target attribute and the value isn't '_self' --*/
if (!('target' in anchorParams) || '_self' === anchorParams.target) {
/*-- Converting _self to _top else it would open in the iframe container --*/
anchorParams.target = '_top';
}
if (IE_GT_8) {
urlRedirection = URL_REDIRECTION;
}
html = '<a rel="noreferrer" href="' + urlRedirection + escapeDoubleQuotes(url) + '" ' + objectToHtmlAttributes(anchorParams) + '>' + innerHTML + '</a>';
return htmlString(html, iframeAttributes);
}
PUB.linkHtml = linkHtml;
/**
* It creates a link without referrer.
*
* @public
* @param {String} url
* @param {String} innerHTML
* @param {Object} [anchorParams]
* @param {object} [iframeAttributes]
* @return {Node}
*/
function linkNode(url, innerHTML, anchorParams, iframeAttributes) {
return htmlToNode(linkHtml(url, innerHTML, anchorParams, iframeAttributes));
}
PUB.linkNode = linkNode;
/**
* It displays an image without sending the referrer.
*
* @public
* @param {String} url
* @param {Object} [imgAttributesParam]
* @return {String} html
*/
function imageHtml(url, imgAttributesParam) {
var imgAttributes = imgAttributesParam || {},
/*-- Making sure this styles are applyed in the image but let the possibility to overwrite them --*/
defaultStyles = 'border:none; margin: 0; padding: 0';
if ('style' in imgAttributes) {
imgAttributes.style = defaultStyles + imgAttributes.style;
} else {
imgAttributes.style = defaultStyles;
}
return htmlString('<a rel="noreferrer" href="' + escapeDoubleQuotes(url) + '" target="_BLANK"><img src="' + escapeDoubleQuotes(url) + '" ' + objectToHtmlAttributes(imgAttributes) + '/></a>');
}
PUB.imageHtml = imageHtml;
/**
* It displays an image without sending the referrer.
*
* @public
* @param {string} url
* @param {object} [imgParams]
* @return {Node}
*/
function imageNode(url, imgParams) {
return htmlToNode(imageHtml(url, imgParams));
}
PUB.imageNode = imageNode;
/*-- Exposing the module interface --*/
return PUB;
})();