Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lotame ID Module : honor publisher-supplied configuration object #12403

Merged
merged 1 commit into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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