UNPKG

@microsoft/applicationinsights-core-js

Version:

Microsoft Application Insights Core Javascript SDK

393 lines • 18.5 kB
/* * Application Insights JavaScript SDK - Core, 3.3.6 * Copyright (c) Microsoft and contributors. All rights reserved. */ var _a, _b; import { arrForEach, arrIndexOf, dumpObj, getDocument, getLazy, getNavigator, isArray, isFunction, isNullOrUndefined, isString, isTruthy, isUndefined, objForEachKey, strEndsWith, strIndexOf, strLeft, strSubstring, strTrim, utcNow } from "@nevware21/ts-utils"; import { cfgDfMerge } from "../Config/ConfigDefaultHelpers"; import { createDynamicConfig, onConfigChange } from "../Config/DynamicConfig"; import { _DYN_ENABLED, _DYN_LENGTH, _DYN_LOGGER, _DYN_SPLIT, _DYN_USER_AGENT } from "../__DynamicConstants"; import { _throwInternal } from "./DiagnosticLogger"; import { getLocation, isIE } from "./EnvUtils"; import { getExceptionName, isNotNullOrUndefined, setValue, strContains } from "./HelperFuncs"; import { STR_DOMAIN, STR_EMPTY, STR_PATH, UNDEFINED_VALUE } from "./InternalConstants"; var strToGMTString = "toGMTString"; var strToUTCString = "toUTCString"; var strCookie = "cookie"; var strExpires = "expires"; var strIsCookieUseDisabled = "isCookieUseDisabled"; var strDisableCookiesUsage = "disableCookiesUsage"; var strConfigCookieMgr = "_ckMgr"; var _supportsCookies = null; var _allowUaSameSite = null; var _parsedCookieValue = null; var _doc; var _cookieCache = {}; var _globalCookieConfig = {}; // // `isCookieUseDisabled` is deprecated, so explicitly casting as a key of IConfiguration to avoid typing error // // when both isCookieUseDisabled and disableCookiesUsage are used disableCookiesUsage will take precedent, which is // // why its listed first /** * Set the supported dynamic config values as undefined (or an empty object) so that * any listeners will be informed of any changes. * Explicitly NOT including the deprecated `isCookieUseDisabled` as we don't want to support * the v1 deprecated field as dynamic for updates */ var rootDefaultConfig = (_a = { cookieCfg: cfgDfMerge((_b = {}, _b[STR_DOMAIN] = { fb: "cookieDomain", dfVal: isNotNullOrUndefined }, _b.path = { fb: "cookiePath", dfVal: isNotNullOrUndefined }, _b.enabled = UNDEFINED_VALUE, _b.ignoreCookies = UNDEFINED_VALUE, _b.blockedCookies = UNDEFINED_VALUE, _b)), cookieDomain: UNDEFINED_VALUE, cookiePath: UNDEFINED_VALUE }, _a[strDisableCookiesUsage] = UNDEFINED_VALUE, _a); function _getDoc() { !_doc && (_doc = getLazy(function () { return getDocument(); })); } /** * @ignore * DO NOT USE or export from the module, this is exposed as public to support backward compatibility of previous static utility methods only. * If you want to manager cookies either use the ICookieMgr available from the core instance via getCookieMgr() or create * your own instance of the CookieMgr and use that. * Using this directly for enabling / disabling cookie handling will not only affect your usage but EVERY user of cookies. * Example, if you are using a shared component that is also using Application Insights you will affect their cookie handling. * @param logger - The DiagnosticLogger to use for reporting errors. */ function _gblCookieMgr(config, logger) { // Stash the global instance against the BaseCookieMgr class var inst = createCookieMgr[strConfigCookieMgr] || _globalCookieConfig[strConfigCookieMgr]; if (!inst) { // Note: not using the getSetValue() helper as that would require always creating a temporary cookieMgr // that ultimately is never used inst = createCookieMgr[strConfigCookieMgr] = createCookieMgr(config, logger); _globalCookieConfig[strConfigCookieMgr] = inst; } return inst; } function _isMgrEnabled(cookieMgr) { if (cookieMgr) { return cookieMgr.isEnabled(); } return true; } function _isIgnoredCookie(cookieMgrCfg, name) { if (name && cookieMgrCfg && isArray(cookieMgrCfg.ignoreCookies)) { return arrIndexOf(cookieMgrCfg.ignoreCookies, name) !== -1; } return false; } function _isBlockedCookie(cookieMgrCfg, name) { if (name && cookieMgrCfg && isArray(cookieMgrCfg.blockedCookies)) { if (arrIndexOf(cookieMgrCfg.blockedCookies, name) !== -1) { return true; } } return _isIgnoredCookie(cookieMgrCfg, name); } function _isCfgEnabled(rootConfig, cookieMgrConfig) { var isCfgEnabled = cookieMgrConfig[_DYN_ENABLED /* @min:%2eenabled */]; if (isNullOrUndefined(isCfgEnabled)) { // Set the enabled from the provided setting or the legacy root values var cookieEnabled = void 0; // This field is deprecated and dynamic updates will not be fully supported if (!isUndefined(rootConfig[strIsCookieUseDisabled])) { cookieEnabled = !rootConfig[strIsCookieUseDisabled]; } // If this value is defined it takes precedent over the above if (!isUndefined(rootConfig[strDisableCookiesUsage])) { cookieEnabled = !rootConfig[strDisableCookiesUsage]; } // Not setting the cookieMgrConfig.enabled as that will update (set) the global dynamic config // So future "updates" then may not be as expected isCfgEnabled = cookieEnabled; } return isCfgEnabled; } /** * Helper to return the ICookieMgr from the core (if not null/undefined) or a default implementation * associated with the configuration or a legacy default. * @param core - The AppInsightsCore instance to get the cookie manager from * @param config - The config to use if the core is not available * @returns */ export function safeGetCookieMgr(core, config) { var cookieMgr; if (core) { // Always returns an instance cookieMgr = core.getCookieMgr(); } else if (config) { var cookieCfg = config.cookieCfg; if (cookieCfg && cookieCfg[strConfigCookieMgr]) { cookieMgr = cookieCfg[strConfigCookieMgr]; } else { cookieMgr = createCookieMgr(config); } } if (!cookieMgr) { // Get or initialize the default global (legacy) cookie manager if we couldn't find one cookieMgr = _gblCookieMgr(config, (core || {})[_DYN_LOGGER /* @min:%2elogger */]); } return cookieMgr; } export function createCookieMgr(rootConfig, logger) { var cookieMgrConfig; var _path; var _domain; var unloadHandler; // Explicitly checking against false, so that setting to undefined will === true var _enabled; var _getCookieFn; var _setCookieFn; var _delCookieFn; // Make sure the root config is dynamic as it may be the global config rootConfig = createDynamicConfig(rootConfig || _globalCookieConfig, null, logger).cfg; // Will get recalled if the referenced configuration is changed unloadHandler = onConfigChange(rootConfig, function (details) { // Make sure the root config has all of the the defaults to the root config to ensure they are dynamic details.setDf(details.cfg, rootDefaultConfig); // Create and apply the defaults to the cookieCfg element cookieMgrConfig = details.ref(details.cfg, "cookieCfg"); // details.setDf(details.cfg.cookieCfg, defaultConfig); _path = cookieMgrConfig[STR_PATH /* @min:%2epath */] || "/"; _domain = cookieMgrConfig[STR_DOMAIN /* @min:%2edomain */]; // Explicitly checking against false, so that setting to undefined will === true _enabled = _isCfgEnabled(rootConfig, cookieMgrConfig) !== false; _getCookieFn = cookieMgrConfig.getCookie || _getCookieValue; _setCookieFn = cookieMgrConfig.setCookie || _setCookieValue; _delCookieFn = cookieMgrConfig.delCookie || _setCookieValue; }, logger); var cookieMgr = { isEnabled: function () { var enabled = _isCfgEnabled(rootConfig, cookieMgrConfig) !== false && _enabled && areCookiesSupported(logger); // Using an indirect lookup for any global cookie manager to support tree shaking for SDK's // that don't use the "applicationinsights-core" version of the default cookie function var gblManager = _globalCookieConfig[strConfigCookieMgr]; if (enabled && gblManager && cookieMgr !== gblManager) { // Make sure the GlobalCookie Manager instance (if not this instance) is also enabled. // As the global (deprecated) functions may have been called (for backward compatibility) enabled = _isMgrEnabled(gblManager); } return enabled; }, setEnabled: function (value) { // Explicitly checking against false, so that setting to undefined will === true _enabled = value !== false; cookieMgrConfig[_DYN_ENABLED /* @min:%2eenabled */] = value; }, set: function (name, value, maxAgeSec, domain, path) { var result = false; if (_isMgrEnabled(cookieMgr) && !_isBlockedCookie(cookieMgrConfig, name)) { var values = {}; var theValue = strTrim(value || STR_EMPTY); var idx = strIndexOf(theValue, ";"); if (idx !== -1) { theValue = strTrim(strLeft(value, idx)); values = _extractParts(strSubstring(value, idx + 1)); } // Only update domain if not already present (isUndefined) and the value is truthy (not null, undefined or empty string) setValue(values, STR_DOMAIN, domain || _domain, isTruthy, isUndefined); if (!isNullOrUndefined(maxAgeSec)) { var _isIE = isIE(); if (isUndefined(values[strExpires])) { var nowMs = utcNow(); // Only add expires if not already present var expireMs = nowMs + (maxAgeSec * 1000); // Sanity check, if zero or -ve then ignore if (expireMs > 0) { var expiry = new Date(); expiry.setTime(expireMs); setValue(values, strExpires, _formatDate(expiry, !_isIE ? strToUTCString : strToGMTString) || _formatDate(expiry, _isIE ? strToGMTString : strToUTCString) || STR_EMPTY, isTruthy); } } if (!_isIE) { // Only replace if not already present setValue(values, "max-age", STR_EMPTY + maxAgeSec, null, isUndefined); } } var location_1 = getLocation(); if (location_1 && location_1.protocol === "https:") { setValue(values, "secure", null, null, isUndefined); // Only set same site if not also secure if (_allowUaSameSite === null) { _allowUaSameSite = !uaDisallowsSameSiteNone((getNavigator() || {})[_DYN_USER_AGENT /* @min:%2euserAgent */]); } if (_allowUaSameSite) { setValue(values, "SameSite", "None", null, isUndefined); } } setValue(values, STR_PATH, path || _path, null, isUndefined); //let setCookieFn = cookieMgrConfig.setCookie || _setCookieValue; _setCookieFn(name, _formatCookieValue(theValue, values)); result = true; } return result; }, get: function (name) { var value = STR_EMPTY; if (_isMgrEnabled(cookieMgr) && !_isIgnoredCookie(cookieMgrConfig, name)) { value = _getCookieFn(name); } return value; }, del: function (name, path) { var result = false; if (_isMgrEnabled(cookieMgr)) { // Only remove the cookie if the manager and cookie support has not been disabled result = cookieMgr.purge(name, path); } return result; }, purge: function (name, path) { var _a; var result = false; if (areCookiesSupported(logger)) { // Setting the expiration date in the past immediately removes the cookie var values = (_a = {}, _a[STR_PATH] = path ? path : "/", _a[strExpires] = "Thu, 01 Jan 1970 00:00:01 GMT", _a); if (!isIE()) { // Set max age to expire now values["max-age"] = "0"; } // let delCookie = cookieMgrConfig.delCookie || _setCookieValue; _delCookieFn(name, _formatCookieValue(STR_EMPTY, values)); result = true; } return result; }, unload: function (isAsync) { unloadHandler && unloadHandler.rm(); unloadHandler = null; } }; // Associated this cookie manager with the config cookieMgr[strConfigCookieMgr] = cookieMgr; return cookieMgr; } /* * Helper method to tell if document.cookie object is supported by the runtime */ export function areCookiesSupported(logger) { if (_supportsCookies === null) { _supportsCookies = false; !_doc && _getDoc(); try { var doc = _doc.v || {}; _supportsCookies = doc[strCookie] !== undefined; } catch (e) { _throwInternal(logger, 2 /* eLoggingSeverity.WARNING */, 68 /* _eInternalMessageId.CannotAccessCookie */, "Cannot access document.cookie - " + getExceptionName(e), { exception: dumpObj(e) }); } } return _supportsCookies; } function _extractParts(theValue) { var values = {}; if (theValue && theValue[_DYN_LENGTH /* @min:%2elength */]) { var parts = strTrim(theValue)[_DYN_SPLIT /* @min:%2esplit */](";"); arrForEach(parts, function (thePart) { thePart = strTrim(thePart || STR_EMPTY); if (thePart) { var idx = strIndexOf(thePart, "="); if (idx === -1) { values[thePart] = null; } else { values[strTrim(strLeft(thePart, idx))] = strTrim(strSubstring(thePart, idx + 1)); } } }); } return values; } function _formatDate(theDate, func) { if (isFunction(theDate[func])) { return theDate[func](); } return null; } function _formatCookieValue(value, values) { var cookieValue = value || STR_EMPTY; objForEachKey(values, function (name, theValue) { cookieValue += "; " + name + (!isNullOrUndefined(theValue) ? "=" + theValue : STR_EMPTY); }); return cookieValue; } function _getCookieValue(name) { var cookieValue = STR_EMPTY; !_doc && _getDoc(); if (_doc.v) { var theCookie = _doc.v[strCookie] || STR_EMPTY; if (_parsedCookieValue !== theCookie) { _cookieCache = _extractParts(theCookie); _parsedCookieValue = theCookie; } cookieValue = strTrim(_cookieCache[name] || STR_EMPTY); } return cookieValue; } function _setCookieValue(name, cookieValue) { !_doc && _getDoc(); if (_doc.v) { _doc.v[strCookie] = name + "=" + cookieValue; } } export function uaDisallowsSameSiteNone(userAgent) { if (!isString(userAgent)) { return false; } // Cover all iOS based browsers here. This includes: // - Safari on iOS 12 for iPhone, iPod Touch, iPad // - WkWebview on iOS 12 for iPhone, iPod Touch, iPad // - Chrome on iOS 12 for iPhone, iPod Touch, iPad // All of which are broken by SameSite=None, because they use the iOS networking stack if (strContains(userAgent, "CPU iPhone OS 12") || strContains(userAgent, "iPad; CPU OS 12")) { return true; } // Cover Mac OS X based browsers that use the Mac OS networking stack. This includes: // - Safari on Mac OS X // This does not include: // - Internal browser on Mac OS X // - Chrome on Mac OS X // - Chromium on Mac OS X // Because they do not use the Mac OS networking stack. if (strContains(userAgent, "Macintosh; Intel Mac OS X 10_14") && strContains(userAgent, "Version/") && strContains(userAgent, "Safari")) { return true; } // Cover Mac OS X internal browsers that use the Mac OS networking stack. This includes: // - Internal browser on Mac OS X // This does not include: // - Safari on Mac OS X // - Chrome on Mac OS X // - Chromium on Mac OS X // Because they do not use the Mac OS networking stack. if (strContains(userAgent, "Macintosh; Intel Mac OS X 10_14") && strEndsWith(userAgent, "AppleWebKit/605.1.15 (KHTML, like Gecko)")) { return true; } // Cover Chrome 50-69, because some versions are broken by SameSite=None, and none in this range require it. // Note: this covers some pre-Chromium Edge versions, but pre-Chromim Edge does not require SameSite=None, so this is fine. // Note: this regex applies to Windows, Mac OS X, and Linux, deliberately. if (strContains(userAgent, "Chrome/5") || strContains(userAgent, "Chrome/6")) { return true; } // Unreal Engine runs Chromium 59, but does not advertise as Chrome until 4.23. Treat versions of Unreal // that don't specify their Chrome version as lacking support for SameSite=None. if (strContains(userAgent, "UnrealEngine") && !strContains(userAgent, "Chrome")) { return true; } // UCBrowser < 12.13.2 ignores Set-Cookie headers with SameSite=None // NB: this rule isn't complete - you need regex to make a complete rule. // See: https://www.chromium.org/updates/same-site/incompatible-clients if (strContains(userAgent, "UCBrowser/12") || strContains(userAgent, "UCBrowser/11")) { return true; } return false; } //# sourceMappingURL=CookieMgr.js.map