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

Userid module: change support for multiple sources in a single eid #8499

Merged
merged 2 commits into from
Jun 7, 2022
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
74 changes: 43 additions & 31 deletions modules/merkleIdSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {submodule} from '../src/hook.js'
import {getStorageManager} from '../src/storageManager.js';

const MODULE_NAME = 'merkleId';
const ID_URL = 'https://id2.sv.rkdms.com/identity/';
const ID_URL = 'https://prebid.sv.rkdms.com/identity/';
const DEFAULT_REFRESH = 7 * 3600;
const SESSION_COOKIE_NAME = '_svsid';

Expand All @@ -30,19 +30,19 @@ function getSession(configParams) {
function setCookie(name, value, expires) {
let expTime = new Date();
expTime.setTime(expTime.getTime() + expires * 1000 * 60);
storage.setCookie(name, value, expTime.toUTCString());
storage.setCookie(name, value, expTime.toUTCString(), 'Lax');
}

function setSession(storage, response) {
logInfo('Merkle setting session ');
if (response && response.c && response.c.value && typeof response.c.value === 'string') {
setCookie(SESSION_COOKIE_NAME, response.c.value, storage.expires);
logInfo('Merkle setting ' + `${SESSION_COOKIE_NAME}`);
if (response && response[SESSION_COOKIE_NAME] && typeof response[SESSION_COOKIE_NAME] === 'string') {
setCookie(SESSION_COOKIE_NAME, response[SESSION_COOKIE_NAME], storage.expires);
}
}

function constructUrl(configParams) {
const session = getSession(configParams);
let url = configParams.endpoint + `?vendor=${configParams.vendor}&sv_cid=${configParams.sv_cid}&sv_domain=${configParams.sv_domain}&sv_pubid=${configParams.sv_pubid}`;
let url = configParams.endpoint + `?sv_domain=${configParams.sv_domain}&sv_pubid=${configParams.sv_pubid}&ssp_ids=${configParams.ssp_ids.join()}`;
if (session) {
url = `${url}&sv_session=${session}`;
}
Expand Down Expand Up @@ -86,52 +86,60 @@ function generateId(configParams, configStorage) {
/** @type {Submodule} */
export const merkleIdSubmodule = {
/**
* used to link submodule with config
* @type {string}
*/
* used to link submodule with config
* @type {string}
*/
name: MODULE_NAME,

/**
* decode the stored id value for passing to bid requests
* @function
* @param {string} value
* @returns {{merkleId:string}}
*/
* decode the stored id value for passing to bid requests
* @function
* @param {string} value
* @returns {{eids:arrayofields}}
*/
decode(value) {
// Legacy support for a single id
const id = (value && value.pam_id && typeof value.pam_id.id === 'string') ? value.pam_id : undefined;
logInfo('Merkle id ' + JSON.stringify(id));
return id ? {'merkleId': id} : undefined;

if (id) {
return {'merkleId': id}
}

// Supports multiple IDs for different SSPs
const merkleIds = (value && value?.merkleId && Array.isArray(value.merkleId)) ? value.merkleId : undefined;
logInfo('merkleIds: ' + JSON.stringify(merkleIds));

return merkleIds ? {'merkleId': merkleIds} : undefined;
},

/**
* performs action to obtain id and return a value in the callback's response argument
* @function
* @param {SubmoduleConfig} [config]
* @param {ConsentData} [consentData]
* @returns {IdResponse|undefined}
*/
* performs action to obtain id and return a value in the callback's response argument
* @function
* @param {SubmoduleConfig} [config]
* @param {ConsentData} [consentData]
* @returns {IdResponse|undefined}
*/
getId(config, consentData) {
logInfo('User ID - merkleId generating id');

const configParams = (config && config.params) || {};

if (!configParams || typeof configParams.vendor !== 'string') {
logError('User ID - merkleId submodule requires a valid vendor to be defined');
return;
}

if (typeof configParams.sv_cid !== 'string') {
logError('User ID - merkleId submodule requires a valid sv_cid string to be defined');
if (typeof configParams.sv_pubid !== 'string') {
logError('User ID - merkleId submodule requires a valid sv_pubid string to be defined');
return;
}

if (typeof configParams.sv_pubid !== 'string') {
logError('User ID - merkleId submodule requires a valid sv_pubid string to be defined');
if (!Array.isArray(configParams.ssp_ids)) {
logError('User ID - merkleId submodule requires a valid ssp_ids array to be defined');
return;
}

if (consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies) {
logError('User ID - merkleId submodule does not currently handle consent strings');
return;
}

if (typeof configParams.endpoint !== 'string') {
logWarn('User ID - merkleId submodule endpoint string is not defined');
configParams.endpoint = ID_URL
Expand All @@ -146,7 +154,7 @@ export const merkleIdSubmodule = {
return {callback: resp};
},
extendId: function (config = {}, consentData, storedId) {
logInfo('User ID - merkleId stored id ' + storedId);
logInfo('User ID - stored id ' + storedId);
const configParams = (config && config.params) || {};

if (typeof configParams.endpoint !== 'string') {
Expand All @@ -162,15 +170,18 @@ export const merkleIdSubmodule = {
if (typeof configParams.sv_domain !== 'string') {
configParams.sv_domain = merkleIdSubmodule.findRootDomain();
}

const configStorage = (config && config.storage) || {};
if (configStorage && configStorage.refreshInSeconds && typeof configParams.refreshInSeconds === 'number') {
return {id: storedId};
}

let refreshInSeconds = DEFAULT_REFRESH;
if (configParams && configParams.refreshInSeconds && typeof configParams.refreshInSeconds === 'number') {
refreshInSeconds = configParams.refreshInSeconds;
logInfo('User ID - merkleId param refreshInSeconds' + refreshInSeconds);
}

const storedDate = new Date(storedId.date);
let refreshNeeded = false;
if (storedDate) {
Expand All @@ -181,6 +192,7 @@ export const merkleIdSubmodule = {
return {callback: resp};
}
}

logInfo('User ID - merkleId not refreshed');
return {id: storedId};
}
Expand Down
30 changes: 25 additions & 5 deletions modules/userId/eids.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,15 +151,25 @@ export const USER_IDS_CONFIG = {

// merkleId
'merkleId': {
source: 'merkleinc.com',
atype: 3,
getSource: function(data) {
if (data?.ext?.ssp) {
return `${data.ext.ssp}.merkleinc.com`
}
return 'merkleinc.com'
},
getValue: function(data) {
return data.id;
},
getUidExt: function(data) {
return (data && data.keyID) ? {
keyID: data.keyID
} : undefined;
if (data.keyID) {
return {
keyID: data.keyID
}
}
if (data.ext) {
return data.ext;
}
}
},

Expand Down Expand Up @@ -327,7 +337,8 @@ function createEidObject(userIdData, subModuleKey) {
const conf = USER_IDS_CONFIG[subModuleKey];
if (conf && userIdData) {
let eid = {};
eid.source = conf['source'];
eid.source = isFn(conf['getSource']) ? conf['getSource'](userIdData) : conf['source'];

const value = isFn(conf['getValue']) ? conf['getValue'](userIdData) : userIdData;
if (isStr(value)) {
const uid = { id: value, atype: conf['atype'] };
Expand Down Expand Up @@ -357,10 +368,19 @@ function createEidObject(userIdData, subModuleKey) {
// if any adapter does not want any particular userId to be passed then adapter can use Array.filter(e => e.source != 'tdid')
export function createEidsArray(bidRequestUserId) {
let eids = [];

for (const subModuleKey in bidRequestUserId) {
if (bidRequestUserId.hasOwnProperty(subModuleKey)) {
if (subModuleKey === 'pubProvidedId') {
eids = eids.concat(bidRequestUserId['pubProvidedId']);
} else if (Array.isArray(bidRequestUserId[subModuleKey])) {
bidRequestUserId[subModuleKey].forEach((config, index, arr) => {
const eid = createEidObject(config, subModuleKey);

if (eid) {
eids.push(eid);
}
})
} else {
const eid = createEidObject(bidRequestUserId[subModuleKey], subModuleKey);
if (eid) {
Expand Down
51 changes: 48 additions & 3 deletions test/spec/modules/eids_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,65 @@ describe('eids array generation for known sub-modules', function() {
});
});

it('merkleId', function() {
it('merkleId (legacy) - supports single id', function() {
const userId = {
merkleId: {
id: 'some-random-id-value', keyID: 1
}
};
const newEids = createEidsArray(userId);

expect(newEids.length).to.equal(1);
expect(newEids[0]).to.deep.equal({
source: 'merkleinc.com',
uids: [{
id: 'some-random-id-value',
atype: 3,
ext: { keyID: 1 }
}]
});
});

it('merkleId supports multiple source providers', function() {
const userId = {
merkleId: [{
id: 'some-random-id-value', ext: { enc: 1, keyID: 16, idName: 'pamId', ssp: 'ssp1' }
}, {
id: 'another-random-id-value',
ext: {
enc: 1,
idName: 'pamId',
third: 4,
ssp: 'ssp2'
}
}]
}

const newEids = createEidsArray(userId);
expect(newEids.length).to.equal(2);
expect(newEids[0]).to.deep.equal({
source: 'ssp1.merkleinc.com',
uids: [{id: 'some-random-id-value',
atype: 3,
ext: { keyID: 1
}}]
ext: {
enc: 1,
keyID: 16,
idName: 'pamId',
ssp: 'ssp1'
}
}]
});
expect(newEids[1]).to.deep.equal({
source: 'ssp2.merkleinc.com',
uids: [{id: 'another-random-id-value',
atype: 3,
ext: {
third: 4,
enc: 1,
idName: 'pamId',
ssp: 'ssp2'
}
}]
});
});

Expand Down
Loading