Skip to content

Commit

Permalink
33Across User ID sub-module: Introduce first-party ID support (prebid…
Browse files Browse the repository at this point in the history
…#10714)

* Introduce first-party ID support to 33Across User ID sub-module. Resolves IDG-1216.

* Ensure first-party ID is removed for local storage in situations like GPP conssent change

* 33Across User ID sub-module: Add cookie storage support for first-party ID,

* 33Across User ID sub-module: Also remove first-party ID from cookie storage

* remove duplicated 33across ID test

* clear 33across ID from localstorage

* Add configuration flag for 1PID

* Suppress 33across ID requests where GDPR applies

---------

Co-authored-by: Joshua Poritz <joshua.poritz@33across.com>
Co-authored-by: Carlos Felix <carlos.felix@33across.com>
Co-authored-by: Aparna Rao <aparna.hegde@33across.com>
  • Loading branch information
4 people committed Feb 21, 2024
1 parent f5b71cd commit adbcf71
Show file tree
Hide file tree
Showing 3 changed files with 408 additions and 34 deletions.
94 changes: 79 additions & 15 deletions modules/33acrossIdSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
* @requires module:modules/userId
*/

import { logMessage, logError } from '../src/utils.js';
import { logMessage, logError, logWarn } from '../src/utils.js';
import { ajaxBuilder } from '../src/ajax.js';
import { submodule } from '../src/hook.js';
import { uspDataHandler, coppaDataHandler, gppDataHandler } from '../src/adapterManager.js';
import { getStorageManager, STORAGE_TYPE_COOKIES, STORAGE_TYPE_LOCALSTORAGE } from '../src/storageManager.js';
import { MODULE_TYPE_UID } from '../src/activities/modules.js';

/**
* @typedef {import('../modules/userId/index.js').Submodule} Submodule
Expand All @@ -20,35 +22,42 @@ const MODULE_NAME = '33acrossId';
const API_URL = 'https://lexicon.33across.com/v1/envelope';
const AJAX_TIMEOUT = 10000;
const CALLER_NAME = 'pbjs';
const GVLID = 58;

function getEnvelope(response) {
const STORAGE_FPID_KEY = '33acrossIdFp';

export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME });

function calculateResponseObj(response) {
if (!response.succeeded) {
if (response.error == 'Cookied User') {
logMessage(`${MODULE_NAME}: Unsuccessful response`.concat(' ', response.error));
} else {
logError(`${MODULE_NAME}: Unsuccessful response`.concat(' ', response.error));
}
return;
return {};
}

if (!response.data.envelope) {
logMessage(`${MODULE_NAME}: No envelope was received`);

return;
return {};
}

return response.data.envelope;
return {
envelope: response.data.envelope,
fp: response.data.fp
};
}

function calculateQueryStringParams(pid, gdprConsentData) {
function calculateQueryStringParams(pid, gdprConsentData, storageConfig) {
const uspString = uspDataHandler.getConsentData();
const gdprApplies = Boolean(gdprConsentData?.gdprApplies);
const coppaValue = coppaDataHandler.getCoppa();
const gppConsent = gppDataHandler.getConsentData();

const params = {
pid,
gdpr: Number(gdprApplies),
gdpr: 0,
src: CALLER_NAME,
ver: '$prebid.version$',
coppa: Number(coppaValue)
Expand All @@ -69,9 +78,49 @@ function calculateQueryStringParams(pid, gdprConsentData) {
params.gdpr_consent = gdprConsentData.consentString;
}

const fp = getStoredValue(STORAGE_FPID_KEY, storageConfig);
if (fp) {
params.fp = fp;
}

return params;
}

function deleteFromStorage(key) {
if (storage.cookiesAreEnabled()) {
const expiredDate = new Date(0).toUTCString();

storage.setCookie(key, '', expiredDate, 'Lax');
}

storage.removeDataFromLocalStorage(key);
}

function storeValue(key, value, storageConfig = {}) {
if (storageConfig.type === STORAGE_TYPE_COOKIES && storage.cookiesAreEnabled()) {
const expirationInMs = 60 * 60 * 24 * 1000 * storageConfig.expires;
const expirationTime = new Date(Date.now() + expirationInMs);

storage.setCookie(key, value, expirationTime.toUTCString(), 'Lax');
} else if (storageConfig.type === STORAGE_TYPE_LOCALSTORAGE) {
storage.setDataInLocalStorage(key, value);
}
}

function getStoredValue(key, storageConfig = {}) {
if (storageConfig.type === STORAGE_TYPE_COOKIES && storage.cookiesAreEnabled()) {
return storage.getCookie(key);
} else if (storageConfig.type === STORAGE_TYPE_LOCALSTORAGE) {
return storage.getDataFromLocalStorage(key);
}
}

function handleFpId(fpId, storageConfig = {}) {
fpId
? storeValue(STORAGE_FPID_KEY, fpId, storageConfig)
: deleteFromStorage(STORAGE_FPID_KEY);
}

/** @type {Submodule} */
export const thirthyThreeAcrossIdSubmodule = {
/**
Expand All @@ -80,7 +129,7 @@ export const thirthyThreeAcrossIdSubmodule = {
*/
name: MODULE_NAME,

gvlid: 58,
gvlid: GVLID,

/**
* decode the stored id value for passing to bid requests
Expand All @@ -102,34 +151,49 @@ export const thirthyThreeAcrossIdSubmodule = {
* @param {SubmoduleConfig} [config]
* @returns {IdResponse|undefined}
*/
getId({ params = { } }, gdprConsentData) {
getId({ params = { }, storage: storageConfig }, gdprConsentData) {
if (typeof params.pid !== 'string') {
logError(`${MODULE_NAME}: Submodule requires a partner ID to be defined`);

return;
}

const { pid, apiUrl = API_URL } = params;
if (gdprConsentData?.gdprApplies === true) {
logWarn(`${MODULE_NAME}: Submodule cannot be used where GDPR applies`);

return;
}

const { pid, storeFpid, apiUrl = API_URL } = params;

return {
callback(cb) {
ajaxBuilder(AJAX_TIMEOUT)(apiUrl, {
success(response) {
let envelope;
let responseObj = { };

try {
envelope = getEnvelope(JSON.parse(response))
responseObj = calculateResponseObj(JSON.parse(response));
} catch (err) {
logError(`${MODULE_NAME}: ID reading error:`, err);
}
cb(envelope);

if (!responseObj.envelope) {
deleteFromStorage(MODULE_NAME);
}

if (storeFpid) {
handleFpId(responseObj.fp, storageConfig);
}

cb(responseObj.envelope);
},
error(err) {
logError(`${MODULE_NAME}: ID error response`, err);

cb();
}
}, calculateQueryStringParams(pid, gdprConsentData), { method: 'GET', withCredentials: true });
}, calculateQueryStringParams(pid, gdprConsentData, storageConfig), { method: 'GET', withCredentials: true });
}
};
},
Expand Down
1 change: 1 addition & 0 deletions modules/33acrossIdSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ The following settings are available in the `params` property in `userSync.userI
| Param name | Scope | Type | Description | Example |
| --- | --- | --- | --- | --- |
| pid | Required | String | Partner ID provided by 33Across | `"0010b00002GYU4eBAH"` |
| storeFpid | Optional | Boolean | Indicates whether a supplemental first-party ID may be stored to improve addressability | `false` (default) or `true` |
Loading

0 comments on commit adbcf71

Please sign in to comment.