UNPKG

mk9-prebid

Version:

Header Bidding Management Library

289 lines (265 loc) 7.56 kB
/** * This module adds LotamePanoramaId to the User ID module * The {@link module:modules/userId} module is required * @module modules/lotamePanoramaId * @requires module:modules/userId */ import * as utils from '../src/utils.js'; import { ajax } from '../src/ajax.js'; import { submodule } from '../src/hook.js'; import { getStorageManager } from '../src/storageManager.js'; const KEY_ID = 'panoramaId'; const KEY_EXPIRY = `${KEY_ID}_expiry`; const KEY_PROFILE = '_cc_id'; const MODULE_NAME = 'lotamePanoramaId'; const NINE_MONTHS_MS = 23328000 * 1000; const DAYS_TO_CACHE = 7; const DAY_MS = 60 * 60 * 24 * 1000; const MISSING_CORE_CONSENT = 111; const GVLID = 95; export const storage = getStorageManager(GVLID, MODULE_NAME); let cookieDomain; /** * Set the Lotame First Party Profile ID in the first party namespace * @param {String} profileId */ function setProfileId(profileId) { if (storage.cookiesAreEnabled()) { let expirationDate = new Date(utils.timestamp() + NINE_MONTHS_MS).toUTCString(); storage.setCookie( KEY_PROFILE, profileId, expirationDate, 'Lax', cookieDomain, undefined ); } if (storage.hasLocalStorage()) { storage.setDataInLocalStorage(KEY_PROFILE, profileId, undefined); } } /** * Get the Lotame profile id by checking cookies first and then local storage */ function getProfileId() { if (storage.cookiesAreEnabled()) { return storage.getCookie(KEY_PROFILE, undefined); } if (storage.hasLocalStorage()) { return storage.getDataFromLocalStorage(KEY_PROFILE, undefined); } } /** * Get a value from browser storage by checking cookies first and then local storage * @param {String} key */ function getFromStorage(key) { let value = null; if (storage.cookiesAreEnabled()) { value = storage.getCookie(key, undefined); } if (storage.hasLocalStorage() && value === null) { const storedValueExp = storage.getDataFromLocalStorage( `${key}_exp`, undefined ); if (storedValueExp === '') { value = storage.getDataFromLocalStorage(key, undefined); } else if (storedValueExp) { if ((new Date(storedValueExp)).getTime() - Date.now() > 0) { value = storage.getDataFromLocalStorage(key, undefined); } } } return value; } /** * Save a key/value pair to the browser cache (cookies and local storage) * @param {String} key * @param {String} value * @param {Number} expirationTimestamp */ function saveLotameCache( key, value, expirationTimestamp = utils.timestamp() + DAYS_TO_CACHE * DAY_MS ) { if (key && value) { let expirationDate = new Date(expirationTimestamp).toUTCString(); if (storage.cookiesAreEnabled()) { storage.setCookie( key, value, expirationDate, 'Lax', cookieDomain, undefined ); } if (storage.hasLocalStorage()) { storage.setDataInLocalStorage( `${key}_exp`, String(expirationTimestamp), undefined ); storage.setDataInLocalStorage(key, value, undefined); } } } /** * Retrieve all the cached values from cookies and/or local storage */ function getLotameLocalCache() { let cache = { data: getFromStorage(KEY_ID), expiryTimestampMs: 0, }; try { const rawExpiry = getFromStorage(KEY_EXPIRY); if (utils.isStr(rawExpiry)) { cache.expiryTimestampMs = parseInt(rawExpiry, 10); } } catch (error) { utils.logError(error); } return cache; } /** * Clear a cached value from cookies and local storage * @param {String} key */ function clearLotameCache(key) { if (key) { if (storage.cookiesAreEnabled()) { let expirationDate = new Date(0).toUTCString(); storage.setCookie( key, '', expirationDate, 'Lax', cookieDomain, undefined ); } if (storage.hasLocalStorage()) { storage.removeDataFromLocalStorage(key, undefined); } } } /** @type {Submodule} */ export const lotamePanoramaIdSubmodule = { /** * used to link submodule with config * @type {string} */ name: MODULE_NAME, /** * Vendor id of Lotame * @type {Number} */ gvlid: GVLID, /** * Decode the stored id value for passing to bid requests * @function decode * @param {(Object|string)} value * @param {SubmoduleConfig|undefined} config * @returns {(Object|undefined)} */ decode(value, config) { return utils.isStr(value) ? { lotamePanoramaId: value } : undefined; }, /** * Retrieve the Lotame Panorama Id * @function * @param {SubmoduleConfig} [config] * @param {ConsentData} [consentData] * @param {(Object|undefined)} cacheIdObj * @returns {IdResponse|undefined} */ getId(config, consentData, cacheIdObj) { cookieDomain = lotamePanoramaIdSubmodule.findRootDomain(); let localCache = getLotameLocalCache(); let refreshNeeded = Date.now() > localCache.expiryTimestampMs; if (!refreshNeeded) { return { id: localCache.data, }; } const storedUserId = getProfileId(); const resolveIdFunction = function (callback) { let queryParams = {}; if (storedUserId) { queryParams.fp = storedUserId; } let consentString; if (consentData) { if (utils.isBoolean(consentData.gdprApplies)) { queryParams.gdpr_applies = consentData.gdprApplies; } consentString = consentData.consentString; } // If no consent string, try to read it from 1st party cookies if (!consentString) { consentString = getFromStorage('eupubconsent-v2'); } if (!consentString) { consentString = getFromStorage('euconsent-v2'); } if (consentString) { queryParams.gdpr_consent = consentString; } const url = utils.buildUrl({ protocol: 'https', host: `id.crwdcntrl.net`, pathname: '/id', search: utils.isEmpty(queryParams) ? undefined : queryParams, }); ajax( url, (response) => { let coreId; if (response) { try { let responseObj = JSON.parse(response); const shouldUpdateProfileId = !( utils.isArray(responseObj.errors) && responseObj.errors.indexOf(MISSING_CORE_CONSENT) !== -1 ); saveLotameCache(KEY_EXPIRY, responseObj.expiry_ts, responseObj.expiry_ts); if (utils.isStr(responseObj.profile_id)) { if (shouldUpdateProfileId) { setProfileId(responseObj.profile_id); } if (utils.isStr(responseObj.core_id)) { saveLotameCache( KEY_ID, responseObj.core_id, responseObj.expiry_ts ); coreId = responseObj.core_id; } else { clearLotameCache(KEY_ID); } } else { if (shouldUpdateProfileId) { clearLotameCache(KEY_PROFILE); } clearLotameCache(KEY_ID); } } catch (error) { utils.logError(error); } } callback(coreId); }, undefined, { method: 'GET', withCredentials: true, } ); }; return { callback: resolveIdFunction }; }, }; submodule('userId', lotamePanoramaIdSubmodule);