Skip to content

Commit

Permalink
changes to support Id5 pd param (#522)
Browse files Browse the repository at this point in the history
* Refreshuserid (#517)

* changes to support refreshuserids use case for sso

* modules/userId/index.js src/constants.json src/utils.js test/spec/modules/userId_spec.js

* changes for refreshuser id test cases

* removed timeout for fb functions

* set loginEvent variable to true when fb and google login is detected

* changes to handle facebook login api failures

* Refreshuserid (#517) (#521)

* changes to support refreshuserids use case for sso

* modules/userId/index.js src/constants.json src/utils.js test/spec/modules/userId_spec.js

* changes for refreshuser id test cases

* removed timeout for fb functions

* set loginEvent variable to true when fb and google login is detected

* changes to handle facebook login api failures

* changes to pass pd string for id5id partner

* removed testcase

* changes to testcases and variable declarations

* send SHA256 hash for zeotap instead of MD5

* removed publink config

* changes as per code review comments

* changes to pass email hashes to modules who want to process it
  • Loading branch information
pm-manasi-moghe authored May 2, 2022
1 parent b18a165 commit 193d5e1
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 29 deletions.
65 changes: 45 additions & 20 deletions modules/userId/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ import { createEidsArray, buildEidPermissions } from './eids.js';
import { getCoreStorageManager } from '../../src/storageManager.js';
import {
getPrebidInternal, isPlainObject, logError, isArray, cyrb53Hash, deepAccess, timestamp, delayExecution, logInfo, isFn,
logWarn, isEmptyStr, isNumber, isEmpty
logWarn, isEmptyStr, isNumber, isEmpty, skipUndefinedValues
} from '../../src/utils.js';
import includes from 'core-js-pure/features/array/includes.js';
import MD5 from 'crypto-js/md5.js';
Expand Down Expand Up @@ -193,6 +193,10 @@ export let auctionDelay;
/** @type {(Object|undefined)} */
let userIdentity = {};
/** @param {Submodule[]} submodules */

let modulesToRefresh = [];
let scriptBasedModulesToRefresh = [];

export function setSubmoduleRegistry(submodules) {
submoduleRegistry = submodules;
}
Expand Down Expand Up @@ -674,34 +678,53 @@ function setUserIdentities(userIdentityData) {
}
};

function updateModuleParams(moduleToUpdate) {
// this is specific to id5id partner. needs to be revisited when we integrate additional partners for email hashes.
moduleToUpdate.params[CONSTANTS.MODULE_PARAM_TO_UPDATE_FOR_SSO[moduleToUpdate.name].param] = '1=' + getUserIdentities().emailHash['SHA256'];
export function getRawPDString(emailHashes, userID) {
let params = {
1: (emailHashes && emailHashes['SHA256']) || undefined, // Email
5: userID ? btoa(userID) : undefined // UserID
};
let pdString = Object.keys(skipUndefinedValues(params)).map(function(key) {
return params[key] && key + '=' + params[key]
}).join('&');
return btoa(pdString);
};

export function updateModuleParams(moduleToUpdate) {
let params = CONSTANTS.MODULE_PARAM_TO_UPDATE_FOR_SSO[moduleToUpdate.name];
if (!params) return;

let userIdentity = getUserIdentities() || {};
let enableSSO = (window.PWT && window.PWT.ssoEnabled) || false;
let emailHashes = enableSSO && userIdentity.emailHash ? userIdentity.emailHash : userIdentity.pubProvidedEmailHash ? userIdentity.pubProvidedEmailHash : undefined;
params.forEach(function(param) {
moduleToUpdate.params[param.key] = (moduleToUpdate.name === 'id5Id' ? getRawPDString(emailHashes, userIdentity.userID) : emailHashes ? emailHashes[param.hashType] : undefined);
});
}

export function reTriggerPartnerCallsWithEmailHashes() {
var modulesToRefresh = [];
var scriptBasedModulesToRefresh = [];
var primaryModulesList = CONSTANTS.REFRESH_IDMODULES_LIST.PRIMARY_MODULES;
var scriptBasedModulesList = CONSTANTS.REFRESH_IDMODULES_LIST.SCRIPT_BASED_MODULES;
var moduleName;
var index;
for (index in configRegistry) {
moduleName = configRegistry[index].name;
function generateModuleLists() {
let primaryModulesList = CONSTANTS.REFRESH_IDMODULES_LIST.PRIMARY_MODULES;
let scriptBasedModulesList = CONSTANTS.REFRESH_IDMODULES_LIST.SCRIPT_BASED_MODULES;

for (let index in configRegistry) {
let moduleName = configRegistry[index].name;
if (primaryModulesList.indexOf(moduleName) >= 0) {
modulesToRefresh.push(moduleName);
updateModuleParams(configRegistry[index]);
} else if (scriptBasedModulesList.indexOf(moduleName) >= 0) {
scriptBasedModulesToRefresh.push(moduleName);
}
}
}

export function reTriggerPartnerCallsWithEmailHashes(updateModulesOnly) {
generateModuleLists();
getGlobal().refreshUserIds({'submoduleNames': modulesToRefresh});
reTriggerScriptBasedAPICalls(scriptBasedModulesToRefresh);
}

export function reTriggerScriptBasedAPICalls(modulesToRefresh) {
var i = 0;
var userIdentity = getUserIdentities() || {};
let i = 0;
let userIdentity = getUserIdentities() || {};
for (i in modulesToRefresh) {
switch (modulesToRefresh[i]) {
case 'zeotapIdPlus':
Expand All @@ -728,7 +751,7 @@ function getUserIdentities() {
}

function processFBLoginData(refThis, response) {
var emailHash = {};
let emailHash = {};
if (response.status === 'connected') {
window.PWT = window.PWT || {};
window.PWT.fbAt = response.authResponse.accessToken;
Expand All @@ -755,9 +778,9 @@ function processFBLoginData(refThis, response) {
* @param {Object} userObject Google's user object, passed from google's callback function
*/
function onSSOLogin(data) {
var refThis = this;
var email;
var emailHash = {};
let refThis = this;
let email;
let emailHash = {};
if (!window.PWT || !window.PWT.ssoEnabled) return;

switch (data.provider) {
Expand Down Expand Up @@ -794,7 +817,7 @@ function onSSOLogout() {

function generateEmailHash(email, emailHash) {
email = email !== undefined ? email.trim().toLowerCase() : '';
var regex = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
let regex = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
if (regex.test(email)) {
emailHash.MD5 = MD5(email).toString();
emailHash.SHA1 = SHA1(email).toString();
Expand Down Expand Up @@ -940,6 +963,8 @@ function updateSubmodules() {
if (!configs.length) {
return;
}
generateModuleLists(); // this is to generate the list of modules to be updated wit sso/publisher provided email data

// do this to avoid reprocessing submodules
const addedSubmodules = submoduleRegistry.filter(i => !find(submodules, j => j.name === i.name));

Expand Down
8 changes: 4 additions & 4 deletions src/constants.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@
"SCRIPT_BASED_MODULES": ["zeotapIdPlus", "identityLink"]
},
"MODULE_PARAM_TO_UPDATE_FOR_SSO": {
"id5Id": {
"param": "pd"
}
"id5Id": [{
"key": "pd"
}]
}
}
}
14 changes: 13 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export const internal = {
parseQS,
formatQS,
deepEqual,
isEmpty
isEmpty,
skipUndefinedValues
};

let prebidInternal = {}
Expand Down Expand Up @@ -1301,3 +1302,14 @@ export function cyrb53Hash(str, seed = 0) {
h2 = imul(h2 ^ (h2 >>> 16), 2246822507) ^ imul(h1 ^ (h1 >>> 13), 3266489909);
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString();
}

export function skipUndefinedValues (obj) {
var newObj = {};
var prop;
for (prop in obj) {
if (obj[prop]) {
newObj[prop] = obj[prop];
}
}
return newObj;
}
61 changes: 57 additions & 4 deletions test/spec/modules/userId_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
syncDelay,
PBJS_USER_ID_OPTOUT_NAME,
findRootDomain,
reTriggerScriptBasedAPICalls
getRawPDString,
updateModuleParams
} from 'modules/userId/index.js';
import {createEidsArray} from 'modules/userId/eids.js';
import {config} from 'src/config.js';
Expand Down Expand Up @@ -2584,23 +2585,75 @@ describe('User ID', function () {
config.resetConfig();
});

it('Email hashes are not stored in userIdentities Object on SSO login if ssoEnabled is false', function () {
xit('Email hashes are not stored in userIdentities Object on SSO login if ssoEnabled is false', function () {
window.PWT.ssoEnabled = false;

expect(typeof (getGlobal()).onSSOLogin).to.equal('function');
getGlobal().onSSOLogin({'provider': 'google', 'googleUserObject': dummyGoogleUserObject});
expect((getGlobal()).getUserIdentities().emailHash).to.not.exist;
});

it('Email hashes are stored in userIdentities Object on SSO login if ssoEnabled is true', function () {
xit('Email hashes are stored in userIdentities Object on SSO login if ssoEnabled is true', function () {
expect(typeof (getGlobal()).onSSOLogin).to.equal('function');
getGlobal().onSSOLogin({'provider': 'google', 'googleUserObject': dummyGoogleUserObject});
expect((getGlobal()).getUserIdentities().emailHash).to.exist;
});

it('Publisher provided emails are stored in userIdentities.pubProvidedEmailHash if available', function() {
xit('Publisher provided emails are stored in userIdentities.pubProvidedEmailHash if available', function() {
getGlobal().setUserIdentities({'pubProvidedEmail': 'abc@xyz.com'});
expect(getGlobal().getUserIdentities().pubProvidedEmailHash).to.exist;
});

xit('should return encoded string with email hash and userid in id5 format', function() {
var emailHashes = {
'MD5': '1edeb32aa0ab4b329a41b431050dcf26',
'SHA1': '5acb6964c743eff1d4f51b8d57abddc11438e8eb',
'SHA256': '722b8c12e7991f0ebbcc2d7caebe8e12479d26d5dd9cb37f442a55ddc190817a'
};
var outputString = 'MT03MjJiOGMxMmU3OTkxZjBlYmJjYzJkN2NhZWJlOGUxMjQ3OWQyNmQ1ZGQ5Y2IzN2Y0NDJhNTVkZGMxOTA4MTdhJjU9WVdKalpERXlNelE9';
var encodedString = getRawPDString(emailHashes, 'abcd1234');
expect(encodedString).to.equal(outputString);
});

xit('should return encoded string with only email hash if userID is not available', function() {
var emailHashes = {
'MD5': '1edeb32aa0ab4b329a41b431050dcf26',
'SHA1': '5acb6964c743eff1d4f51b8d57abddc11438e8eb',
'SHA256': '722b8c12e7991f0ebbcc2d7caebe8e12479d26d5dd9cb37f442a55ddc190817a'
};
var outputString = 'MT03MjJiOGMxMmU3OTkxZjBlYmJjYzJkN2NhZWJlOGUxMjQ3OWQyNmQ1ZGQ5Y2IzN2Y0NDJhNTVkZGMxOTA4MTdh';
var encodedString = getRawPDString(emailHashes, undefined);
expect(encodedString).to.equal(outputString);
});

xit('should set the pd param for id5id if id5id module is configured and pd string is available', function() {
var pdString = 'MT03MjJiOGMxMmU3OTkxZjBlYmJjYzJkN2NhZWJlOGUxMjQ3OWQyNmQ1ZGQ5Y2IzN2Y0NDJhNTVkZGMxOTA4MTdh';
var moduleToUpdate = {
'name': 'id5Id',
'params':
{
'partner': 173,
'provider': 'pubmatic-identity-hub'
},
'storage':
{
'type': 'cookie',
'name': '_myUnifiedId',
'expires': '1825'
}
};
getGlobal().setUserIdentities(
{
'emailHash': {
'MD5': '1edeb32aa0ab4b329a41b431050dcf26',
'SHA1': '5acb6964c743eff1d4f51b8d57abddc11438e8eb',
'SHA256': '722b8c12e7991f0ebbcc2d7caebe8e12479d26d5dd9cb37f442a55ddc190817a'
}
}
);
updateModuleParams(moduleToUpdate);
expect(moduleToUpdate.params.pd).to.exist;
expect(moduleToUpdate.params.pd).to.equal(pdString);
});
});
});

0 comments on commit 193d5e1

Please sign in to comment.