diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ee0fe7..7fa3260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # Changelog +## 6.13.1 +### Fixes +- [browser] Cookie testing is now secure on suitable URLs + ## 6.13.0 ### New - [browser] New configuration `enableExtendedOptout` to enable enhanced tracking of optout visitors (`false` by default) diff --git a/package.json b/package.json index eef42be..837f455 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "piano-analytics-js", "description": "JavaScript library for Piano Analytics", - "version": "6.13.0", + "version": "6.13.1", "main": "dist/browserless/piano-analytics.cjs.js", "module": "dist/browserless/piano-analytics.esm.js", "browser": "dist/browser/piano-analytics.umd.js", diff --git a/src/business/ext/consent/consent.js b/src/business/ext/consent/consent.js index e51a945..f3d3b30 100644 --- a/src/business/ext/consent/consent.js +++ b/src/business/ext/consent/consent.js @@ -1,36 +1,28 @@ "use strict"; - import { localStorage } from "@piano-sdk/storage"; - var createConsentWrapper = function createConsentWrapper(config) { return function () { var consent2 = config.dataLayer.get("consent"); return consent2 && consent2[config.productName] || null; }; }; - var onDlChangeConsent = function onDlChangeConsent(config, cb) { var prevValue = null; - var _onChangeHandler = function _onChangeHandler(data) { var consent2 = (data === null || data === void 0 ? void 0 : data[config.productName]) || null; - if (consent2 !== prevValue) { prevValue = consent2; cb(consent2); } }; - config.dataLayer.addChangeListener("consent", _onChangeHandler); return function () { config.dataLayer.removeChangeListener(_onChangeHandler); }; }; - var createCheckConsentWrapper = function createCheckConsentWrapper(dataLayer, config) { return dataLayer.utils.checkConsent.createCheckConsentWrapper(config); }; - var itemsToNames = function itemsToNames(dataLayer, items, getNames) { var utils = dataLayer.utils.checkConsent; var masks = utils.itemsToMask(items); @@ -41,7 +33,6 @@ var itemsToNames = function itemsToNames(dataLayer, items, getNames) { return keys.includes(name) || utils.getByMask(name, masks); }); }; - var createBaseConsentStorage = function createBaseConsentStorage(storage2, itemType, config) { var getConsent = createConsentWrapper(config); var checkProperty = createCheckConsentWrapper(config.dataLayer, { @@ -49,22 +40,17 @@ var createBaseConsentStorage = function createBaseConsentStorage(storage2, itemT type: itemType, getConsent: getConsent }); - var _init = function _init() { var removeOnInit = config.checkConsentOnInit === void 0 ? config.enableAutoRemove : false; - if (config.enableAutoRemove) { onDlChangeConsent(config, onChangeConsentMode); } - if (removeOnInit) { onChangeConsentMode(getConsent()); } }; - var onChangeConsentMode = function onChangeConsentMode(consent2) { var _a; - (_a = checkProperty(itemsToNames(config.dataLayer, config.items, storage2.getNames), consent2)) === null || _a === void 0 ? void 0 : _a.forEach(function (item) { if (!item.allowed) { storage2.remove(item.name); @@ -73,37 +59,29 @@ var createBaseConsentStorage = function createBaseConsentStorage(storage2, itemT } }); }; - var set = function set(name, value, options) { var _a; - var consent2 = checkProperty(name); - if (consent2 === null || consent2 === void 0 ? void 0 : consent2.allowed) { var newValue = (_a = consent2.data) !== null && _a !== void 0 ? _a : value; var args = options ? [name, newValue, options] : [name, newValue]; storage2.set.apply(null, args); } }; - _init(); - return Object.assign({}, storage2, { set: set, check: checkProperty }); }; - var createTTLChecker = function createTTLChecker(dataLayer) { var name = localStorage.__protected__.ttlName; var config = { dataLayer: dataLayer, productName: "DL" }; - var check = function () { var _a; - var checker = createCheckConsentWrapper(config.dataLayer, { items: (_a = {}, _a[name] = "mandatory", _a), type: "localStorage", @@ -114,47 +92,36 @@ var createTTLChecker = function createTTLChecker(dataLayer) { return result.allowed && !result.data; }; }(); - var allowed = true; - var updateMemoValue = function updateMemoValue() { allowed = check(); - if (!allowed) { localStorage.remove(name); } }; - onDlChangeConsent(config, updateMemoValue); updateMemoValue(); return function () { return allowed; }; }; - var createLocalStorage = function createLocalStorage(config) { var checkTTL = createTTLChecker(config.dataLayer); var lsConsent = createBaseConsentStorage(localStorage, "localStorage", config); - var set = function set(name, value, options) { var newOptions = options; - if ((options === null || options === void 0 ? void 0 : options.expires) && !checkTTL()) { newOptions = Object.assign({}, options); delete newOptions.expires; } - return lsConsent.set(name, value, newOptions); }; - return Object.assign({}, lsConsent, { set: set }); }; - import { cookie } from "@piano-sdk/storage"; var ITEM_TYPE = "cookie"; - var createCookie = function createCookie(config) { var consentUtils = config.dataLayer.utils.checkConsent; var getConsent = createConsentWrapper(config); @@ -162,11 +129,9 @@ var createCookie = function createCookie(config) { var cookieOptionsByMasks = []; var items = {}; var cookieOptions = {}; - (function () { Object.keys(config.items).forEach(function (itemName) { var option = config.items[itemName]; - if (option.type) { var _a = option, type = _a.type, @@ -174,15 +139,12 @@ var createCookie = function createCookie(config) { path = _a.path; var options = {}; items[itemName] = type; - if (domain) { options.domain = domain; } - if (path) { options.path = path; } - if (consentUtils.isMask(itemName)) { cookieOptionsByMasks.push(consentUtils.createMask(itemName, options)); } else { @@ -193,34 +155,27 @@ var createCookie = function createCookie(config) { } }); })(); - var checkProperty = createCheckConsentWrapper(config.dataLayer, { items: items, type: ITEM_TYPE, getConsent: getConsent }); - var _init = function _init() { var removeOnInit = !!(config.checkConsentOnInit === void 0 ? config.enableAutoRemove : false); - if (config.enableAutoRemove) { cookieOptions = config.enableAutoRemove; onDlChangeConsent(config, onChangeConsentMode); } - if (removeOnInit) { onChangeConsentMode(getConsent()); } }; - var onChangeConsentMode = function onChangeConsentMode(consent2) { var _a; - (_a = checkProperty(itemsToNames(config.dataLayer, items, cookie.getNames), consent2)) === null || _a === void 0 ? void 0 : _a.forEach(function (item) { var getOptions = function getOptions() { return cookieOptionsByCookie[item.name] || consentUtils.getByMask(item.name, cookieOptionsByMasks) || cookieOptions; }; - if (!item.allowed) { cookie.remove(item.name, getOptions()); } else if (item.data) { @@ -228,31 +183,23 @@ var createCookie = function createCookie(config) { } }); }; - _init(); - var set = function set(name, value, options, limitValue) { var _a; - var consent2 = checkProperty(name); - if (consent2 === null || consent2 === void 0 ? void 0 : consent2.allowed) { cookie.set(name, (_a = consent2.data) !== null && _a !== void 0 ? _a : value, options, limitValue); } }; - return Object.assign({}, cookie, { check: checkProperty, set: set }); }; - import { sessionStorage } from "@piano-sdk/storage"; - var createSessionStorage = function createSessionStorage(config) { return createBaseConsentStorage(sessionStorage, "sessionStorage", config); }; - var createBasePropertyWrapper = function createBasePropertyWrapper(itemType, config) { return { check: createCheckConsentWrapper(config.dataLayer, { @@ -262,15 +209,12 @@ var createBasePropertyWrapper = function createBasePropertyWrapper(itemType, con }) }; }; - var createProperty = function createProperty(config) { return createBasePropertyWrapper("property", config); }; - var createEvent = function createEvent(config) { return createBasePropertyWrapper("event", config); }; - import * as storage from "@piano-sdk/storage"; var consent = { createLocalStorage: createLocalStorage, diff --git a/src/business/ext/data-layer/data-layer.js b/src/business/ext/data-layer/data-layer.js index 0ac127e..1556bb7 100644 --- a/src/business/ext/data-layer/data-layer.js +++ b/src/business/ext/data-layer/data-layer.js @@ -1,6 +1,6 @@ /** * @license - * Piano Browser SDK-DataLayer@2.9.4. + * Piano Browser SDK-DataLayer@2.9.5. * Copyright 2010-2022 Piano Software Inc. */ import { cookie } from '@piano-sdk/storage'; diff --git a/src/business/ext/storage/storage.js b/src/business/ext/storage/storage.js index f6080d4..21302f1 100644 --- a/src/business/ext/storage/storage.js +++ b/src/business/ext/storage/storage.js @@ -1,24 +1,19 @@ "use strict"; - var randomStr = function randomStr() { var date = new Date().getTime().toString(36); var prefix = Math.round(Math.random() * 2147483647).toString(36); return date + prefix; }; - var byteCount = function byteCount(str) { return encodeURI(str).split(/%(?:u[\dA-F]{2})?[\dA-F]{2}|./).length - 1; }; - var expiresToDate = function expiresToDate(expires) { var date = new Date(); - var increaseDays = function increaseDays(days2) { if (days2) { date.setDate(date.getDate() + days2); } }; - if (expires instanceof Date) { date = expires; } else if (typeof expires === "number") { @@ -28,33 +23,26 @@ var expiresToDate = function expiresToDate(expires) { days = _a.days, minutes = _a.minutes; increaseDays(days); - if (minutes) { date.setMinutes(date.getMinutes() + minutes); } } - return date; }; - var decode = function decode(s) { var res = s.replace(/\+/g, " ").replace(/^\s+|\s+$/g, ""); - try { return decodeURIComponent(res); } catch (e) { return res; } }; - var decodeValue = function decodeValue(s) { if (s.indexOf('"') === 0) { s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\"); } - return decode(s); }; - var cookie = function () { var _generateCookieString = function _generateCookieString(name, value, _a) { var _b = _a === void 0 ? {} : _a, @@ -63,34 +51,27 @@ var cookie = function () { expires = _b.expires, secure = _b.secure, samesite = _b.samesite, - raw = _b.raw; - - return (raw ? name : encodeURIComponent(name)) + "=" + (raw ? value : encodeURIComponent(value)) + (expires ? "; expires=".concat(expiresToDate(expires).toUTCString()) : "") + (path ? "; path=".concat(path) : "") + (domain ? "; domain=".concat(domain) : "") + (secure ? "; secure" : "") + (samesite ? typeof samesite === "boolean" ? "; sameSite" : "; sameSite=".concat(samesite) : ""); + raw = _b.raw, + priority = _b.priority; + return (raw ? name : encodeURIComponent(name)) + "=" + (raw ? value : encodeURIComponent(value)) + (expires ? "; expires=".concat(expiresToDate(expires).toUTCString()) : "") + (path ? "; path=".concat(path) : "") + (domain ? "; domain=".concat(domain) : "") + (secure ? "; secure" : "") + (samesite ? typeof samesite === "boolean" ? "; sameSite" : "; sameSite=".concat(samesite) : "") + (priority ? "; priority=".concat(priority) : ""); }; - var setCookie = function setCookie(name, value, cookieOptions, limitValue) { if (value === void 0 || limitValue !== void 0 && byteCount(value) > limitValue) { return; } - document.cookie = _generateCookieString(name, value, cookieOptions); }; - var parseCookie = function parseCookie(cb) { var allCookies = document.cookie.split(";"); - for (var i = 0; i < allCookies.length; i++) { var _cookie = allCookies[i].split("="); - var cookieName = decode(_cookie[0]); var cookieValue = _cookie[1] || ""; - if (cb(cookieName, cookieValue)) { return void 0; } } }; - function getCookie(name) { var result = null; var cookies = {}; @@ -104,14 +85,11 @@ var cookie = function () { cookies[cookieName] = decodeValue(cookieValue); } }); - if (name) { return result; } - return cookies; } - var getNames = function getNames() { var result = []; parseCookie(function (cookieName) { @@ -119,41 +97,37 @@ var cookie = function () { }); return result; }; - var removeCookie = function removeCookie(name, cookieOptions) { setCookie(name, "", Object.assign({}, cookieOptions, { expires: -1 })); }; - var getTopLevelDomain = function () { var testName = "_cookie_test"; + var secure = document.location.protocol === "https:"; return function (domainExceptions) { if (domainExceptions === void 0) { domainExceptions = []; } - var domainParts = window.location.hostname.split("."); var testValue = randomStr(); var expires = new Date(); expires.setSeconds(expires.getSeconds() + 30); - for (var i = 0; i < domainParts.length; i++) { try { var candidate = domainParts.slice(-(i + 1)).join("."); - if (!domainExceptions.includes(candidate)) { setCookie(testName, testValue, { expires: expires, path: "/", - domain: candidate + domain: candidate, + secure: secure }); var allowed = getCookie(testName) === testValue; removeCookie(testName, { path: "/", domain: candidate }); - if (allowed) { return candidate; } @@ -162,7 +136,6 @@ var cookie = function () { } }; }(); - return { set: setCookie, get: getCookie, @@ -174,29 +147,23 @@ var cookie = function () { } }; }(); - var localStorage = function () { var TTL_NAME_ITEMS = "_ls_ttl"; - var _checkTTl = function _checkTTl(ttl) { return ttl ? ttl > Date.now() : true; }; - var _parseTTLValues = function _parseTTLValues() { try { var value = window.localStorage.getItem(TTL_NAME_ITEMS); - if (value) { var obj = JSON.parse(value); return obj; } - return null; } catch (e) { return null; } }; - var _setTTLValues = function _setTTLValues(ttlValues) { try { if (Object.keys(ttlValues).length) { @@ -206,49 +173,34 @@ var localStorage = function () { } } catch (e) {} }; - var _saveTTLValues = function _saveTTLValues(name, expires) { var ttlValues = _parseTTLValues(); - if (expires === void 0) { if (ttlValues === null || ttlValues === void 0 ? void 0 : ttlValues[name]) { delete ttlValues[name]; - _setTTLValues(ttlValues); } - return true; } - var expiresTime = expiresToDate(expires).getTime(); - if (expiresTime > Date.now()) { ttlValues = ttlValues || {}; ttlValues[name] = expiresTime.toString(36); - _setTTLValues(ttlValues); - return true; } - return false; }; - var _checkTTLValues = function _checkTTLValues() { var names = _getNames(); - var ttls = _parseTTLValues(); - var ttlsUpdated = {}; - if (!ttls) { return; } - Object.keys(ttls).forEach(function (key) { if (names.includes(key)) { var expire = ttls[key] ? parseInt(ttls[key], 36) : null; - if (!_checkTTl(expire)) { try { window.localStorage.removeItem(key); @@ -258,24 +210,19 @@ var localStorage = function () { } } }); - if (JSON.stringify(ttls) !== JSON.stringify(ttlsUpdated)) { _setTTLValues(ttlsUpdated); } }; - var _get = function _get(key) { var _a; - _checkTTLValues(); - try { return (_a = window.localStorage.getItem(key)) !== null && _a !== void 0 ? _a : null; } catch (e) { return null; } }; - var _getNames = function _getNames() { try { return Object.keys(window.localStorage); @@ -283,29 +230,23 @@ var localStorage = function () { return []; } }; - var _set = function _set(key, value, options) { if (options === void 0) { options = {}; } - if (_saveTTLValues(key, options.expires)) { try { window.localStorage.setItem(key, value); } catch (e) {} } }; - var _remove = function _remove(key) { try { window.localStorage.removeItem(key); } catch (e) {} - _checkTTLValues(); }; - _checkTTLValues(); - return { get: _get, set: _set, @@ -316,11 +257,9 @@ var localStorage = function () { get ttlName() { return TTL_NAME_ITEMS; } - } }; }(); - var sessionStorage = function () { var _get = function _get(key) { try { @@ -329,19 +268,16 @@ var sessionStorage = function () { return null; } }; - var _set = function _set(key, value) { try { window.sessionStorage.setItem(key, value); } catch (e) {} }; - var _remove = function _remove(key) { try { window.sessionStorage.removeItem(key); } catch (e) {} }; - var _getNames = function _getNames() { try { return Object.keys(window.sessionStorage); @@ -349,7 +285,6 @@ var sessionStorage = function () { return []; } }; - return { get: _get, set: _set, @@ -357,5 +292,4 @@ var sessionStorage = function () { remove: _remove }; }(); - -export { cookie, localStorage, sessionStorage }; \ No newline at end of file +export { cookie, localStorage, sessionStorage }; diff --git a/src/config.js b/src/config.js index 847de5b..57e9e4d 100644 --- a/src/config.js +++ b/src/config.js @@ -23,7 +23,7 @@ export default { ], 'storageVisitor': 'pa_vid', 'storageUser': 'pa_user', - 'version': '6.13.0', + 'version': '6.13.1', 'minHeartbeat': 5, 'minBufferingHeartbeat': 1, 'queueVarName': '_paq',