Skip to content

Commit

Permalink
Added support for IDs for multiple sources (prebid#8499)
Browse files Browse the repository at this point in the history
Co-authored-by: Nick Curry <[email protected]>
  • Loading branch information
Nick-Merkle and Nick Curry authored Jun 7, 2022
1 parent a2fcadf commit 302411b
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 77 deletions.
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

0 comments on commit 302411b

Please sign in to comment.