1/* 2* fingerprintJS 0.5.4 - Fast browser fingerprint library 3* https://github.com/Valve/fingerprintjs 4* Copyright (c) 2013 Valentin Vasilyev ([email protected]) 5* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. 6* 7* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 8* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 9* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 10* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 11* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 12* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 13* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 14* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 15* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 16* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 17*/ 18 19;(function (name, context, definition) { 20 if (typeof module !== 'undefined' && module.exports) { module.exports = definition(); } 21 else if (typeof define === 'function' && define.amd) { define(definition); } 22 else { context[name] = definition(); } 23})('Fingerprint', this, function () { 24 'use strict'; 25 26 var Fingerprint = function (options) { 27 var nativeForEach, nativeMap; 28 nativeForEach = Array.prototype.forEach; 29 nativeMap = Array.prototype.map; 30 31 this.each = function (obj, iterator, context) { 32 if (obj === null) { 33 return; 34 } 35 if (nativeForEach && obj.forEach === nativeForEach) { 36 obj.forEach(iterator, context); 37 } else if (obj.length === +obj.length) { 38 for (var i = 0, l = obj.length; i < l; i++) { 39 if (iterator.call(context, obj[i], i, obj) === {}) return; 40 } 41 } else { 42 for (var key in obj) { 43 if (obj.hasOwnProperty(key)) { 44 if (iterator.call(context, obj[key], key, obj) === {}) return; 45 } 46 } 47 } 48 }; 49 50 this.map = function(obj, iterator, context) { 51 var results = []; 52 // Not using strict equality so that this acts as a 53 // shortcut to checking for `null` and `undefined`. 54 if (obj == null) return results; 55 if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); 56 this.each(obj, function(value, index, list) { 57 results[results.length] = iterator.call(context, value, index, list); 58 }); 59 return results; 60 }; 61 62 if (typeof options == 'object'){ 63 this.hasher = options.hasher; 64 this.screen_resolution = options.screen_resolution; 65 this.screen_orientation = options.screen_orientation; 66 this.canvas = options.canvas; 67 this.ie_activex = options.ie_activex; 68 } else if(typeof options == 'function'){ 69 this.hasher = options; 70 } 71 }; 72 73 Fingerprint.prototype = { 74 get: function(){ 75 var keys = []; 76 keys.push(navigator.userAgent); 77 keys.push(navigator.language); 78 keys.push(screen.colorDepth); 79 if (this.screen_resolution) { 80 var resolution = this.getScreenResolution(); 81 if (typeof resolution !== 'undefined'){ // headless browsers, such as phantomjs 82 keys.push(this.getScreenResolution().join('x')); 83 } 84 } 85 keys.push(new Date().getTimezoneOffset()); 86 keys.push(this.hasSessionStorage()); 87 keys.push(this.hasLocalStorage()); 88 keys.push(!!window.indexedDB); 89 //body might not be defined at this point or removed programmatically 90 if(document.body){ 91 keys.push(typeof(document.body.addBehavior)); 92 } else { 93 keys.push(typeof undefined); 94 } 95 keys.push(typeof(window.openDatabase)); 96 keys.push(navigator.cpuClass); 97 keys.push(navigator.platform); 98 keys.push(navigator.doNotTrack); 99 keys.push(this.getPluginsString()); 100 if(this.canvas && this.isCanvasSupported()){ 101 keys.push(this.getCanvasFingerprint()); 102 } 103 if(this.hasher){ 104 return this.hasher(keys.join('###'), 31); 105 } else { 106 return this.murmurhash3_32_gc(keys.join('###'), 31); 107 } 108 }, 109 110 /** 111 * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011) 112 * 113 * @author <a href="mailto:[email protected]">Gary Court</a> 114 * @see http://github.com/garycourt/murmurhash-js 115 * @author <a href="mailto:[email protected]">Austin Appleby</a> 116 * @see http://sites.google.com/site/murmurhash/ 117 * 118 * @param {string} key ASCII only 119 * @param {number} seed Positive integer only 120 * @return {number} 32-bit positive integer hash 121 */ 122 123 murmurhash3_32_gc: function(key, seed) { 124 var remainder, bytes, h1, h1b, c1, c2, k1, i; 125 126 remainder = key.length & 3; // key.length % 4 127 bytes = key.length - remainder; 128 h1 = seed; 129 c1 = 0xcc9e2d51; 130 c2 = 0x1b873593; 131 i = 0; 132 133 while (i < bytes) {
134 k1 = 135 ((key.charCodeAt(i) & 0xff)) | 136 ((key.charCodeAt(++i) & 0xff) << 8) | 137 ((key.charCodeAt(++i) & 0xff) << 16) | 138 ((key.charCodeAt(++i) & 0xff) << 24); 139 ++i; 140 141 k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff; 142 k1 = (k1 << 15) | (k1 >>> 17); 143 k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff; 144 145 h1 ^= k1; 146 h1 = (h1 << 13) | (h1 >>> 19); 147 h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff; 148 h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16)); 149 } 150 151 k1 = 0; 152 153 switch (remainder) { 154 case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16; 155 case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8; 156 case 1: k1 ^= (key.charCodeAt(i) & 0xff); 157 158 k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff; 159 k1 = (k1 << 15) | (k1 >>> 17); 160 k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff; 161 h1 ^= k1; 162 } 163 164 h1 ^= key.length; 165 166 h1 ^= h1 >>> 16; 167 h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff; 168 h1 ^= h1 >>> 13; 169 h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff; 170 h1 ^= h1 >>> 16; 171 172 return h1 >>> 0; 173 }, 174 175 // https://bugzilla.mozilla.org/show_bug.cgi?id=781447 176 hasLocalStorage: function () { 177 try{ 178 return !!window.localStorage; 179 } catch(e) { 180 return true; // SecurityError when referencing it means it exists 181 } 182 }, 183 184 hasSessionStorage: function () { 185 try{ 186 return !!window.sessionStorage; 187 } catch(e) { 188 return true; // SecurityError when referencing it means it exists 189 } 190 }, 191 192 isCanvasSupported: function () { 193 var elem = document.createElement('canvas'); 194 return !!(elem.getContext && elem.getContext('2d')); 195 }, 196 197 isIE: function () { 198 if(navigator.appName === 'Microsoft Internet Explorer') { 199 return true; 200 } else if(navigator.appName === 'Netscape' && /Trident/.test(navigator.userAgent)){// IE 11 201 return true; 202 } 203 return false; 204 }, 205 206 getPluginsString: function () { 207 if(this.isIE() && this.ie_activex){ 208 return this.getIEPluginsString(); 209 } else { 210 return this.getRegularPluginsString(); 211 } 212 }, 213 214 getRegularPluginsString: function () { 215 return this.map(navigator.plugins, function (p) { 216 var mimeTypes = this.map(p, function(mt){ 217 return [mt.type, mt.suffixes].join('~'); 218 }).join(','); 219 return [p.name, p.description, mimeTypes].join('::'); 220 }, this).join(';'); 221 }, 222 223 getIEPluginsString: function () { 224 if(window.ActiveXObject){ 225 var names = ['ShockwaveFlash.ShockwaveFlash',//flash plugin 226 'AcroPDF.PDF', // Adobe PDF reader 7+ 227 'PDF.PdfCtrl', // Adobe PDF reader 6 and earlier, brrr 228 'QuickTime.QuickTime', // QuickTime 229 // 5 versions of real players 230 'rmocx.RealPlayer G2 Control', 231 'rmocx.RealPlayer G2 Control.1', 232 'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)', 233 'RealVideo.RealVideo(tm) ActiveX Control (32-bit)', 234 'RealPlayer', 235 'SWCtl.SWCtl', // ShockWave player 236 'WMPlayer.OCX', // Windows media player 237 'AgControl.AgControl', // Silverlight 238 'Skype.Detection']; 239 240 // starting to detect plugins in IE 241 return this.map(names, function(name){ 242 try{ 243 new ActiveXObject(name); 244 return name; 245 } catch(e){ 246 return null; 247 } 248 }).join(';'); 249 } else { 250 return ""; // behavior prior version 0.5.0, not breaking backwards compat. 251 } 252 }, 253 254 getScreenResolution: function () { 255 var resolution; 256 if(this.screen_orientation){ 257 resolution = (screen.height > screen.width) ? [screen.height, screen.width] : [screen.width, screen.height]; 258 }else{ 259 resolution = [screen.height, screen.width]; 260 } 261 return resolution; 262 }, 263 264 getCanvasFingerprint: function () { 265 var canvas = document.createElement('canvas'); 266 var ctx = canvas.getContext('2d'); 267 // https://www.browserleaks.com/canvas#how-does-it-work 268 var txt = 'http://valve.github.io'; 269 ctx.textBaseline = "top"; 270 ctx.font = "14px 'Arial'"; 271 ctx.textBaseline = "alphabetic"; 272 ctx.fillStyle = "#f60"; 273 ctx.fillRect(125,1,62,20); 274 ctx.fillStyle = "#069"; 275 ctx.fillText(txt, 2, 15); 276 ctx.fillStyle = "rgba(102, 204, 0, 0.7)"; 277 ctx.fillText(txt, 4, 17); 278 return canvas.toDataURL(); 279 } 280 }; 281 282 283 return Fingerprint; 284 285});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.