UNPKG

xcoobee-cookie-kit-core

Version:

GDPR / CCPA Easy Cookie, Script, and Fingerprint Consent Management for Websites

323 lines (256 loc) 9.89 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; /* global XcooBee */ /** * Sets cookies * * @param {String} name the name of cookie * @param {String} value the value of cookie * @param {Number} days optional: the number of days to persist cookie, if not provided will become session cookie */ function xckSetCookie(name, value, days) { var expires = ""; if (days) { var date = new Date(); date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000); expires = "; expires=".concat(date.toUTCString()); } document.cookie = "".concat(name, "=").concat(value || "").concat(expires, "; path=/"); } /** * Deletes cookie with given name * * @param {String} name the name of cookie */ function xckEraseCookie(name) { document.cookie = "".concat(name, "=; Max-Age=-99999999; path=/"); } /** * Retrieves array of cookie names * * @returns {Array} array of cookie names */ function xckGetCookieNames() { var ca = document.cookie.split(";"); var ra = []; for (var i = 0; i < ca.length; i++) { var c = ca[i].split("=")[0].trim(); ra.push(c); } return ra; } /** * Compares two arrays, return array of elements contained in newArray not part of oldArray * * @param {Array} oldArray the initial array to compare against * @param {Array} newArray the second array. Only elements from this array will be returned * @returns {Array} array of elements only contained in newArray */ function xckReturnNewElements(oldArray, newArray) { var ra = []; for (var i = 0; i < newArray.length; i++) { var item = newArray[i]; if (oldArray.indexOf(item) === -1) { ra.push(item); } } return ra; } /** * Updates our local store with cookies that have been set for a given category so far * * @param {Array} aInitialCookies - The array of cookies that were set before script was run * @param {String} category - cookie category related to this load */ function xckSaveCookieState(aInitialCookies, category) { var aNewCookies = xckGetCookieNames(); var aAddedCookies = xckReturnNewElements(aInitialCookies, aNewCookies); // Check what cookies are set now and save this to our local store if (typeof category !== "undefined") { // Load and save the cookies set for this category var storeName = "xck_cat_".concat(category); var currentCategoryCookies = localStorage.getItem(storeName); if (aAddedCookies.length > 0) { if (currentCategoryCookies === null) { currentCategoryCookies = aAddedCookies.join(); } else { currentCategoryCookies = "".concat(currentCategoryCookies, ",").concat(aAddedCookies.join()); } localStorage.setItem(storeName, currentCategoryCookies); } } } /** * Loads Javascript. Can load from remote file or code. * * @param {Object} loadScripts - The HTMLCollection of script tags to be loaded * @param {String} category - cookie category related to this load */ function xckLoadJs(loadScripts, category) { var aInitialCookies = xckGetCookieNames(); if (loadScripts.length > 0) { var _loop = function _loop(i) { var item = loadScripts[i]; var script = document.createElement("script"); if (item.src === "") { script.text = item.text; } else { // Load from file script.async = true; // we always load async script.src = item.src; // After script is loaded we need to process the cookie state script.onload = function onload() { if (XcooBee.kit.getParam("testMode") && item.src !== "") { // eslint-disable-next-line no-console console.log("Cookie script from ".concat(item.src, " is ready!")); } xckSaveCookieState(aInitialCookies, category); }; // Other elements if (item.integrity !== "") { script.integrity = item.integrity; } if (item.crossOrigin !== "") { script.crossOrigin = item.crossOrigin; } } // Now append to document for execution and save cookie state document.body.appendChild(script); if (item.src === "") { xckSaveCookieState(aInitialCookies, category); } }; for (var i = 0; i < loadScripts.length; i++) { _loop(i); } } } /** * Removes cookies for categories without consent. * Clears all cookies crated by scripts that have no longer consent from user. * * @param {Object} cookieTypes - The object collection of cookie categories consented by user */ function xckClearCookies(cookieTypes) { var entries = Object.entries(cookieTypes); for (var i = 0; i < entries.length; i++) { var category = entries[i]; var storeName = "xck_cat_".concat(category[0]); // Check whether we need to delete the category if (!category[1]) { var currentSetCookies = localStorage.getItem(storeName); if (currentSetCookies !== null) { var cookies = currentSetCookies.split(","); // Iterate and delete for (var j = 0; j < cookies.length; j++) { xckEraseCookie(cookies[j]); } // Clear local storage localStorage.removeItem(storeName); } } } } /** * Parse html encoded script directives * * @param {Array} htmlData - string with script tags to be loaded * @return {Object} the fully parsed html elements in HtmlCollection */ function xckParseHtml(htmlData) { // Parse encoded via text area var txt = document.createElement("textarea"); txt.innerHTML = htmlData; // Now add this as html to our shadow doc var el = document.createElement("html"); el.innerHTML = txt.innerText; return el; } /** * Scans document for HTML defined xbee-script tags and converts them into * scripts that will be loaded once user grants consent. Will also look for * unset scripts when user removes consent. * * @param {Object} cookieTypes object with true/false for each user cookie type. * Example Object { application: false, usage: true, statistics: false, advertising: false } */ function xckHandleXbeeScriptTags(cookieTypes) { var xbeCookieScripts = document.getElementsByTagName("xbee-script"); var i = 0; var resolvedScripts = ""; if (xbeCookieScripts.length > 0 && XcooBee.kit.getConsentStatus() === "complete") { for (i = 0; i < xbeCookieScripts.length; i++) { var item = xbeCookieScripts[i]; var script = item.outerHTML; resolvedScripts = ""; try { // We use this notation to cause error when required attributes are not present var scriptAction = item.attributes.action.value; var scriptCategory = item.attributes.category.value; // For setting continue if user has responded, we are allowed the category, and action matches if (scriptAction === "set" && cookieTypes[scriptCategory]) { // Replace xbee-script with script script = script.replace(/xbee-script/ig, "script"); resolvedScripts += script; } // For un-setting getCookieTypes() has to be false we use separate condition for easier readability if (scriptAction === "unset" && !cookieTypes[scriptCategory]) { // Replace xbee-script with script script = script.replace(/xbee-script/ig, "script"); resolvedScripts += script; } // Parse and load text scripts if we can find them if (resolvedScripts !== "") { var runnableScripts = xckParseHtml(resolvedScripts); // Load scripts presumably to set cookies xckLoadJs(runnableScripts.getElementsByTagName("script"), scriptCategory); } } catch (error) { // Error happened var msg = "Tag caused error, please make sure you have supplied required attributes:"; console.error(msg, script.substr(0, 40)); if (XcooBee.kit.getParam("testMode")) { console.error(error); } } } } } /** * Scans document for HTML defined xbee-cookie tags and sets or removes cookies * once user grants consent. * * @param {Object} cookieTypes object with true/false for each user cookie category. * Example Object { application: false, usage: true, statistics: false, advertising: false } */ function xckHandleXbeeCookieTags(cookieTypes) { var xbeCookieTags = document.getElementsByTagName("xbee-cookie"); var i = 0; if (xbeCookieTags.length > 0 && XcooBee.kit.getConsentStatus() === "complete") { for (i = 0; i < xbeCookieTags.length; i++) { var item = xbeCookieTags[i]; var cookieValue = item.innerHTML; var itemOuter = item.outerHTML; try { // We use the array notation since it will throw error when we have missing required attributes cookieValue = cookieValue.replace(/\r?\n|\r/g, ""); // Remove CRLF var cookieName = item.attributes.name.value; var cookieCategory = item.attributes.category.value; var cookieDays = 0; // Days is optional so we use this notation to retrieve it if (item.attributes.getNamedItem("days") !== null) { cookieDays = parseInt(item.attributes("days"), 10); } // Set or erase this cookie based on whether category is allowed if (cookieTypes[cookieCategory]) { // Set cookie xckSetCookie(cookieName, cookieValue, cookieDays); } else { // Erase cookie xckEraseCookie(cookieName); } } catch (error) { // Error happened console.error("error in cookie definition in tag:", itemOuter.substr(0, 30)); if (XcooBee.kit.getParam("testMode")) { console.error(error); } } } } } var _default = { xckClearCookies: xckClearCookies, xckHandleXbeeScriptTags: xckHandleXbeeScriptTags, xckHandleXbeeCookieTags: xckHandleXbeeCookieTags }; exports.default = _default;