Skip to content

Commit

Permalink
Updates the Lotame User ID module to honor a publisher-supplied stora…
Browse files Browse the repository at this point in the history
…ge configuration object
  • Loading branch information
Tonsil committed Nov 13, 2024
1 parent 655712c commit 5ee5f03
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 190 deletions.
115 changes: 62 additions & 53 deletions modules/lotamePanoramaIdSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@ import {
isBoolean,
buildUrl,
isEmpty,
isArray,
isEmptyStr
isArray
} from '../src/utils.js';
import { ajax } from '../src/ajax.js';
import { submodule } from '../src/hook.js';
import {getStorageManager} from '../src/storageManager.js';
import { uspDataHandler } from '../src/adapterManager.js';
import {MODULE_TYPE_UID} from '../src/activities/modules.js';

/**
Expand All @@ -38,16 +36,24 @@ const MISSING_CORE_CONSENT = 111;
const GVLID = 95;
const ID_HOST = 'id.crwdcntrl.net';
const ID_HOST_COOKIELESS = 'c.ltmsphrcl.net';
const DO_NOT_HONOR_CONFIG = false;

export const storage = getStorageManager({moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME});
let cookieDomain;
let appliedConfig = {
name: 'lotamePanoramaId',
storage: {
type: 'cookie&html5',
name: 'panoramaId'
}
};

/**
* Set the Lotame First Party Profile ID in the first party namespace
* @param {String} profileId
*/
function setProfileId(profileId) {
if (storage.cookiesAreEnabled()) {
if (cookiesAreEnabled()) {
let expirationDate = new Date(timestamp() + NINE_MONTHS_MS).toUTCString();
storage.setCookie(
KEY_PROFILE,
Expand All @@ -58,7 +64,7 @@ function setProfileId(profileId) {
undefined
);
}
if (storage.hasLocalStorage()) {
if (localStorageIsEnabled()) {
storage.setDataInLocalStorage(KEY_PROFILE, profileId, undefined);
}
}
Expand All @@ -68,10 +74,10 @@ function setProfileId(profileId) {
*/
function getProfileId() {
let profileId;
if (storage.cookiesAreEnabled()) {
if (cookiesAreEnabled(DO_NOT_HONOR_CONFIG)) {
profileId = storage.getCookie(KEY_PROFILE, undefined);
}
if (!profileId && storage.hasLocalStorage()) {
if (!profileId && localStorageIsEnabled(DO_NOT_HONOR_CONFIG)) {
profileId = storage.getDataFromLocalStorage(KEY_PROFILE, undefined);
}
return profileId;
Expand All @@ -83,21 +89,11 @@ function getProfileId() {
*/
function getFromStorage(key) {
let value = null;
if (storage.cookiesAreEnabled()) {
if (cookiesAreEnabled(DO_NOT_HONOR_CONFIG)) {
value = storage.getCookie(key, undefined);
}
if (storage.hasLocalStorage() && value === null) {
const storedValueExp = storage.getDataFromLocalStorage(
`${key}_exp`, undefined
);

if (storedValueExp === '' || storedValueExp === null) {
value = storage.getDataFromLocalStorage(key, undefined);
} else if (storedValueExp) {
if ((new Date(parseInt(storedValueExp, 10))).getTime() - Date.now() > 0) {
value = storage.getDataFromLocalStorage(key, undefined);
}
}
if (value === null && localStorageIsEnabled(DO_NOT_HONOR_CONFIG)) {
value = storage.getDataFromLocalStorage(key, undefined);
}
return value;
}
Expand All @@ -115,7 +111,7 @@ function saveLotameCache(
) {
if (key && value) {
let expirationDate = new Date(expirationTimestamp).toUTCString();
if (storage.cookiesAreEnabled()) {
if (cookiesAreEnabled()) {
storage.setCookie(
key,
value,
Expand All @@ -125,12 +121,7 @@ function saveLotameCache(
undefined
);
}
if (storage.hasLocalStorage()) {
storage.setDataInLocalStorage(
`${key}_exp`,
String(expirationTimestamp),
undefined
);
if (localStorageIsEnabled()) {
storage.setDataInLocalStorage(key, value, undefined);
}
}
Expand Down Expand Up @@ -172,7 +163,7 @@ function getLotameLocalCache(clientId = undefined) {
*/
function clearLotameCache(key) {
if (key) {
if (storage.cookiesAreEnabled()) {
if (cookiesAreEnabled(DO_NOT_HONOR_CONFIG)) {
let expirationDate = new Date(0).toUTCString();
storage.setCookie(
key,
Expand All @@ -183,11 +174,50 @@ function clearLotameCache(key) {
undefined
);
}
if (storage.hasLocalStorage()) {
if (localStorageIsEnabled(DO_NOT_HONOR_CONFIG)) {
storage.removeDataFromLocalStorage(key, undefined);
}
}
}
/**
* @param {boolean} honorConfig - false to override for reading or deleting old cookies
* @returns {boolean} for whether we can write the cookie
*/
function cookiesAreEnabled(honorConfig = true) {
if (honorConfig) {
return storage.cookiesAreEnabled() && appliedConfig.storage.type.includes('cookie');
}
return storage.cookiesAreEnabled();
}
/**
* @param {boolean} honorConfig - false to override for reading or deleting old stored items
* @returns {boolean} for whether we can write the cookie
*/
function localStorageIsEnabled(honorConfig = true) {
if (honorConfig) {
return storage.hasLocalStorage() && appliedConfig.storage.type.includes('html5');
}
return storage.hasLocalStorage();
}
/**
* @param {SubmoduleConfig} config
* @returns {null|string} - string error if it finds one, null otherwise.
*/
function checkConfigHasErrorsAndReport(config) {
let error = null;
if (typeof config.storage !== 'undefined') {
Object.assign(appliedConfig.storage, appliedConfig.storage, config.storage);
const READABLE_MODULE_NAME = 'Lotame ID module';
const PERMITTED_STORAGE_TYPES = ['cookie', 'html5', 'cookie&html5'];
if (typeof config.storage.name !== 'undefined' && config.storage.name !== KEY_ID) {
logError(`Misconfigured ${READABLE_MODULE_NAME}, "storage.name" is expected to be "${KEY_ID}", actual is "${config.storage.name}"`);
error = true;
} else if (config.storage.type !== 'undefined' && !PERMITTED_STORAGE_TYPES.includes(config.storage.type)) {
logError(`Misconfigured ${READABLE_MODULE_NAME}, "storage.type" is expected to be one of "${PERMITTED_STORAGE_TYPES.join(', ')}", actual is "${config.storage.type}"`);
}
}
return error;
}
/** @type {Submodule} */
export const lotamePanoramaIdSubmodule = {
/**
Expand Down Expand Up @@ -222,6 +252,9 @@ export const lotamePanoramaIdSubmodule = {
* @returns {IdResponse|undefined}
*/
getId(config, consentData, cacheIdObj) {
if (checkConfigHasErrorsAndReport(config)) {
return;
}
cookieDomain = lotamePanoramaIdSubmodule.findRootDomain();
const configParams = (config && config.params) || {};
const clientId = configParams.clientId;
Expand Down Expand Up @@ -249,18 +282,6 @@ export const lotamePanoramaIdSubmodule = {

const storedUserId = getProfileId();

// Add CCPA Consent data handling
const usp = uspDataHandler.getConsentData();

let usPrivacy;
if (typeof usp !== 'undefined' && !isEmpty(usp) && !isEmptyStr(usp)) {
usPrivacy = usp;
}
if (!usPrivacy) {
// fallback to 1st party cookie
usPrivacy = getFromStorage('us_privacy');
}

const getRequestHost = function() {
if (navigator.userAgent && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
return ID_HOST_COOKIELESS;
Expand All @@ -281,22 +302,10 @@ export const lotamePanoramaIdSubmodule = {
}
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;
}

// Add usPrivacy to the url
if (usPrivacy) {
queryParams.us_privacy = usPrivacy;
}

// Add clientId to the url
if (hasCustomClientId) {
queryParams.c = clientId;
Expand Down
31 changes: 27 additions & 4 deletions modules/lotamePanoramaIdSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,32 @@ Retrieve the Lotame Panorama Id
pbjs.setConfig({
usersync: {
userIds: [
{
name: 'lotamePanoramaId' // The only parameter that is needed
}],
{
name: 'lotamePanoramaId',
storage: {
name: 'panoramaId',
type: 'cookie&html5',
expires: 7
}
}
],
}
});
```
```

| Parameters under `userSync.userIds[]` | Scope | Type | Description | Example |
| ---| --- | --- | --- | --- |
| name | Required | String | Name for the Lotame ID submodule | `"lotamePanoramaId"` |
| storage | Optional | Object | Configures how to cache User IDs locally in the browser | See [storage settings](#storage-settings) |


### Storage Settings

The following settings are available for the `storage` property in the `userSync.userIds[]` object. Please note that inclusion of the `storage` property is optional, but if provided, all three attributes listed below *must* be specified:

| Param name | Scope | Type | Description | Example |
| --- | --- | --- | --- | --- |
| name | Required | String| Name of the cookie or localStorage where the user ID will be stored; *must* be `"panoramaId"` | `"panoramaId"` |
| type | Required | String | `"cookie&html5"` (preferred) or `"cookie"` or `"html5"` | `"cookie&html5"` |
| expires | Required | Number | How long (in days) the user ID information will be stored. Lotame recommends `7`. | `7` |

Loading

0 comments on commit 5ee5f03

Please sign in to comment.