Skip to content

Commit

Permalink
Floc Userid System: add new ID module (#6521)
Browse files Browse the repository at this point in the history
  • Loading branch information
SKOCHERI authored and idettman committed May 21, 2021
1 parent 415b063 commit ddf0f53
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 13 deletions.
8 changes: 8 additions & 0 deletions integrationExamples/gpt/userId_example.html
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,14 @@
{
"name": "uid2"
}
,{
name: "flocId",
params: {
// Default sharedid.org token : "A3dHTSoNUMjjERBLlrvJSelNnwWUCwVQhZ5tNQ+sll7y+LkPPVZXtB77u2y7CweRIxiYaGwGXNlW1/dFp8VMEgIAAAB+eyJvcmlnaW4iOiJodHRwczovL3NoYXJlZGlkLm9yZzo0NDMiLCJmZWF0dXJlIjoiSW50ZXJlc3RDb2hvcnRBUEkiLCJleHBpcnkiOjE2MjYyMjA3OTksImlzU3ViZG9tYWluIjp0cnVlLCJpc1RoaXJkUGFydHkiOnRydWV9"
// To get new token, register https://developer.chrome.com/origintrials/#/trials/active for Federated Learning of Cohorts
token: "A3dHTSoNUMjjERBLlrvJSelNnwWUCwVQhZ5tNQ+sll7y+LkPPVZXtB77u2y7CweRIxiYaGwGXNlW1/dFp8VMEgIAAAB+eyJvcmlnaW4iOiJodHRwczovL3NoYXJlZGlkLm9yZzo0NDMiLCJmZWF0dXJlIjoiSW50ZXJlc3RDb2hvcnRBUEkiLCJleHBpcnkiOjE2MjYyMjA3OTksImlzU3ViZG9tYWluIjp0cnVlLCJpc1RoaXJkUGFydHkiOnRydWV9"
}
}
],
"syncDelay": 5000,
"auctionDelay": 1000
Expand Down
3 changes: 2 additions & 1 deletion modules/.submodules.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"novatiqIdSystem",
"uid2IdSystem",
"admixerIdSystem",
"dmdIdSystem"
"dmdIdSystem",
"flocIdSystem"
],
"adpod": [
"freeWheelAdserverVideo",
Expand Down
110 changes: 110 additions & 0 deletions modules/flocIdSystem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* This module adds flocId to the User ID module
* The {@link module:modules/userId} module is required
* @module modules/flocId
* @requires module:modules/userId
*/

import * as utils from '../src/utils.js'
import {submodule} from '../src/hook.js'

const MODULE_NAME = 'flocId';

/**
* Add meta tag to support enabling of floc origin trial
* @function
* @param {string} token - configured token for origin-trial
*/
function enableOriginTrial(token) {
const tokenElement = document.createElement('meta');
tokenElement.httpEquiv = 'origin-trial';
tokenElement.content = token;
document.head.appendChild(tokenElement);
}

/**
* Get the interest cohort.
* @param successCallback
* @param errorCallback
*/
function getFlocData(successCallback, errorCallback) {
document.interestCohort()
.then((data) => {
successCallback(data);
}).catch((error) => {
errorCallback(error);
});
}

/**
* Encode the id
* @param value
* @returns {string|*}
*/
function encodeId(value) {
const result = {};
if (value) {
result.flocId = value;
utils.logInfo('Decoded value ' + JSON.stringify(result));
return result;
}
return undefined;
}

/** @type {Submodule} */
export const flocIdSubmodule = {
/**
* 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 {{flocId:{ id: string }} or undefined if value doesn't exists
*/
decode(value) {
return (value) ? encodeId(value) : undefined;
},
/**
* If chrome and cohort enabled performs action to obtain id and return a value in the callback's response argument
* @function
* @param {SubmoduleConfig} [config]
* @returns {IdResponse|undefined}
*/
getId(config) {
// Block usage of storage of cohort ID
const checkStorage = (config && config.storage);
if (checkStorage) {
utils.logError('User ID - flocId submodule storage should not defined');
return;
}
// Validate feature is enabled
const isFlocEnabled = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime) && !!document.featurePolicy && !!document.featurePolicy.features() && document.featurePolicy.features().includes('interest-cohort');

if (isFlocEnabled) {
const configParams = (config && config.params) || {};
if (configParams && (typeof configParams.token === 'string')) {
// Insert meta-tag with token from configuration
enableOriginTrial(configParams.token);
}
// Example expected output { "id": "14159", "version": "chrome.1.0" }
let returnCallback = (cb) => {
getFlocData((data) => {
returnCallback = () => { return data; }
utils.logInfo('Cohort id: ' + JSON.stringify(data));
cb(data);
}, (err) => {
utils.logInfo(err);
cb(undefined);
});
};

return {callback: returnCallback};
}
}
};

