debian-mirror-gitlab/snowplow-javascript-tracker/src/js/lib/detectors.js
2020-04-13 14:06:41 +05:30

255 lines
7.8 KiB
JavaScript

/*
* JavaScript tracker for Snowplow: detectors.js
*
* Significant portions copyright 2010 Anthon Pang. Remainder copyright
* 2012-2014 Snowplow Analytics Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
* names of their contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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 THE COPYRIGHT
* OWNER OR CONTRIBUTORS 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() {
var
isFunction = require('lodash/isFunction'),
isUndefined = require('lodash/isUndefined'),
murmurhash3_32_gc = require('murmurhash').v3,
tz = require('jstimezonedetect').jstz.determine(),
cookie = require('browser-cookie-lite'),
object = typeof exports !== 'undefined' ? exports : this, // For eventual node.js environment support
windowAlias = window,
navigatorAlias = navigator,
screenAlias = screen,
documentAlias = document;
/*
* Checks whether sessionStorage is available, in a way that
* does not throw a SecurityError in Firefox if "always ask"
* is enabled for cookies (https://github.com/snowplow/snowplow/issues/163).
*/
object.hasSessionStorage = function () {
try {
return !!windowAlias.sessionStorage;
} catch (e) {
return true; // SecurityError when referencing it means it exists
}
};
/*
* Checks whether localStorage is available, in a way that
* does not throw a SecurityError in Firefox if "always ask"
* is enabled for cookies (https://github.com/snowplow/snowplow/issues/163).
*/
object.hasLocalStorage = function () {
try {
return !!windowAlias.localStorage;
} catch (e) {
return true; // SecurityError when referencing it means it exists
}
};
/*
* Checks whether localStorage is accessible
* sets and removes an item to handle private IOS5 browsing
* (http://git.io/jFB2Xw)
*/
object.localStorageAccessible = function() {
var mod = 'modernizr';
if (!object.hasLocalStorage()) {
return false;
}
try {
windowAlias.localStorage.setItem(mod, mod);
windowAlias.localStorage.removeItem(mod);
return true;
} catch(e) {
return false;
}
};
/*
* Does browser have cookies enabled (for this site)?
*/
object.hasCookies = function(testCookieName) {
var cookieName = testCookieName || 'testcookie';
if (isUndefined(navigatorAlias.cookieEnabled)) {
cookie.cookie(cookieName, '1');
return cookie.cookie(cookieName) === '1' ? '1' : '0';
}
return navigatorAlias.cookieEnabled ? '1' : '0';
};
/**
* JS Implementation for browser fingerprint.
* Does not require any external resources.
* Based on https://github.com/carlo/jquery-browser-fingerprint
* @return {number} 32-bit positive integer hash
*/
object.detectSignature = function(hashSeed) {
var fingerprint = [
navigatorAlias.userAgent,
[ screenAlias.height, screenAlias.width, screenAlias.colorDepth ].join("x"),
( new Date() ).getTimezoneOffset(),
object.hasSessionStorage(),
object.hasLocalStorage()
];
var plugins = [];
if (navigatorAlias.plugins)
{
for(var i = 0; i < navigatorAlias.plugins.length; i++)
{
if (navigatorAlias.plugins[i]) {
var mt = [];
for(var j = 0; j < navigatorAlias.plugins[i].length; j++) {
mt.push([navigatorAlias.plugins[i][j].type, navigatorAlias.plugins[i][j].suffixes]);
}
plugins.push([navigatorAlias.plugins[i].name + "::" + navigatorAlias.plugins[i].description, mt.join("~")]);
}
}
}
return murmurhash3_32_gc(fingerprint.join("###") + "###" + plugins.sort().join(";"), hashSeed);
};
/*
* Returns visitor timezone
*/
object.detectTimezone = function() {
return (typeof (tz) === 'undefined') ? '' : tz.name();
};
/**
* Gets the current viewport.
*
* Code based on:
* - http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/
* - http://responsejs.com/labs/dimensions/
*/
object.detectViewport = function() {
var e = windowAlias, a = 'inner';
if (!('innerWidth' in windowAlias)) {
a = 'client';
e = documentAlias.documentElement || documentAlias.body;
}
var width = e[a+'Width'];
var height = e[a+'Height'];
if (width >= 0 && height >= 0) {
return width + 'x' + height;
} else {
return null;
}
};
/**
* Gets the dimensions of the current
* document.
*
* Code based on:
* - http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/
*/
object.detectDocumentSize = function() {
var de = documentAlias.documentElement, // Alias
be = documentAlias.body,
// document.body may not have rendered, so check whether be.offsetHeight is null
bodyHeight = be ? Math.max(be.offsetHeight, be.scrollHeight) : 0;
var w = Math.max(de.clientWidth, de.offsetWidth, de.scrollWidth);
var h = Math.max(de.clientHeight, de.offsetHeight, de.scrollHeight, bodyHeight);
return isNaN(w) || isNaN(h) ? '' : w + 'x' + h;
};
/**
* Returns browser features (plugins, resolution, cookies)
*
* @param boolean useCookies Whether to test for cookies
* @param string testCookieName Name to use for the test cookie
* @return Object containing browser features
*/
object.detectBrowserFeatures = function(useCookies, testCookieName) {
var i,
mimeType,
pluginMap = {
// document types
pdf: 'application/pdf',
// media players
qt: 'video/quicktime',
realp: 'audio/x-pn-realaudio-plugin',
wma: 'application/x-mplayer2',
// interactive multimedia
dir: 'application/x-director',
fla: 'application/x-shockwave-flash',
// RIA
java: 'application/x-java-vm',
gears: 'application/x-googlegears',
ag: 'application/x-silverlight'
},
features = {};
// General plugin detection
if (navigatorAlias.mimeTypes && navigatorAlias.mimeTypes.length) {
for (i in pluginMap) {
if (Object.prototype.hasOwnProperty.call(pluginMap, i)) {
mimeType = navigatorAlias.mimeTypes[pluginMap[i]];
features[i] = (mimeType && mimeType.enabledPlugin) ? '1' : '0';
}
}
}
// Safari and Opera
// IE6/IE7 navigator.javaEnabled can't be aliased, so test directly
if (navigatorAlias.constructor === window.Navigator &&
typeof navigatorAlias.javaEnabled !== 'unknown' &&
!isUndefined(navigatorAlias.javaEnabled) &&
navigatorAlias.javaEnabled()) {
features.java = '1';
}
// Firefox
if (isFunction(windowAlias.GearsFactory)) {
features.gears = '1';
}
// Other browser features
features.res = screenAlias.width + 'x' + screenAlias.height;
features.cd = screenAlias.colorDepth;
if (useCookies) {
features.cookie = object.hasCookies(testCookieName);
}
return features;
};
}());