vendor: 6,726 bytes, lines 1-166
1// *********************************************************************** 2 3/* 4* Fingerprintjs2 2.0.5 - Modern & flexible browser fingerprint library v2 5* https://github.com/Valve/fingerprintjs2 6* Copyright (c) 2015 Valentin Vasilyev ([email protected]) 7* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. 8* 9* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 10* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 11* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 12* ARE DISCLAIMED. IN NO EVENT SHALL VALENTIN VASILYEV BE LIABLE FOR ANY 13* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 14* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 15* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 16* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 17* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 18* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19*/ 20/* global define */ 21(function (name, context, definition) { 22 'use strict' 23 if (typeof window !== 'undefined' && typeof define === 'function' && define.amd) { define(definition) } else if (typeof module !== 'undefined' && module.exports) { module.exports = definition() } else if (context.exports) { context.exports = definition() } else { context[name] = definition() } 24 })('Fingerprint2', this, function () { 25 'use strict' 26 /// MurmurHash3 related functions 27 // 28 // Given two 64bit ints (as an array of two 32bit ints) returns the two 29 // added together as a 64bit int (as an array of two 32bit ints). 30 // 31 var x64Add = function (m, n) { 32 m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff] 33 n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff] 34 var o = [0, 0, 0, 0] 35 o[3] += m[3] + n[3] 36 o[2] += o[3] >>> 16 37 o[3] &= 0xffff 38 o[2] += m[2] + n[2] 39 o[1] += o[2] >>> 16 40 o[2] &= 0xffff 41 o[1] += m[1] + n[1] 42 o[0] += o[1] >>> 16 43 o[1] &= 0xffff 44 o[0] += m[0] + n[0] 45 o[0] &= 0xffff 46 return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]] 47 } 48 // 49 // Given two 64bit ints (as an array of two 32bit ints) returns the two 50 // multiplied together as a 64bit int (as an array of two 32bit ints). 51 // 52 var x64Multiply = function (m, n) { 53 m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff] 54 n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff] 55 var o = [0, 0, 0, 0] 56 o[3] += m[3] * n[3] 57 o[2] += o[3] >>> 16 58 o[3] &= 0xffff 59 o[2] += m[2] * n[3] 60 o[1] += o[2] >>> 16 61 o[2] &= 0xffff 62 o[2] += m[3] * n[2] 63 o[1] += o[2] >>> 16 64 o[2] &= 0xffff 65 o[1] += m[1] * n[3] 66 o[0] += o[1] >>> 16 67 o[1] &= 0xffff 68 o[1] += m[2] * n[2] 69 o[0] += o[1] >>> 16 70 o[1] &= 0xffff 71 o[1] += m[3] * n[1] 72 o[0] += o[1] >>> 16 73 o[1] &= 0xffff 74 o[0] += (m[0] * n[3]) + (m[1] * n[2]) + (m[2] * n[1]) + (m[3] * n[0]) 75 o[0] &= 0xffff 76 return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]] 77 } 78 // 79 // Given a 64bit int (as an array of two 32bit ints) and an int 80 // representing a number of bit positions, returns the 64bit int (as an 81 // array of two 32bit ints) rotated left by that number of positions. 82 // 83 var x64Rotl = function (m, n) { 84 n %= 64 85 if (n === 32) { 86 return [m[1], m[0]] 87 } else if (n < 32) { 88 return [(m[0] << n) | (m[1] >>> (32 - n)), (m[1] << n) | (m[0] >>> (32 - n))] 89 } else { 90 n -= 32 91 return [(m[1] << n) | (m[0] >>> (32 - n)), (m[0] << n) | (m[1] >>> (32 - n))] 92 } 93 } 94 // 95 // Given a 64bit int (as an array of two 32bit ints) and an int 96 // representing a number of bit positions, returns the 64bit int (as an 97 // array of two 32bit ints) shifted left by that number of positions. 98 // 99 var x64LeftShift = function (m, n) { 100 n %= 64 101 if (n === 0) { 102 return m 103 } else if (n < 32) { 104 return [(m[0] << n) | (m[1] >>> (32 - n)), m[1] << n] 105 } else { 106 return [m[1] << (n - 32), 0] 107 } 108 } 109 // 110 // Given two 64bit ints (as an array of two 32bit ints) returns the two 111 // xored together as a 64bit int (as an array of two 32bit ints). 112 // 113 var x64Xor = function (m, n) { 114 return [m[0] ^ n[0], m[1] ^ n[1]] 115 } 116 // 117 // Given a block, returns murmurHash3's final x64 mix of that block. 118 // (`[0, h[0] >>> 1]` is a 33 bit unsigned right shift. This is the 119 // only place where we need to right shift 64bit ints.) 120 // 121 var x64Fmix = function (h) { 122 h = x64Xor(h, [0, h[0] >>> 1]) 123 h = x64Multiply(h, [0xff51afd7, 0xed558ccd]) 124 h = x64Xor(h, [0, h[0] >>> 1]) 125 h = x64Multiply(h, [0xc4ceb9fe, 0x1a85ec53]) 126 h = x64Xor(h, [0, h[0] >>> 1]) 127 return h 128 } 129 130 // 131 // Given a string and an optional seed as an int, returns a 128 bit 132 // hash using the x64 flavor of MurmurHash3, as an unsigned hex. 133 // 134 var x64hash128 = function (key, seed) { 135 key = key || '' 136 seed = seed || 0 137 var remainder = key.length % 16 138 var bytes = key.length - remainder 139 var h1 = [0, seed] 140 var h2 = [0, seed] 141 var k1 = [0, 0] 142 var k2 = [0, 0] 143 var c1 = [0x87c37b91, 0x114253d5] 144 var c2 = [0x4cf5ad43, 0x2745937f] 145 for (var i = 0; i < bytes; i = i + 16) { 146 k1 = [((key.charCodeAt(i + 4) & 0xff)) | ((key.charCodeAt(i + 5) & 0xff) << 8) | ((key.charCodeAt(i + 6) & 0xff) << 16) | ((key.charCodeAt(i + 7) & 0xff) << 24), ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(i + 1) & 0xff) << 8) | ((key.charCodeAt(i + 2) & 0xff) << 16) | ((key.charCodeAt(i + 3) & 0xff) << 24)] 147 k2 = [((key.charCodeAt(i + 12) & 0xff)) | ((key.charCodeAt(i + 13) & 0xff) << 8) | ((key.charCodeAt(i + 14) & 0xff) << 16) | ((key.charCodeAt(i + 15) & 0xff) << 24), ((key.charCodeAt(i + 8) & 0xff)) | ((key.charCodeAt(i + 9) & 0xff) << 8) | ((key.charCodeAt(i + 10) & 0xff) << 16) | ((key.charCodeAt(i + 11) & 0xff) << 24)] 148 k1 = x64Multiply(k1, c1) 149 k1 = x64Rotl(k1, 31) 150 k1 = x64Multiply(k1, c2) 151 h1 = x64Xor(h1, k1) 152 h1 = x64Rotl(h1, 27) 153 h1 = x64Add(h1, h2) 154 h1 = x64Add(x64Multiply(h1, [0, 5]), [0, 0x52dce729]) 155 k2 = x64Multiply(k2, c2) 156 k2 = x64Rotl(k2, 33) 157 k2 = x64Multiply(k2, c1) 158 h2 = x64Xor(h2, k2) 159 h2 = x64Rotl(h2, 31) 160 h2 = x64Add(h2, h1) 161 h2 = x64Add(x64Multiply(h2, [0, 5]), [0, 0x38495ab5]) 162 } 163 k1 = [0, 0] 164 k2 = [0, 0] 165 switch (remainder) { 166 case 15:
167 k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 14)], 48)) 168 // fallthrough 169 case 14: 170 k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 13)], 40)) 171 // fallthrough 172 case 13: 173 k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 12)], 32)) 174 // fallthrough 175 case 12: 176 k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 11)], 24)) 177 // fallthrough 178 case 11: 179 k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 10)], 16)) 180 // fallthrough 181 case 10: 182 k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 9)], 8)) 183 // fallthrough 184 case 9: 185 k2 = x64Xor(k2, [0, key.charCodeAt(i + 8)]) 186 k2 = x64Multiply(k2, c2) 187 k2 = x64Rotl(k2, 33) 188 k2 = x64Multiply(k2, c1) 189 h2 = x64Xor(h2, k2) 190 // fallthrough 191 case 8: 192 k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 7)], 56)) 193 // fallthrough 194 case 7: 195 k1 = x64Xor(k1, x64LeftShift([0, key.charCo
vendor: 15,720 bytes, lines 195-556
195deAt(i + 6)], 48)) 196 // fallthrough 197 case 6: 198 k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 5)], 40)) 199 // fallthrough 200 case 5: 201 k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 4)], 32)) 202 // fallthrough 203 case 4: 204 k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 3)], 24)) 205 // fallthrough 206 case 3: 207 k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 2)], 16)) 208 // fallthrough 209 case 2: 210 k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 1)], 8)) 211 // fallthrough 212 case 1: 213 k1 = x64Xor(k1, [0, key.charCodeAt(i)]) 214 k1 = x64Multiply(k1, c1) 215 k1 = x64Rotl(k1, 31) 216 k1 = x64Multiply(k1, c2) 217 h1 = x64Xor(h1, k1) 218 // fallthrough 219 } 220 h1 = x64Xor(h1, [0, key.length]) 221 h2 = x64Xor(h2, [0, key.length]) 222 h1 = x64Add(h1, h2) 223 h2 = x64Add(h2, h1) 224 h1 = x64Fmix(h1) 225 h2 = x64Fmix(h2) 226 h1 = x64Add(h1, h2) 227 h2 = x64Add(h2, h1) 228 return ('00000000' + (h1[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h1[1] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[1] >>> 0).toString(16)).slice(-8) 229 } 230 231 var defaultOptions = { 232 preprocessor: null, 233 audio: { 234 timeout: 1000, 235 // On iOS 11, audio context can only be used in response to user interaction. 236 // We require users to explicitly enable audio fingerprinting on iOS 11. 237 // See https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088 238 excludeIOS11: true 239 }, 240 fonts: { 241 swfContainerId: 'fingerprintjs2', 242 swfPath: 'flash/compiled/FontList.swf', 243 userDefinedFonts: [], 244 extendedJsFonts: false 245 }, 246 screen: { 247 // To ensure consistent fingerprints when users rotate their mobile devices 248 detectScreenOrientation: true 249 }, 250 plugins: { 251 sortPluginsFor: [/palemoon/i], 252 excludeIE: false 253 }, 254 extraComponents: [], 255 excludes: { 256 // Unreliable on Windows, see https://github.com/Valve/fingerprintjs2/issues/375 257 'enumerateDevices': true, 258 // devicePixelRatio depends on browser zoom, and it's impossible to detect browser zoom 259 'pixelRatio': true, 260 // DNT depends on incognito mode for some browsers (Chrome) and it's impossible to detect incognito mode 261 'doNotTrack': true, 262 // uses js fonts already 263 'fontsFlash': true 264 }, 265 NOT_AVAILABLE: 'not available', 266 ERROR: 'error', 267 EXCLUDED: 'excluded' 268 } 269 270 var each = function (obj, iterator) { 271 if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) { 272 obj.forEach(iterator) 273 } else if (obj.length === +obj.length) { 274 for (var i = 0, l = obj.length; i < l; i++) { 275 iterator(obj[i], i, obj) 276 } 277 } else { 278 for (var key in obj) { 279 if (obj.hasOwnProperty(key)) { 280 iterator(obj[key], key, obj) 281 } 282 } 283 } 284 } 285 286 var map = function (obj, iterator) { 287 var results = [] 288 // Not using strict equality so that this acts as a 289 // shortcut to checking for `null` and `undefined`. 290 if (obj == null) { 291 return results 292 } 293 if (Array.prototype.map && obj.map === Array.prototype.map) { return obj.map(iterator) } 294 each(obj, function (value, index, list) { 295 results.push(iterator(value, index, list)) 296 }) 297 return results 298 } 299 300 var extendSoft = function (target, source) { 301 if (source == null) { return target } 302 var value 303 var key 304 for (key in source) { 305 value = source[key] 306 if (value != null && !(Object.prototype.hasOwnProperty.call(target, key))) { 307 target[key] = value 308 } 309 } 310 return target 311 } 312 313 // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices 314 var enumerateDevicesKey = function (done, options) { 315 if (!isEnumerateDevicesSupported()) { 316 return done(options.NOT_AVAILABLE) 317 } 318 navigator.mediaDevices.enumerateDevices().then(function (devices) { 319 done(devices.map(function (device) { 320 return 'id=' + device.deviceId + ';gid=' + device.groupId + ';' + device.kind + ';' + device.label 321 })) 322 }) 323 .catch(function (error) { 324 done(error) 325 }) 326 } 327 328 var isEnumerateDevicesSupported = function () { 329 return (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) 330 } 331 // Inspired by and based on https://github.com/cozylife/audio-fingerprint 332 var audioKey = function (done, options) { 333 var audioOptions = options.audio 334 if (audioOptions.excludeIOS11 && navigator.userAgent.match(/OS 11.+Version\/11.+Safari/)) { 335 // See comment for excludeUserAgent and https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088 336 return done(options.EXCLUDED) 337 } 338 339 var AudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext 340 341 if (AudioContext == null) { 342 return done(options.NOT_AVAILABLE) 343 } 344 345 var context = new AudioContext(1, 44100, 44100) 346 347 var oscillator = context.createOscillator() 348 oscillator.type = 'triangle' 349 oscillator.frequency.setValueAtTime(10000, context.currentTime) 350 351 var compressor = context.createDynamicsCompressor() 352 each([ 353 ['threshold', -50], 354 ['knee', 40], 355 ['ratio', 12], 356 ['reduction', -20], 357 ['attack', 0], 358 ['release', 0.25] 359 ], function (item) { 360 if (compressor[item[0]] !== undefined && typeof compressor[item[0]].setValueAtTime === 'function') { 361 compressor[item[0]].setValueAtTime(item[1], context.currentTime) 362 } 363 }) 364 365 oscillator.connect(compressor) 366 compressor.connect(context.destination) 367 oscillator.start(0) 368 context.startRendering() 369 370 var audioTimeoutId = setTimeout(function () { 371 console.warn('Audio fingerprint timed out. Please report bug at https://github.com/Valve/fingerprintjs2 with your user agent: "' + navigator.userAgent + '".') 372 context.oncomplete = function () {} 373 context = null 374 return done('audioTimeout') 375 }, audioOptions.timeout) 376 377 context.oncomplete = function (event) { 378 var fingerprint 379 try { 380 clearTimeout(audioTimeoutId) 381 fingerprint = event.renderedBuffer.getChannelData(0) 382 .slice(4500, 5000) 383 .reduce(function (acc, val) { return acc + Math.abs(val) }, 0) 384 .toString() 385 oscillator.disconnect() 386 compressor.disconnect() 387 } catch (error) { 388 done(error) 389 return 390 } 391 done(fingerprint) 392 } 393 } 394 var UserAgent = function (done) { 395 done(navigator.userAgent) 396 } 397 var languageKey = function (done, options) { 398 done(navigator.language || navigator.userLanguage || navigator.browserLanguage || navigator.systemLanguage || options.NOT_AVAILABLE) 399 } 400 var colorDepthKey = function (done, options) { 401 done(window.screen.colorDepth || options.NOT_AVAILABLE) 402 } 403 var deviceMemoryKey = function (done, options) { 404 done(navigator.deviceMemory || options.NOT_AVAILABLE) 405 } 406 var pixelRatioKey = function (done, options) { 407 done(window.devicePixelRatio || options.NOT_AVAILABLE) 408 } 409 var screenResolutionKey = function (done, options) { 410 done(getScreenResolution(options)) 411 } 412 var getScreenResolution = function (options) { 413 var resolution = [window.screen.width, window.screen.height] 414 if (options.screen.detectScreenOrientation) { 415 resolution.sort().reverse() 416 } 417 return resolution 418 } 419 var availableScreenResolutionKey = function (done, options) { 420 done(getAvailableScreenResolution(options)) 421 } 422 var getAvailableScreenResolution = function (options) { 423 if (window.screen.availWidth && window.screen.availHeight) { 424 var available = [window.screen.availHeight, window.screen.availWidth] 425 if (options.screen.detectScreenOrientation) { 426 available.sort().reverse() 427 } 428 return available 429 } 430 // headless browsers 431 return options.NOT_AVAILABLE 432 } 433 var timezoneOffset = function (done) { 434 done(new Date().getTimezoneOffset()) 435 } 436 var timezone = function (done, options) { 437 if (window.Intl && window.Intl.DateTimeFormat) { 438 done(new window.Intl.DateTimeFormat().resolvedOptions().timeZone) 439 return 440 } 441 done(options.NOT_AVAILABLE) 442 } 443 var sessionStorageKey = function (done, options) { 444 done(hasSessionStorage(options)) 445 } 446 var localStorageKey = function (done, options) { 447 done(hasLocalStorage(options)) 448 } 449 var indexedDbKey = function (done, options) { 450 done(hasIndexedDB(options)) 451 } 452 var addBehaviorKey = function (done) { 453 // body might not be defined at this point or removed programmatically 454 done(!!(document.body && document.body.addBehavior)) 455 } 456 var openDatabaseKey = function (done) { 457 done(!!window.openDatabase) 458 } 459 var cpuClassKey = function (done, options) { 460 done(getNavigatorCpuClass(options)) 461 } 462 var platformKey = function (done, options) { 463 done(getNavigatorPlatform(options)) 464 } 465 var doNotTrackKey = function (done, options) { 466 done(getDoNotTrack(options)) 467 } 468 var canvasKey = function (done, options) { 469 if (isCanvasSupported()) { 470 done(getCanvasFp(options)) 471 return 472 } 473 done(options.NOT_AVAILABLE) 474 } 475 var webglKey = function (done, options) { 476 if (isWebGlSupported()) { 477 done(getWebglFp()) 478 return 479 } 480 done(options.NOT_AVAILABLE) 481 } 482 var webglVendorAndRendererKey = function (done) { 483 if (isWebGlSupported()) { 484 done(getWebglVendorAndRenderer()) 485 return 486 } 487 done() 488 } 489 var adBlockKey = function (done) { 490 done(getAdBlock()) 491 } 492 var hasLiedLanguagesKey = function (done) { 493 done(getHasLiedLanguages()) 494 } 495 var hasLiedResolutionKey = function (done) { 496 done(getHasLiedResolution()) 497 } 498 var hasLiedOsKey = function (done) { 499 done(getHasLiedOs()) 500 } 501 var hasLiedBrowserKey = function (done) { 502 done(getHasLiedBrowser()) 503 } 504 // flash fonts (will increase fingerprinting time 20X to ~ 130-150ms) 505 var flashFontsKey = function (done, options) { 506 // we do flash if swfobject is loaded 507 if (!hasSwfObjectLoaded()) { 508 return done('swf object not loaded') 509 } 510 if (!hasMinFlashInstalled()) { 511 return done('flash not installed') 512 } 513 if (!options.fonts.swfPath) { 514 return done('missing options.fonts.swfPath') 515 } 516 loadSwfAndDetectFonts(function (fonts) { 517 done(fonts) 518 }, options) 519 } 520 // kudos to http://www.lalit.org/lab/javascript-css-font-detect/ 521 var jsFontsKey = function (done, options) { 522 // a font will be compared against all the three default fonts. 523 // and if it doesn't match all 3 then that font is not available. 524 var baseFonts = ['monospace', 'sans-serif', 'serif'] 525 526 var fontList = [ 527 'Andale Mono', 'Arial', 'Arial Black', 'Arial Hebrew', 'Arial MT', 'Arial Narrow', 'Arial Rounded MT Bold', 'Arial Unicode MS', 528 'Bitstream Vera Sans Mono', 'Book Antiqua', 'Bookman Old Style', 529 'Calibri', 'Cambria', 'Cambria Math', 'Century', 'Century Gothic', 'Century Schoolbook', 'Comic Sans', 'Comic Sans MS', 'Consolas', 'Courier', 'Courier New', 530 'Geneva', 'Georgia', 531 'Helvetica', 'Helvetica Neue', 532 'Impact', 533 'Lucida Bright', 'Lucida Calligraphy', 'Lucida Console', 'Lucida Fax', 'LUCIDA GRANDE', 'Lucida Handwriting', 'Lucida Sans', 'Lucida Sans Typewriter', 'Lucida Sans Unicode', 534 'Microsoft Sans Serif', 'Monaco', 'Monotype Corsiva', 'MS Gothic', 'MS Outlook', 'MS PGothic', 'MS Reference Sans Serif', 'MS Sans Serif', 'MS Serif', 'MYRIAD', 'MYRIAD PRO', 535 'Palatino', 'Palatino Linotype', 536 'Segoe Print', 'Segoe Script', 'Segoe UI', 'Segoe UI Light', 'Segoe UI Semibold', 'Segoe UI Symbol', 537 'Tahoma', 'Times', 'Times New Roman', 'Times New Roman PS', 'Trebuchet MS', 538 'Verdana', 'Wingdings', 'Wingdings 2', 'Wingdings 3' 539 ] 540 541 if (options.fonts.extendedJsFonts) { 542 var extendedFontList = [ 543 'Abadi MT Condensed Light', 'Academy Engraved LET', 'ADOBE CASLON PRO', 'Adobe Garamond', 'ADOBE GARAMOND PRO', 'Agency FB', 'Aharoni', 'Albertus Extra Bold', 'Albertus Medium', 'Algerian', 'Amazone BT', 'American Typewriter', 544 'American Typewriter Condensed', 'AmerType Md BT', 'Andalus', 'Angsana New', 'AngsanaUPC', 'Antique Olive', 'Aparajita', 'Apple Chancery', 'Apple Color Emoji', 'Apple SD Gothic Neo', 'Arabic Typesetting', 'ARCHER', 545 'ARNO PRO', 'Arrus BT', 'Aurora Cn BT', 'AvantGarde Bk BT', 'AvantGarde Md BT', 'AVENIR', 'Ayuthaya', 'Bandy', 'Bangla Sangam MN', 'Bank Gothic', 'BankGothic Md BT', 'Baskerville', 546 'Baskerville Old Face', 'Batang', 'BatangChe', 'Bauer Bodoni', 'Bauhaus 93', 'Bazooka', 'Bell MT', 'Bembo', 'Benguiat Bk BT', 'Berlin Sans FB', 'Berlin Sans FB Demi', 'Bernard MT Condensed', 'BernhardFashion BT', 'BernhardMod BT', 'Big Caslon', 'BinnerD', 547 'Blackadder ITC', 'BlairMdITC TT', 'Bodoni 72', 'Bodoni 72 Oldstyle', 'Bodoni 72 Smallcaps', 'Bodoni MT', 'Bodoni MT Black', 'Bodoni MT Condensed', 'Bodoni MT Poster Compressed', 548 'Bookshelf Symbol 7', 'Boulder', 'Bradley Hand', 'Bradley Hand ITC', 'Bremen Bd BT', 'Britannic Bold', 'Broadway', 'Browallia New', 'BrowalliaUPC', 'Brush Script MT', 'Californian FB', 'Calisto MT', 'Calligrapher', 'Candara', 549 'CaslonOpnface BT', 'Castellar', 'Centaur', 'Cezanne', 'CG Omega', 'CG Times', 'Chalkboard', 'Chalkboard SE', 'Chalkduster', 'Charlesworth', 'Charter Bd BT', 'Charter BT', 'Chaucer', 550 'ChelthmITC Bk BT', 'Chiller', 'Clarendon', 'Clarendon Condensed', 'CloisterBlack BT', 'Cochin', 'Colonna MT', 'Constantia', 'Cooper Black', 'Copperplate', 'Copperplate Gothic', 'Copperplate Gothic Bold', 551 'Copperplate Gothic Light', 'CopperplGoth Bd BT', 'Corbel', 'Cordia New', 'CordiaUPC', 'Cornerstone', 'Coronet', 'Cuckoo', 'Curlz MT', 'DaunPenh', 'Dauphin', 'David', 'DB LCD Temp', 'DELICIOUS', 'Denmark', 552 'DFKai-SB', 'Didot', 'DilleniaUPC', 'DIN', 'DokChampa', 'Dotum', 'DotumChe', 'Ebrima', 'Edwardian Script ITC', 'Elephant', 'English 111 Vivace BT', 'Engravers MT', 'EngraversGothic BT', 'Eras Bold ITC', 'Eras Demi ITC', 'Eras Light ITC', 'Eras Medium ITC', 553 'EucrosiaUPC', 'Euphemia', 'Euphemia UCAS', 'EUROSTILE', 'Exotc350 Bd BT', 'FangSong', 'Felix Titling', 'Fixedsys', 'FONTIN', 'Footlight MT Light', 'Forte', 554 'FrankRuehl', 'Fransiscan', 'Freefrm721 Blk BT', 'FreesiaUPC', 'Freestyle Script', 'French Script MT', 'FrnkGothITC Bk BT', 'Fruitger', 'FRUTIGER', 555 'Futura', 'Futura Bk BT', 'Futura Lt BT', 'Futura Md BT', 'Futura ZBlk BT', 'FuturaBlack BT', 'Gabriola', 'Galliard BT', 'Gautami', 'Geeza Pro', 'Geometr231 BT', 'Geometr231 Hv BT', 'Geometr231 Lt BT', 'GeoSlab 703 Lt BT', 556 'GeoSlab 703 XBd BT', 'Gigi', 'Gill Sans', 'Gill Sans MT', 'Gill Sans MT Condensed', 'Gill Sans MT Ext Condensed Bold', 'Gill Sans Ultra Bold', 'Gill Sans Ultra Bold Condensed', 'Gisha', 'Gloucester MT Extra Condensed', 'GOTHAM', 'GOTHAM BOLD',
557 'Goudy Old Style', 'Goudy Stout', 'GoudyHandtooled BT', 'GoudyOLSt BT', 'Gujarati Sangam MN', 'Gulim', 'GulimChe', 'Gungsuh', 'GungsuhChe', 'Gurmukhi MN', 'Haettenschweiler', 'Harlow Solid Italic', 'Harrington', 'Heather', 'Heiti SC', 'Heiti TC', 'HELV', 558 'Herald', 'High Tower Text', 'Hiragino Kaku Gothic ProN', 'Hiragino Mincho ProN', 'Hoefler Text', 'Humanst 521 Cn BT', 'Humanst521 BT', 'Humanst521 Lt BT', 'Imprint MT Shadow', 'Incised901 Bd BT', 'Incised901 BT', 559 'Incised901 Lt BT', 'INCONSOLATA', 'Informal Roman', 'Informal011 BT', 'INTERSTATE', 'IrisUPC', 'Iskoola Pota', 'JasmineUPC', 'Jazz LET', 'Jenson', 'Jester', 'Jokerman', 'Juice ITC', 'Kabel Bk BT', 'Kabel Ult BT', 'Kailasa', 'KaiTi', 'Kalinga', 'Kannada Sangam MN', 560 'Kartika', 'Kaufmann Bd BT', 'Kaufmann BT', 'Khmer UI', 'KodchiangUPC', 'Kokila', 'Korinna BT', 'Kristen ITC', 'Krungthep', 'Kunstler Script', 'Lao UI', 'Latha', 'Leelawadee', 'Letter Gothic', 'Levenim MT', 'LilyUPC', 'Lithograph', 'Lithograph Light', 'Long Island', 561 'Lydian BT', 'Magneto', 'Maiandra GD', 'Malayalam Sangam MN', 'Malgun Gothic', 562 'Mangal', 'Marigold', 'Marion', 'Marker Felt', 'Market', 'Marlett', 'Matisse ITC', 'Matura MT Script Capitals', 'Meiryo', 'Meiryo UI', 'Microsoft Himalaya', 'Microsoft JhengHei', 'Microsoft New Tai Lue', 'Microsoft PhagsPa', 'Microsoft Tai Le', 563 'Microsoft Uighur', 'Microsoft YaHei', 'Microsoft Yi Baiti', 'MingLiU', 'MingLiU_HKSCS', 'MingLiU_HKSCS-ExtB', 'MingLiU-ExtB', 'Minion', 'Minion Pro', 'Miriam', 'Miriam Fixed', 'Mistral', 'Modern', 'Modern No. 20', 'Mona Lisa Solid ITC TT', 'Mongolian Baiti', 564 'MONO', 'MoolBoran', 'Mrs Eaves', 'MS LineDraw', 'MS Mincho', 'MS PMincho', 'MS Reference Specialty', 'MS UI Gothic', 'MT Extra', 'MUSEO', 'MV Boli', 565 'Nadeem', 'Narkisim', 'NEVIS', 'News Gothic', 'News GothicMT', 'NewsGoth BT', 'Niagara Engraved', 'Niagara Solid', 'Noteworthy', 'NSimSun', 'Nyala', 'OCR A Extended', 'Old Century', 'Old English Text MT', 'Onyx', 'Onyx BT', 'OPTIMA', 'Oriya Sangam MN', 566 'OSAKA', 'OzHandicraft BT', 'Palace Script MT', 'Papyrus', 'Parchment', 'Party LET', 'Pegasus', 'Perpetua', 'Perpetua Titling MT', 'PetitaBold', 'Pickwick', 'Plantagenet Cherokee', 'Playbill', 'PMingLiU', 'PMingLiU-ExtB', 567 'Poor Richard', 'Poster', 'PosterBodoni BT', 'PRINCETOWN LET', 'Pristina', 'PTBarnum BT', 'Pythagoras', 'Raavi', 'Rage Italic', 'Ravie', 'Ribbon131 Bd BT', 'Rockwell', 'Rockwell Condensed', 'Rockwell Extra Bold', 'Rod', 'Roman', 'Sakkal Majalla', 568 'Santa Fe LET', 'Savoye LET', 'Sceptre', 'Script', 'Script MT Bold', 'SCRIPTINA', 'Serifa', 'Serifa BT', 'Serifa Th BT', 'ShelleyVolante BT', 'Sherwood', 569 'Shonar Bangla', 'Showcard Gothic', 'Shruti', 'Signboard', 'SILKSCREEN', 'SimHei', 'Simplified Arabic', 'Simplified Arabic Fixed', 'SimSun', 'SimSun-ExtB', 'Sinhala Sangam MN', 'Sketch Rockwell', 'Skia', 'Small Fonts', 'Snap ITC', 'Snell Roundhand', 'Socket', 570 'Souvenir Lt BT', 'Staccato222 BT', 'Steamer', 'Stencil', 'Storybook', 'Styllo', 'Subway', 'Swis721 BlkEx BT', 'Swiss911 XCm BT', 'Sylfaen', 'Synchro LET', 'System', 'Tamil Sangam MN', 'Technical', 'Teletype', 'Telugu Sangam MN', 'Tempus Sans ITC', 571 'Terminal', 'Thonburi', 'Traditional Arabic', 'Trajan', 'TRAJAN PRO', 'Tristan', 'Tubular', 'Tunga', 'Tw Cen MT', 'Tw Cen MT C
vendor: 35,210 bytes, lines 571-1450
571ondensed', 'Tw Cen MT Condensed Extra Bold', 572 'TypoUpright BT', 'Unicorn', 'Univers', 'Univers CE 55 Medium', 'Univers Condensed', 'Utsaah', 'Vagabond', 'Vani', 'Vijaya', 'Viner Hand ITC', 'VisualUI', 'Vivaldi', 'Vladimir Script', 'Vrinda', 'Westminster', 'WHITNEY', 'Wide Latin', 573 'ZapfEllipt BT', 'ZapfHumnst BT', 'ZapfHumnst Dm BT', 'Zapfino', 'Zurich BlkEx BT', 'Zurich Ex BT', 'ZWAdobeF'] 574 fontList = fontList.concat(extendedFontList) 575 } 576 577 fontList = fontList.concat(options.fonts.userDefinedFonts) 578 579 // remove duplicate fonts 580 fontList = fontList.filter(function (font, position) { 581 return fontList.indexOf(font) === position 582 }) 583 584 // we use m or w because these two characters take up the maximum width. 585 // And we use a LLi so that the same matching fonts can get separated 586 var testString = 'mmmmmmmmmmlli' 587 588 // we test using 72px font size, we may use any size. I guess larger the better. 589 var testSize = '72px' 590 591 var h = document.getElementsByTagName('body')[0] 592 593 // div to load spans for the base fonts 594 var baseFontsDiv = document.createElement('div') 595 596 // div to load spans for the fonts to detect 597 var fontsDiv = document.createElement('div') 598 599 var defaultWidth = {} 600 var defaultHeight = {} 601 602 // creates a span where the fonts will be loaded 603 var createSpan = function () { 604 var s = document.createElement('span') 605 /* 606 * We need this css as in some weird browser this 607 * span elements shows up for a microSec which creates a 608 * bad user experience 609 */ 610 s.style.position = 'absolute' 611 s.style.left = '-9999px' 612 s.style.fontSize = testSize 613 614 // css font reset to reset external styles 615 s.style.fontStyle = 'normal' 616 s.style.fontWeight = 'normal' 617 s.style.letterSpacing = 'normal' 618 s.style.lineBreak = 'auto' 619 s.style.lineHeight = 'normal' 620 s.style.textTransform = 'none' 621 s.style.textAlign = 'left' 622 s.style.textDecoration = 'none' 623 s.style.textShadow = 'none' 624 s.style.whiteSpace = 'normal' 625 s.style.wordBreak = 'normal' 626 s.style.wordSpacing = 'normal' 627 628 s.innerHTML = testString 629 return s 630 } 631 632 // creates a span and load the font to detect and a base font for fallback 633 var createSpanWithFonts = function (fontToDetect, baseFont) { 634 var s = createSpan() 635 s.style.fontFamily = "'" + fontToDetect + "'," + baseFont 636 return s 637 } 638 639 // creates spans for the base fonts and adds them to baseFontsDiv 640 var initializeBaseFontsSpans = function () { 641 var spans = [] 642 for (var index = 0, length = baseFonts.length; index < length; index++) { 643 var s = createSpan() 644 s.style.fontFamily = baseFonts[index] 645 baseFontsDiv.appendChild(s) 646 spans.push(s) 647 } 648 return spans 649 } 650 651 // creates spans for the fonts to detect and adds them to fontsDiv 652 var initializeFontsSpans = function () { 653 var spans = {} 654 for (var i = 0, l = fontList.length; i < l; i++) { 655 var fontSpans = [] 656 for (var j = 0, numDefaultFonts = baseFonts.length; j < numDefaultFonts; j++) { 657 var s = createSpanWithFonts(fontList[i], baseFonts[j]) 658 fontsDiv.appendChild(s) 659 fontSpans.push(s) 660 } 661 spans[fontList[i]] = fontSpans // Stores {fontName : [spans for that font]} 662 } 663 return spans 664 } 665 666 // checks if a font is available 667 var isFontAvailable = function (fontSpans) { 668 var detected = false 669 for (var i = 0; i < baseFonts.length; i++) { 670 detected = (fontSpans[i].offsetWidth !== defaultWidth[baseFonts[i]] || fontSpans[i].offsetHeight !== defaultHeight[baseFonts[i]]) 671 if (detected) { 672 return detected 673 } 674 } 675 return detected 676 } 677 678 // create spans for base fonts 679 var baseFontsSpans = initializeBaseFontsSpans() 680 681 // add the spans to the DOM 682 h.appendChild(baseFontsDiv) 683 684 // get the default width for the three base fonts 685 for (var index = 0, length = baseFonts.length; index < length; index++) { 686 defaultWidth[baseFonts[index]] = baseFontsSpans[index].offsetWidth // width for the default font 687 defaultHeight[baseFonts[index]] = baseFontsSpans[index].offsetHeight // height for the default font 688 } 689 690 // create spans for fonts to detect 691 var fontsSpans = initializeFontsSpans() 692 693 // add all the spans to the DOM 694 h.appendChild(fontsDiv) 695 696 // check available fonts 697 var available = [] 698 for (var i = 0, l = fontList.length; i < l; i++) { 699 if (isFontAvailable(fontsSpans[fontList[i]])) { 700 available.push(fontList[i]) 701 } 702 } 703 704 // remove spans from DOM 705 h.removeChild(fontsDiv) 706 h.removeChild(baseFontsDiv) 707 done(available) 708 } 709 var pluginsComponent = function (done, options) { 710 if (isIE()) { 711 if (!options.plugins.excludeIE) { 712 done(getIEPlugins(options)) 713 } else { 714 done(options.EXCLUDED) 715 } 716 } else { 717 done(getRegularPlugins(options)) 718 } 719 } 720 var getRegularPlugins = function (options) { 721 if (navigator.plugins == null) { 722 return options.NOT_AVAILABLE 723 } 724 725 var plugins = [] 726 // plugins isn't defined in Node envs. 727 for (var i = 0, l = navigator.plugins.length; i < l; i++) { 728 if (navigator.plugins[i]) { plugins.push(navigator.plugins[i]) } 729 } 730 731 // sorting plugins only for those user agents, that we know randomize the plugins 732 // every time we try to enumerate them 733 if (pluginsShouldBeSorted(options)) { 734 plugins = plugins.sort(function (a, b) { 735 if (a.name > b.name) { return 1 } 736 if (a.name < b.name) { return -1 } 737 return 0 738 }) 739 } 740 return map(plugins, function (p) { 741 var mimeTypes = map(p, function (mt) { 742 return [mt.type, mt.suffixes] 743 }) 744 return [p.name, p.description, mimeTypes] 745 }) 746 } 747 var getIEPlugins = function (options) { 748 var result = [] 749 if ((Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(window, 'ActiveXObject')) || ('ActiveXObject' in window)) { 750 var names = [ 751 'AcroPDF.PDF', // Adobe PDF reader 7+ 752 'Adodb.Stream', 753 'AgControl.AgControl', // Silverlight 754 'DevalVRXCtrl.DevalVRXCtrl.1', 755 'MacromediaFlashPaper.MacromediaFlashPaper', 756 'Msxml2.DOMDocument', 757 'Msxml2.XMLHTTP', 758 'PDF.PdfCtrl', // Adobe PDF reader 6 and earlier, brrr 759 'QuickTime.QuickTime', // QuickTime 760 'QuickTimeCheckObject.QuickTimeCheck.1', 761 'RealPlayer', 762 'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)', 763 'RealVideo.RealVideo(tm) ActiveX Control (32-bit)', 764 'Scripting.Dictionary', 765 'SWCtl.SWCtl', // ShockWave player 766 'Shell.UIHelper', 767 'ShockwaveFlash.ShockwaveFlash', // flash plugin 768 'Skype.Detection', 769 'TDCCtl.TDCCtl', 770 'WMPlayer.OCX', // Windows media player 771 'rmocx.RealPlayer G2 Control', 772 'rmocx.RealPlayer G2 Control.1' 773 ] 774 // starting to detect plugins in IE 775 result = map(names, function (name) { 776 try { 777 // eslint-disable-next-line no-new 778 new window.ActiveXObject(name) 779 return name 780 } catch (e) { 781 return options.ERROR 782 } 783 }) 784 } else { 785 result.push(options.NOT_AVAILABLE) 786 } 787 if (navigator.plugins) { 788 result = result.concat(getRegularPlugins(options)) 789 } 790 return result 791 } 792 var pluginsShouldBeSorted = function (options) { 793 var should = false 794 for (var i = 0, l = options.plugins.sortPluginsFor.length; i < l; i++) { 795 var re = options.plugins.sortPluginsFor[i] 796 if (navigator.userAgent.match(re)) { 797 should = true 798 break 799 } 800 } 801 return should 802 } 803 var touchSupportKey = function (done) { 804 done(getTouchSupport()) 805 } 806 var hardwareConcurrencyKey = function (done, options) { 807 done(getHardwareConcurrency(options)) 808 } 809 var hasSessionStorage = function (options) { 810 try { 811 return !!window.sessionStorage 812 } catch (e) { 813 return options.ERROR // SecurityError when referencing it means it exists 814 } 815 } 816 817 // https://bugzilla.mozilla.org/show_bug.cgi?id=781447 818 var hasLocalStorage = function (options) { 819 try { 820 return !!window.localStorage 821 } catch (e) { 822 return options.ERROR // SecurityError when referencing it means it exists 823 } 824 } 825 var hasIndexedDB = function (options) { 826 try { 827 return !!window.indexedDB 828 } catch (e) { 829 return options.ERROR // SecurityError when referencing it means it exists 830 } 831 } 832 var getHardwareConcurrency = function (options) { 833 if (navigator.hardwareConcurrency) { 834 return navigator.hardwareConcurrency 835 } 836 return options.NOT_AVAILABLE 837 } 838 var getNavigatorCpuClass = function (options) { 839 return navigator.cpuClass || options.NOT_AVAILABLE 840 } 841 var getNavigatorPlatform = function (options) { 842 if (navigator.platform) { 843 return navigator.platform 844 } else { 845 return options.NOT_AVAILABLE 846 } 847 } 848 var getDoNotTrack = function (options) { 849 if (navigator.doNotTrack) { 850 return navigator.doNotTrack 851 } else if (navigator.msDoNotTrack) { 852 return navigator.msDoNotTrack 853 } else if (window.doNotTrack) { 854 return window.doNotTrack 855 } else { 856 return options.NOT_AVAILABLE 857 } 858 } 859 // This is a crude and primitive touch screen detection. 860 // It's not possible to currently reliably detect the availability of a touch screen 861 // with a JS, without actually subscribing to a touch event. 862 // http://www.stucox.com/blog/you-cant-detect-a-touchscreen/ 863 // https://github.com/Modernizr/Modernizr/issues/548 864 // method returns an array of 3 values: 865 // maxTouchPoints, the success or failure of creating a TouchEvent, 866 // and the availability of the 'ontouchstart' property 867 868 var getTouchSupport = function () { 869 var maxTouchPoints = 0 870 var touchEvent 871 if (typeof navigator.maxTouchPoints !== 'undefined') { 872 maxTouchPoints = navigator.maxTouchPoints 873 } else if (typeof navigator.msMaxTouchPoints !== 'undefined') { 874 maxTouchPoints = navigator.msMaxTouchPoints 875 } 876 try { 877 document.createEvent('TouchEvent') 878 touchEvent = true 879 } catch (_) { 880 touchEvent = false 881 } 882 var touchStart = 'ontouchstart' in window 883 return [maxTouchPoints, touchEvent, touchStart] 884 } 885 // https://www.browserleaks.com/canvas#how-does-it-work 886 887 var getCanvasFp = function (options) { 888 var result = [] 889 // Very simple now, need to make it more complex (geo shapes etc) 890 var canvas = document.createElement('canvas') 891 canvas.width = 2000 892 canvas.height = 200 893 canvas.style.display = 'inline' 894 var ctx = canvas.getContext('2d') 895 // detect browser support of canvas winding 896 // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/ 897 // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/canvas/winding.js 898 ctx.rect(0, 0, 10, 10) 899 ctx.rect(2, 2, 6, 6) 900 result.push('canvas winding:' + ((ctx.isPointInPath(5, 5, 'evenodd') === false) ? 'yes' : 'no')) 901 902 ctx.textBaseline = 'alphabetic' 903 ctx.fillStyle = '#f60' 904 ctx.fillRect(125, 1, 62, 20) 905 ctx.fillStyle = '#069' 906 // https://github.com/Valve/fingerprintjs2/issues/66 907 if (options.dontUseFakeFontInCanvas) { 908 ctx.font = '11pt Arial' 909 } else { 910 ctx.font = '11pt no-real-font-123' 911 } 912 ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 2, 15) 913 ctx.fillStyle = 'rgba(102, 204, 0, 0.2)' 914 ctx.font = '18pt Arial' 915 ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 4, 45) 916 917 // canvas blending 918 // http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/ 919 // http://jsfiddle.net/NDYV8/16/ 920 ctx.globalCompositeOperation = 'multiply' 921 ctx.fillStyle = 'rgb(255,0,255)' 922 ctx.beginPath() 923 ctx.arc(50, 50, 50, 0, Math.PI * 2, true) 924 ctx.closePath() 925 ctx.fill() 926 ctx.fillStyle = 'rgb(0,255,255)' 927 ctx.beginPath() 928 ctx.arc(100, 50, 50, 0, Math.PI * 2, true) 929 ctx.closePath() 930 ctx.fill() 931 ctx.fillStyle = 'rgb(255,255,0)' 932 ctx.beginPath() 933 ctx.arc(75, 100, 50, 0, Math.PI * 2, true) 934 ctx.closePath() 935 ctx.fill() 936 ctx.fillStyle = 'rgb(255,0,255)' 937 // canvas winding 938 // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/ 939 // http://jsfiddle.net/NDYV8/19/ 940 ctx.arc(75, 75, 75, 0, Math.PI * 2, true) 941 ctx.arc(75, 75, 25, 0, Math.PI * 2, true) 942 ctx.fill('evenodd') 943 944 if (canvas.toDataURL) { result.push('canvas fp:' + canvas.toDataURL()) } 945 return result 946 } 947 var getWebglFp = function () { 948 var gl 949 var fa2s = function (fa) { 950 gl.clearColor(0.0, 0.0, 0.0, 1.0) 951 gl.enable(gl.DEPTH_TEST) 952 gl.depthFunc(gl.LEQUAL) 953 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 954 return '[' + fa[0] + ', ' + fa[1] + ']' 955 } 956 var maxAnisotropy = function (gl) { 957 var ext = gl.getExtension('EXT_texture_filter_anisotropic') || gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic') || gl.getExtension('MOZ_EXT_texture_filter_anisotropic') 958 if (ext) { 959 var anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT) 960 if (anisotropy === 0) { 961 anisotropy = 2 962 } 963 return anisotropy 964 } else { 965 return null 966 } 967 } 968 969 gl = getWebglCanvas() 970 if (!gl) { return null } 971 // WebGL fingerprinting is a combination of techniques, found in MaxMind antifraud script & Augur fingerprinting. 972 // First it draws a gradient object with shaders and convers the image to the Base64 string. 973 // Then it enumerates all WebGL extensions & capabilities and appends them to the Base64 string, resulting in a huge WebGL string, potentially very unique on each device 974 // Since iOS supports webgl starting from version 8.1 and 8.1 runs on several graphics chips, the results may be different across ios devices, but we need to verify it. 975 var result = [] 976 var vShaderTemplate = 'attribute vec2 attrVertex;varying vec2 varyinTexCoordinate;uniform vec2 uniformOffset;void main(){varyinTexCoordinate=attrVertex+uniformOffset;gl_Position=vec4(attrVertex,0,1);}' 977 var fShaderTemplate = 'precision mediump float;varying vec2 varyinTexCoordinate;void main() {gl_FragColor=vec4(varyinTexCoordinate,0,1);}' 978 var vertexPosBuffer = gl.createBuffer() 979 gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer) 980 var vertices = new Float32Array([-0.2, -0.9, 0, 0.4, -0.26, 0, 0, 0.732134444, 0]) 981 gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW) 982 vertexPosBuffer.itemSize = 3 983 vertexPosBuffer.numItems = 3 984 var program = gl.createProgram() 985 var vshader = gl.createShader(gl.VERTEX_SHADER) 986 gl.shaderSource(vshader, vShaderTemplate) 987 gl.compileShader(vshader) 988 var fshader = gl.createShader(gl.FRAGMENT_SHADER) 989 gl.shaderSource(fshader, fShaderTemplate) 990 gl.compileShader(fshader) 991 gl.attachShader(program, vshader) 992 gl.attachShader(program, fshader) 993 gl.linkProgram(program) 994 gl.useProgram(program) 995 program.vertexPosAttrib = gl.getAttribLocation(program, 'attrVertex') 996 program.offsetUniform = gl.getUniformLocation(program, 'uniformOffset') 997 gl.enableVertexAttribArray(program.vertexPosArray) 998 gl.vertexAttribPointer(program.vertexPosAttrib, vertexPosBuffer.itemSize, gl.FLOAT, !1, 0, 0) 999 gl.uniform2f(program.offsetUniform, 1, 1) 1000 gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertexPosBuffer.numItems) 1001 try { 1002 result.push(gl.canvas.toDataURL()) 1003 } catch (e) { 1004 /* .toDataURL may be absent or broken (blocked by extension) */ 1005 } 1006 result.push('extensions:' + (gl.getSupportedExtensions() || []).join(';')) 1007 result.push('webgl aliased line width range:' + fa2s(gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE))) 1008 result.push('webgl aliased point size range:' + fa2s(gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE))) 1009 result.push('webgl alpha bits:' + gl.getParameter(gl.ALPHA_BITS)) 1010 result.push('webgl antialiasing:' + (gl.getContextAttributes().antialias ? 'yes' : 'no')) 1011 result.push('webgl blue bits:' + gl.getParameter(gl.BLUE_BITS)) 1012 result.push('webgl depth bits:' + gl.getParameter(gl.DEPTH_BITS)) 1013 result.push('webgl green bits:' + gl.getParameter(gl.GREEN_BITS)) 1014 result.push('webgl max anisotropy:' + maxAnisotropy(gl)) 1015 result.push('webgl max combined texture image units:' + gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)) 1016 result.push('webgl max cube map texture size:' + gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE)) 1017 result.push('webgl max fragment uniform vectors:' + gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS)) 1018 result.push('webgl max render buffer size:' + gl.getParameter(gl.MAX_RENDERBUFFER_SIZE)) 1019 result.push('webgl max texture image units:' + gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)) 1020 result.push('webgl max texture size:' + gl.getParameter(gl.MAX_TEXTURE_SIZE)) 1021 result.push('webgl max varying vectors:' + gl.getParameter(gl.MAX_VARYING_VECTORS)) 1022 result.push('webgl max vertex attribs:' + gl.getParameter(gl.MAX_VERTEX_ATTRIBS)) 1023 result.push('webgl max vertex texture image units:' + gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)) 1024 result.push('webgl max vertex uniform vectors:' + gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS)) 1025 result.push('webgl max viewport dims:' + fa2s(gl.getParameter(gl.MAX_VIEWPORT_DIMS))) 1026 result.push('webgl red bits:' + gl.getParameter(gl.RED_BITS)) 1027 result.push('webgl renderer:' + gl.getParameter(gl.RENDERER)) 1028 result.push('webgl shading language version:' + gl.getParameter(gl.SHADING_LANGUAGE_VERSION)) 1029 result.push('webgl stencil bits:' + gl.getParameter(gl.STENCIL_BITS)) 1030 result.push('webgl vendor:' + gl.getParameter(gl.VENDOR)) 1031 result.push('webgl version:' + gl.getParameter(gl.VERSION)) 1032 1033 try { 1034 // Add the unmasked vendor and unmasked renderer if the debug_renderer_info extension is available 1035 var extensionDebugRendererInfo = gl.getExtension('WEBGL_debug_renderer_info') 1036 if (extensionDebugRendererInfo) { 1037 result.push('webgl unmasked vendor:' + gl.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL)) 1038 result.push('webgl unmasked renderer:' + gl.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL)) 1039 } 1040 } catch (e) { /* squelch */ } 1041 1042 if (!gl.getShaderPrecisionFormat) { 1043 return result 1044 } 1045 1046 each(['FLOAT', 'INT'], function (numType) { 1047 each(['VERTEX', 'FRAGMENT'], function (shader) { 1048 each(['HIGH', 'MEDIUM', 'LOW'], function (numSize) { 1049 each(['precision', 'rangeMin', 'rangeMax'], function (key) { 1050 var format = gl.getShaderPrecisionFormat(gl[shader + '_SHADER'], gl[numSize + '_' + numType])[key] 1051 if (key !== 'precision') { 1052 key = 'precision ' + key 1053 } 1054 var line = ['webgl ', shader.toLowerCase(), ' shader ', numSize.toLowerCase(), ' ', numType.toLowerCase(), ' ', key, ':', format].join('') 1055 result.push(line) 1056 }) 1057 }) 1058 }) 1059 }) 1060 return result 1061 } 1062 var getWebglVendorAndRenderer = function () { 1063 /* This a subset of the WebGL fingerprint with a lot of entropy, while being reasonably browser-independent */ 1064 try { 1065 var glContext = getWebglCanvas() 1066 var extensionDebugRendererInfo = glContext.getExtension('WEBGL_debug_renderer_info') 1067 return glContext.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL) + '~' + glContext.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL) 1068 } catch (e) { 1069 return null 1070 } 1071 } 1072 var getAdBlock = function () { 1073 var ads = document.createElement('div') 1074 ads.innerHTML = ' ' 1075 ads.className = 'adsbox' 1076 var result = false 1077 try { 1078 // body may not exist, that's why we need try/catch 1079 document.body.appendChild(ads) 1080 result = document.getElementsByClassName('adsbox')[0].offsetHeight === 0 1081 document.body.removeChild(ads) 1082 } catch (e) { 1083 result = false 1084 } 1085 return result 1086 } 1087 var getHasLiedLanguages = function () { 1088 // We check if navigator.language is equal to the first language of navigator.languages 1089 if (typeof navigator.languages !== 'undefined') { 1090 try { 1091 var firstLanguages = navigator.languages[0].substr(0, 2) 1092 if (firstLanguages !== navigator.language.substr(0, 2)) { 1093 return true 1094 } 1095 } catch (err) { 1096 return true 1097 } 1098 } 1099 return false 1100 } 1101 var getHasLiedResolution = function () { 1102 return window.screen.width < window.screen.availWidth || window.screen.height < window.screen.availHeight 1103 } 1104 var getHasLiedOs = function () { 1105 var userAgent = navigator.userAgent.toLowerCase() 1106 var oscpu = navigator.oscpu 1107 var platform = navigator.platform.toLowerCase() 1108 var os 1109 // We extract the OS from the user agent (respect the order of the if else if statement) 1110 if (userAgent.indexOf('windows phone') >= 0) { 1111 os = 'Windows Phone' 1112 } else if (userAgent.indexOf('win') >= 0) { 1113 os = 'Windows' 1114 } else if (userAgent.indexOf('android') >= 0) { 1115 os = 'Android' 1116 } else if (userAgent.indexOf('linux') >= 0) { 1117 os = 'Linux' 1118 } else if (userAgent.indexOf('iphone') >= 0 || userAgent.indexOf('ipad') >= 0) { 1119 os = 'iOS' 1120 } else if (userAgent.indexOf('mac') >= 0) { 1121 os = 'Mac' 1122 } else { 1123 os = 'Other' 1124 } 1125 // We detect if the person uses a mobile device 1126 var mobileDevice = (('ontouchstart' in window) || 1127 (navigator.maxTouchPoints > 0) || 1128 (navigator.msMaxTouchPoints > 0)) 1129 1130 if (mobileDevice && os !== 'Windows Phone' && os !== 'Android' && os !== 'iOS' && os !== 'Other') { 1131 return true 1132 } 1133 1134 // We compare oscpu with the OS extracted from the UA 1135 if (typeof oscpu !== 'undefined') { 1136 oscpu = oscpu.toLowerCase() 1137 if (oscpu.indexOf('win') >= 0 && os !== 'Windows' && os !== 'Windows Phone') { 1138 return true 1139 } else if (oscpu.indexOf('linux') >= 0 && os !== 'Linux' && os !== 'Android') { 1140 return true 1141 } else if (oscpu.indexOf('mac') >= 0 && os !== 'Mac' && os !== 'iOS') { 1142 return true 1143 } else if ((oscpu.indexOf('win') === -1 && oscpu.indexOf('linux') === -1 && oscpu.indexOf('mac') === -1) !== (os === 'Other')) { 1144 return true 1145 } 1146 } 1147 1148 // We compare platform with the OS extracted from the UA 1149 if (platform.indexOf('win') >= 0 && os !== 'Windows' && os !== 'Windows Phone') { 1150 return true 1151 } else if ((platform.indexOf('linux') >= 0 || platform.indexOf('android') >= 0 || platform.indexOf('pike') >= 0) && os !== 'Linux' && os !== 'Android') { 1152 return true 1153 } else if ((platform.indexOf('mac') >= 0 || platform.indexOf('ipad') >= 0 || platform.indexOf('ipod') >= 0 || platform.indexOf('iphone') >= 0) && os !== 'Mac' && os !== 'iOS') { 1154 return true 1155 } else if ((platform.indexOf('win') === -1 && platform.indexOf('linux') === -1 && platform.indexOf('mac') === -1) !== (os === 'Other')) { 1156 return true 1157 } 1158 1159 return typeof navigator.plugins === 'undefined' && os !== 'Windows' && os !== 'Windows Phone' 1160 } 1161 var getHasLiedBrowser = function () { 1162 var userAgent = navigator.userAgent.toLowerCase() 1163 var productSub = navigator.productSub 1164 1165 // we extract the browser from the user agent (respect the order of the tests) 1166 var browser 1167 if (userAgent.indexOf('firefox') >= 0) { 1168 browser = 'Firefox' 1169 } else if (userAgent.indexOf('opera') >= 0 || userAgent.indexOf('opr') >= 0) { 1170 browser = 'Opera' 1171 } else if (userAgent.indexOf('chrome') >= 0) { 1172 browser = 'Chrome' 1173 } else if (userAgent.indexOf('safari') >= 0) { 1174 browser = 'Safari' 1175 } else if (userAgent.indexOf('trident') >= 0) { 1176 browser = 'Internet Explorer' 1177 } else { 1178 browser = 'Other' 1179 } 1180 1181 if ((browser === 'Chrome' || browser === 'Safari' || browser === 'Opera') && productSub !== '20030107') { 1182 return true 1183 } 1184 1185 // eslint-disable-next-line no-eval 1186 var tempRes = eval.toString().length 1187 if (tempRes === 37 && browser !== 'Safari' && browser !== 'Firefox' && browser !== 'Other') { 1188 return true 1189 } else if (tempRes === 39 && browser !== 'Internet Explorer' && browser !== 'Other') { 1190 return true 1191 } else if (tempRes === 33 && browser !== 'Chrome' && browser !== 'Opera' && browser !== 'Other') { 1192 return true 1193 } 1194 1195 // We create an error to see how it is handled 1196 var errFirefox 1197 try { 1198 // eslint-disable-next-line no-throw-literal 1199 throw 'a' 1200 } catch (err) { 1201 try { 1202 err.toSource() 1203 errFirefox = true 1204 } catch (errOfErr) { 1205 errFirefox = false 1206 } 1207 } 1208 return errFirefox && browser !== 'Firefox' && browser !== 'Other' 1209 } 1210 var isCanvasSupported = function () { 1211 var elem = document.createElement('canvas') 1212 return !!(elem.getContext && elem.getContext('2d')) 1213 } 1214 var isWebGlSupported = function () { 1215 // code taken from Modernizr 1216 if (!isCanvasSupported()) { 1217 return false 1218 } 1219 1220 var glContext = getWebglCanvas() 1221 return !!window.WebGLRenderingContext && !!glContext 1222 } 1223 var isIE = function () { 1224 if (navigator.appName === 'Microsoft Internet Explorer') { 1225 return true 1226 } else if (navigator.appName === 'Netscape' && /Trident/.test(navigator.userAgent)) { // IE 11 1227 return true 1228 } 1229 return false 1230 } 1231 var hasSwfObjectLoaded = function () { 1232 return typeof window.swfobject !== 'undefined' 1233 } 1234 var hasMinFlashInstalled = function () { 1235 return window.swfobject.hasFlashPlayerVersion('9.0.0') 1236 } 1237 var addFlashDivNode = function (options) { 1238 var node = document.createElement('div') 1239 node.setAttribute('id', options.fonts.swfContainerId) 1240 document.body.appendChild(node) 1241 } 1242 var loadSwfAndDetectFonts = function (done, options) { 1243 var hiddenCallback = '___fp_swf_loaded' 1244 window[hiddenCallback] = function (fonts) { 1245 done(fonts) 1246 } 1247 var id = options.fonts.swfContainerId 1248 addFlashDivNode() 1249 var flashvars = { onReady: hiddenCallback } 1250 var flashparams = { allowScriptAccess: 'always', menu: 'false' } 1251 window.swfobject.embedSWF(options.fonts.swfPath, id, '1', '1', '9.0.0', false, flashvars, flashparams, {}) 1252 } 1253 var getWebglCanvas = function () { 1254 var canvas = document.createElement('canvas') 1255 var gl = null 1256 try { 1257 gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') 1258 } catch (e) { /* squelch */ } 1259 if (!gl) { gl = null } 1260 return gl 1261 } 1262 1263 var components = [ 1264 {key: 'userAgent', getData: UserAgent}, 1265 {key: 'language', getData: languageKey}, 1266 {key: 'colorDepth', getData: colorDepthKey}, 1267 {key: 'deviceMemory', getData: deviceMemoryKey}, 1268 {key: 'pixelRatio', getData: pixelRatioKey}, 1269 {key: 'hardwareConcurrency', getData: hardwareConcurrencyKey}, 1270 {key: 'screenResolution', getData: screenResolutionKey}, 1271 {key: 'availableScreenResolution', getData: availableScreenResolutionKey}, 1272 {key: 'timezoneOffset', getData: timezoneOffset}, 1273 {key: 'timezone', getData: timezone}, 1274 {key: 'sessionStorage', getData: sessionStorageKey}, 1275 {key: 'localStorage', getData: localStorageKey}, 1276 {key: 'indexedDb', getData: indexedDbKey}, 1277 {key: 'addBehavior', getData: addBehaviorKey}, 1278 {key: 'openDatabase', getData: openDatabaseKey}, 1279 {key: 'cpuClass', getData: cpuClassKey}, 1280 {key: 'platform', getData: platformKey}, 1281 {key: 'doNotTrack', getData: doNotTrackKey}, 1282 {key: 'plugins', getData: pluginsComponent}, 1283 {key: 'canvas', getData: canvasKey}, 1284 {key: 'webgl', getData: webglKey}, 1285 {key: 'webglVendorAndRenderer', getData: webglVendorAndRendererKey}, 1286 {key: 'adBlock', getData: adBlockKey}, 1287 {key: 'hasLiedLanguages', getData: hasLiedLanguagesKey}, 1288 {key: 'hasLiedResolution', getData: hasLiedResolutionKey}, 1289 {key: 'hasLiedOs', getData: hasLiedOsKey}, 1290 {key: 'hasLiedBrowser', getData: hasLiedBrowserKey}, 1291 {key: 'touchSupport', getData: touchSupportKey}, 1292 {key: 'fonts', getData: jsFontsKey, pauseBefore: true}, 1293 {key: 'fontsFlash', getData: flashFontsKey, pauseBefore: true}, 1294 {key: 'audio', getData: audioKey}, 1295 {key: 'enumerateDevices', getData: enumerateDevicesKey} 1296 ] 1297 1298 var Fingerprint2 = function (options) { 1299 throw new Error("'new Fingerprint()' is deprecated, see https://github.com/Valve/fingerprintjs2#upgrade-guide-from-182-to-200") 1300 } 1301 1302 Fingerprint2.get = function (options, callback) { 1303 if (!callback) { 1304 callback = options 1305 options = {} 1306 } else if (!options) { 1307 options = {} 1308 } 1309 extendSoft(options, defaultOptions) 1310 options.components = options.extraComponents.concat(components) 1311 1312 var keys = { 1313 data: [], 1314 addPreprocessedComponent: function (key, value) { 1315 if (typeof options.preprocessor === 'function') { 1316 value = options.preprocessor(key, value) 1317 } 1318 keys.data.push({key: key, value: value}) 1319 } 1320 } 1321 1322 var i = -1 1323 var chainComponents = function (alreadyWaited) { 1324 i += 1 1325 if (i >= options.components.length) { // on finish 1326 callback(keys.data) 1327 return 1328 } 1329 var component = options.components[i] 1330 1331 if (options.excludes[component.key]) { 1332 chainComponents(false) // skip 1333 return 1334 } 1335 1336 if (!alreadyWaited && component.pauseBefore) { 1337 i -= 1 1338 setTimeout(function () { 1339 chainComponents(true) 1340 }, 1) 1341 return 1342 } 1343 1344 try { 1345 component.getData(function (value) { 1346 keys.addPreprocessedComponent(component.key, value) 1347 chainComponents(false) 1348 }, options) 1349 } catch (error) { 1350 // main body error 1351 keys.addPreprocessedComponent(component.key, String(error)) 1352 chainComponents(false) 1353 } 1354 } 1355 chainComponents(false) 1356 } 1357 1358 Fingerprint2.getPromise = function (options) { 1359 return new Promise(function (resolve, reject) { 1360 Fingerprint2.get(options, resolve) 1361 }) 1362 } 1363 1364 Fingerprint2.getV18 = function (options, callback) { 1365 if (callback == null) { 1366 callback = options 1367 options = {} 1368 } 1369 return Fingerprint2.get(options, function (components) { 1370 var newComponents = [] 1371 for (var i = 0; i < components.length; i++) { 1372 var component = components[i] 1373 if (component.value === (options.NOT_AVAILABLE || 'not available')) { 1374 newComponents.push({key: component.key, value: 'unknown'}) 1375 } else if (component.key === 'plugins') { 1376 newComponents.push({key: 'plugins', 1377 value: map(component.value, function (p) { 1378 var mimeTypes = map(p[2], function (mt) { 1379 if (mt.join) { return mt.join('~') } 1380 return mt 1381 }).join(',') 1382 return [p[0], p[1], mimeTypes].join('::') 1383 })}) 1384 } else if (['canvas', 'webgl'].indexOf(component.key) !== -1) { 1385 newComponents.push({key: component.key, value: component.value.join('~')}) 1386 } else if (['sessionStorage', 'localStorage', 'indexedDb', 'addBehavior', 'openDatabase'].indexOf(component.key) !== -1) { 1387 if (component.value) { 1388 newComponents.push({key: component.key, value: 1}) 1389 } else { 1390 // skip 1391 continue 1392 } 1393 } else { 1394 if (component.value) { 1395 newComponents.push(component.value.join ? {key: component.key, value: component.value.join(';')} : component) 1396 } else { 1397 newComponents.push({key: component.key, value: component.value}) 1398 } 1399 } 1400 } 1401 var murmur = x64hash128(map(newComponents, function (component) { return component.value }).join('~~~'), 31) 1402 callback(murmur, newComponents) 1403 }) 1404 } 1405 1406 Fingerprint2.x64hash128 = x64hash128 1407 Fingerprint2.VERSION = '2.0.0' 1408 return Fingerprint2 1409 }) 1410 1411 1412// ************************************************************************ 1413 1414jQuery(document).ready(function ($) { 1415 var hasConsole = typeof console !== "undefined" 1416 var fingerprintReport = function () { 1417 var options = { 1418 excludes: { 1419 availableScreenResolution: true, 1420 enumerateDevices: true, 1421 doNotTrack: true, 1422 adBlock: true, 1423 indexedDb: true, 1424 font: true 1425 } 1426 } 1427 1428 Fingerprint2.get(options, function (components) { 1429 var signature = Fingerprint2.x64hash128(components.map(function (pair) { 1430 return pair.value 1431 }).join(), 31) 1432 //console.log("User Fingerprint Outside: ", signature); 1433 //$('#fingerprint2_signature_poll_'+poll.options.pollID).val(signature); //not get pollID 1434 1435 //$('#fingerprint2_signature_poll').val(signature); 1436 jQuery(".fingerprint2_signature_poll_class").each(function() { 1437 jQuery(this).val(signature); 1438 }); 1439 }) 1440 } 1441 var cancelId 1442 var cancelFunction 1443 if (window.requestIdleCallback) { 1444 cancelId = requestIdleCallback(fingerprintReport) 1445 cancelFunction = cancelIdleCallback 1446 } else { 1447 cancelId = setTimeout(fingerprintReport, 500) 1448 cancelFunction = clearTimeout 1449 } 1450});
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.