submodule('userId', flocIdSubmodule);
34 changes: 34 additions & 0 deletions modules/flocIdSystem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## FloC ID User ID Submodule

### Building Prebid with Floc Id Support
Your Prebid build must include the modules for both **userId** and **flocIdSystem** submodule. Follow the build instructions for Prebid as
explained in the top level README.md file of the Prebid source tree.

ex: $ gulp build --modules=userId,flocIdSystem

### Prebid Params

Individual params may be set for the FloC ID User ID Submodule.
```
pbjs.setConfig({
userSync: {
userIds: [{
name: 'flocId',
params: {
token: "Registered token or default sharedid.org token"
}
}]
}
});
```

### Parameter Descriptions for the `userSync` Configuration Section
The below parameters apply only to the FloC ID User ID Module integration.

| Params under usersync.userIds[]| Scope | Type | Description | Example |
| --- | --- | --- | --- | --- |
| name | Required | String | ID value for the Floc ID module - `"flocId"` | `"flocId"` |
| params | Optional | Object | Details for flocId syncing. | |
| params.token | Optional | Object | Publisher registered token.To get new token, register https://developer.chrome.com/origintrials/#/trials/active for Federated Learning of Cohorts. Default sharedid.org token: token: "A3dHTSoNUMjjERBLlrvJSelNnwWUCwVQhZ5tNQ+sll7y+LkPPVZXtB77u2y7CweRIxiYaGwGXNlW1/dFp8VMEgIAAAB+eyJvcmlnaW4iOiJodHRwczovL3NoYXJlZGlkLm9yZzo0NDMiLCJmZWF0dXJlIjoiSW50ZXJlc3RDb2hvcnRBUEkiLCJleHBpcnkiOjE2MjYyMjA3OTksImlzU3ViZG9tYWluIjp0cnVlLCJpc1RoaXJkUGFydHkiOnRydWV9"| token: "A3dHTSoNUMjjERBLlrvJSelNnwWUCwVQhZ5tNQ+sll7y+LkPPVZXtB77u2y7CweRIxiYaGwGXNlW1/dFp8VMEgIAAAB+eyJvcmlnaW4iOiJodHRwczovL3NoYXJlZGlkLm9yZzo0NDMiLCJmZWF0dXJlIjoiSW50ZXJlc3RDb2hvcnRBUEkiLCJleHBpcnkiOjE2MjYyMjA3OTksImlzU3ViZG9tYWluIjp0cnVlLCJpc1RoaXJkUGFydHkiOnRydWV9"
|
| storage | Not Allowed | Object | Will ask browser for cohort everytime. Setting storage will fail id lookup ||
10 changes: 10 additions & 0 deletions modules/userId/userId.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ pbjs.setConfig({
name: '__adm__admixer',
expires: 30
}
},{
name: 'flocId',
params: {
token: "Registered token or default sharedid.org token" // Default sharedid.org token: "A3dHTSoNUMjjERBLlrvJSelNnwWUCwVQhZ5tNQ+sll7y+LkPPVZXtB77u2y7CweRIxiYaGwGXNlW1/dFp8VMEgIAAAB+eyJvcmlnaW4iOiJodHRwczovL3NoYXJlZGlkLm9yZzo0NDMiLCJmZWF0dXJlIjoiSW50ZXJlc3RDb2hvcnRBUEkiLCJleHBpcnkiOjE2MjYyMjA3OTksImlzU3ViZG9tYWluIjp0cnVlLCJpc1RoaXJkUGFydHkiOnRydWV9"
}
}],
syncDelay: 5000,
auctionDelay: 1000
Expand Down Expand Up @@ -232,6 +237,11 @@ pbjs.setConfig({
name: 'admixerId',
expires: 30
}
},{
name: 'flocId',
params: {
token: "Registered token or default sharedid.org token" // Default sharedid.org token: "A3dHTSoNUMjjERBLlrvJSelNnwWUCwVQhZ5tNQ+sll7y+LkPPVZXtB77u2y7CweRIxiYaGwGXNlW1/dFp8VMEgIAAAB+eyJvcmlnaW4iOiJodHRwczovL3NoYXJlZGlkLm9yZzo0NDMiLCJmZWF0dXJlIjoiSW50ZXJlc3RDb2hvcnRBUEkiLCJleHBpcnkiOjE2MjYyMjA3OTksImlzU3ViZG9tYWluIjp0cnVlLCJpc1RoaXJkUGFydHkiOnRydWV9"
}
},{
name: "deepintentId",
storage: {
Expand Down
28 changes: 16 additions & 12 deletions test/spec/modules/userId_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {getPrebidInternal} from 'src/utils.js';
import {uid2IdSubmodule} from 'modules/uid2IdSystem.js';
import {admixerIdSubmodule} from 'modules/admixerIdSystem.js';
import {deepintentDpesSubmodule} from 'modules/deepintentDpesIdSystem.js';
import {flocIdSubmodule} from 'modules/flocIdSystem.js'

let assert = require('chai').assert;
let expect = require('chai').expect;
Expand Down Expand Up @@ -464,22 +465,22 @@ describe('User ID', function () {
});

it('handles config with no usersync object', function () {
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule]);
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, flocIdSubmodule]);
init(config);
config.setConfig({});
// usersync is undefined, and no logInfo message for 'User ID - usersync config updated'
expect(typeof utils.logInfo.args[0]).to.equal('undefined');
});

