/* * fingerprintjs 0.5.4 - fast browser fingerprint library * https://github.com/valve/fingerprintjs * copyright (c) 2013 valentin vasilyev (valentin.vasilyev@outlook.com) * licensed under the mit (http://www.opensource.org/licenses/mit-license.php) license. * * this software is provided by the copyright holders and contributors "as is" * and any express or implied warranties, including, but not limited to, the * implied warranties of merchantability and fitness for a particular purpose * are disclaimed. in no event shall be liable for any * direct, indirect, incidental, special, exemplary, or consequential damages * (including, but not limited to, procurement of substitute goods or services; * loss of use, data, or profits; or business interruption) however caused and * on any theory of liability, whether in contract, strict liability, or tort * (including negligence or otherwise) arising in any way out of the use of * this software, even if advised of the possibility of such damage. */ ;(function (name, context, definition) { if (typeof module !== 'undefined' && module.exports) { module.exports = definition(); } else if (typeof define === 'function' && define.amd) { define(definition); } else { context[name] = definition(); } })('fingerprint', this, function () { 'use strict'; var fingerprint = function (options) { var nativeforeach, nativemap; nativeforeach = array.prototype.foreach; nativemap = array.prototype.map; this.each = function (obj, iterator, context) { if (obj === null) { return; } if (nativeforeach && obj.foreach === nativeforeach) { obj.foreach(iterator, context); } else if (obj.length === +obj.length) { for (var i = 0, l = obj.length; i < l; i++) { if (iterator.call(context, obj[i], i, obj) === {}) return; } } else { for (var key in obj) { if (obj.hasownproperty(key)) { if (iterator.call(context, obj[key], key, obj) === {}) return; } } } }; this.map = function(obj, iterator, context) { var results = []; // not using strict equality so that this acts as a // shortcut to checking for `null` and `undefined`. if (obj == null) return results; if (nativemap && obj.map === nativemap) return obj.map(iterator, context); this.each(obj, function(value, index, list) { results[results.length] = iterator.call(context, value, index, list); }); return results; }; if (typeof options == 'object'){ this.hasher = options.hasher; this.screen_resolution = options.screen_resolution; this.screen_orientation = options.screen_orientation; this.canvas = options.canvas; this.ie_activex = options.ie_activex; } else if(typeof options == 'function'){ this.hasher = options; } }; fingerprint.prototype = { get: function(){ var keys = []; keys.push(navigator.useragent); keys.push(navigator.language); keys.push(screen.colordepth); if (this.screen_resolution) { var resolution = this.getscreenresolution(); if (typeof resolution !== 'undefined'){ // headless browsers, such as phantomjs keys.push(this.getscreenresolution().join('x')); } } keys.push(new date().gettimezoneoffset()); keys.push(this.hassessionstorage()); keys.push(this.haslocalstorage()); keys.push(!!window.indexeddb); //body might not be defined at this point or removed programmatically if(document.body){ keys.push(typeof(document.body.addbehavior)); } else { keys.push(typeof undefined); } keys.push(typeof(window.opendatabase)); keys.push(navigator.cpuclass); keys.push(navigator.platform); keys.push(navigator.donottrack); keys.push(this.getpluginsstring()); if(this.canvas && this.iscanvassupported()){ keys.push(this.getcanvasfingerprint()); } if(this.hasher){ return this.hasher(keys.join('###'), 31); } else { return this.murmurhash3_32_gc(keys.join('###'), 31); } }, /** * js implementation of murmurhash3 (r136) (as of may 20, 2011) * * @author gary court * @see http://github.com/garycourt/murmurhash-js * @author austin appleby * @see http://sites.google.com/site/murmurhash/ * * @param {string} key ascii only * @param {number} seed positive integer only * @return {number} 32-bit positive integer hash */ murmurhash3_32_gc: function(key, seed) { var remainder, bytes, h1, h1b, c1, c2, k1, i; remainder = key.length & 3; // key.length % 4 bytes = key.length - remainder; h1 = seed; c1 = 0xcc9e2d51; c2 = 0x1b873593; i = 0; while (i < bytes) { k1 = ((key.charcodeat(i) & 0xff)) | ((key.charcodeat(++i) & 0xff) << 8) | ((key.charcodeat(++i) & 0xff) << 16) | ((key.charcodeat(++i) & 0xff) << 24); ++i; k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff; k1 = (k1 << 15) | (k1 >>> 17); k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff; h1 ^= k1; h1 = (h1 << 13) | (h1 >>> 19); h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff; h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16)); } k1 = 0; switch (remainder) { case 3: k1 ^= (key.charcodeat(i + 2) & 0xff) << 16; case 2: k1 ^= (key.charcodeat(i + 1) & 0xff) << 8; case 1: k1 ^= (key.charcodeat(i) & 0xff); k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff; k1 = (k1 << 15) | (k1 >>> 17); k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff; h1 ^= k1; } h1 ^= key.length; h1 ^= h1 >>> 16; h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff; h1 ^= h1 >>> 13; h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff; h1 ^= h1 >>> 16; return h1 >>> 0; }, // https://bugzilla.mozilla.org/show_bug.cgi?id=781447 haslocalstorage: function () { try{ return !!window.localstorage; } catch(e) { return true; // securityerror when referencing it means it exists } }, hassessionstorage: function () { try{ return !!window.sessionstorage; } catch(e) { return true; // securityerror when referencing it means it exists } }, iscanvassupported: function () { var elem = document.createelement('canvas'); return !!(elem.getcontext && elem.getcontext('2d')); }, isie: function () { if(navigator.appname === 'microsoft internet explorer') { return true; } else if(navigator.appname === 'netscape' && /trident/.test(navigator.useragent)){// ie 11 return true; } return false; }, getpluginsstring: function () { if(this.isie() && this.ie_activex){ return this.getiepluginsstring(); } else { return this.getregularpluginsstring(); } }, getregularpluginsstring: function () { return this.map(navigator.plugins, function (p) { var mimetypes = this.map(p, function(mt){ return [mt.type, mt.suffixes].join('~'); }).join(','); return [p.name, p.description, mimetypes].join('::'); }, this).join(';'); }, getiepluginsstring: function () { if(window.activexobject){ var names = ['shockwaveflash.shockwaveflash',//flash plugin 'acropdf.pdf', // adobe pdf reader 7+ 'pdf.pdfctrl', // adobe pdf reader 6 and earlier, brrr 'quicktime.quicktime', // quicktime // 5 versions of real players 'rmocx.realplayer g2 control', 'rmocx.realplayer g2 control.1', 'realplayer.realplayer(tm) activex control (32-bit)', 'realvideo.realvideo(tm) activex control (32-bit)', 'realplayer', 'swctl.swctl', // shockwave player 'wmplayer.ocx', // windows media player 'agcontrol.agcontrol', // silverlight 'skype.detection']; // starting to detect plugins in ie return this.map(names, function(name){ try{ new activexobject(name); return name; } catch(e){ return null; } }).join(';'); } else { return ""; // behavior prior version 0.5.0, not breaking backwards compat. } }, getscreenresolution: function () { var resolution; if(this.screen_orientation){ resolution = (screen.height > screen.width) ? [screen.height, screen.width] : [screen.width, screen.height]; }else{ resolution = [screen.height, screen.width]; } return resolution; }, getcanvasfingerprint: function () { var canvas = document.createelement('canvas'); var ctx = canvas.getcontext('2d'); // https://www.browserleaks.com/canvas#how-does-it-work var txt = 'http://valve.github.io'; ctx.textbaseline = "top"; ctx.font = "14px 'arial'"; ctx.textbaseline = "alphabetic"; ctx.fillstyle = "#f60"; ctx.fillrect(125,1,62,20); ctx.fillstyle = "#069"; ctx.filltext(txt, 2, 15); ctx.fillstyle = "rgba(102, 204, 0, 0.7)"; ctx.filltext(txt, 4, 17); return canvas.todataurl(); } }; return fingerprint; });