it('handles config with empty usersync object', function () {
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule]);
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, flocIdSubmodule]);
init(config);
config.setConfig({userSync: {}});
expect(typeof utils.logInfo.args[0]).to.equal('undefined');
});

it('handles config with usersync and userIds that are empty objs', function () {
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule]);
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule]);
init(config);
config.setConfig({
userSync: {
Expand All @@ -490,7 +491,7 @@ describe('User ID', function () {
});

it('handles config with usersync and userIds with empty names or that dont match a submodule.name', function () {
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule]);
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule]);
init(config);
config.setConfig({
userSync: {
Expand All @@ -507,7 +508,7 @@ describe('User ID', function () {
});

it('config with 1 configurations should create 1 submodules', function () {
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule]);
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, flocIdSubmodule]);
init(config);
config.setConfig(getConfigMock(['unifiedId', 'unifiedid', 'cookie']));

Expand All @@ -528,8 +529,8 @@ describe('User ID', function () {
expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 1 submodules');
});

it('config with 19 configurations should result in 20 submodules add', function () {
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, liveIntentIdSubmodule, britepoolIdSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule]);
it('config with 21 configurations should result in 21 submodules add', function () {
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, liveIntentIdSubmodule, britepoolIdSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule]);
init(config);
config.setConfig({
userSync: {
Expand Down Expand Up @@ -584,17 +585,20 @@ describe('User ID', function () {
}, {
name: 'deepintentId',
storage: {name: 'deepintentId', type: 'cookie'}
}, {
name: 'flocId'
}, {
name: 'dmdId',
storage: {name: 'dmdId', type: 'cookie'},
storage: {name: 'dmdId', type: 'cookie'}
}]
}
});
expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 20 submodules');
expect(utils.logInfo.args[0][0]).to.exist.and.to.contain('User ID - usersync config updated for 21 submodules');
});

it('config syncDelay updates module correctly', function () {
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule]);
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule]);

init(config);
config.setConfig({
userSync: {
Expand All @@ -609,7 +613,7 @@ describe('User ID', function () {
});

it('config auctionDelay updates module correctly', function () {
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule]);
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule]);
init(config);
config.setConfig({
userSync: {
Expand All @@ -624,7 +628,7 @@ describe('User ID', function () {
});

it('config auctionDelay defaults to 0 if not a number', function () {
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule]);
setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, nextrollIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule, criteoIdSubmodule, mwOpenLinkIdSubModule, tapadIdSubmodule, uid2IdSubmodule, admixerIdSubmodule, deepintentDpesSubmodule, dmdIdSubmodule, flocIdSubmodule]);
init(config);
config.setConfig({
userSync: {
Expand Down

0 comments on commit ddf0f53

Please sign in to comment.