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

Adding sharedid submodule #1

Closed
wants to merge 13 commits into from
9 changes: 8 additions & 1 deletion integrationExamples/gpt/userId_example.html
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,16 @@
name: 'idl_env',
expires: 30
}
}, {
name: "sharedId",
storage: {
type: "cookie",
name: "sharedid",
expires: 28
},
}],
syncDelay: 5000,
auctionDelay: 1000
auctionDelay: 1000
}
});
pbjs.addAdUnits(adUnits);
Expand Down
3 changes: 2 additions & 1 deletion modules/.submodules.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"liveIntentIdSystem",
"criteoIdSystem",
"netIdSystem",
"identityLinkIdSystem"
"identityLinkIdSystem",
"sharedIdSystem"
],
"adpod": [
"freeWheelAdserverVideo",
Expand Down
176 changes: 176 additions & 0 deletions modules/sharedIdSystem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/**
* This module adds Shared ID support to the User ID module
* The {@link module:modules/userId} module is required.
* @module modules/sharedIdSystem
* @requires module:modules/userId
*/
import { submodule } from '../src/hook.js';
import * as utils from '../src/utils.js';
// These values should NEVER change. If
// they do, we're no longer making ulids!
const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; // Crockford's Base32
const ENCODING_LEN = ENCODING.length;
const TIME_MAX = Math.pow(2, 48) - 1;
const TIME_LEN = 10;
const RANDOM_LEN = 16;
const MODULE_NAME = 'sharedId';

/** @type {Submodule} */
export const sharedIdSubmodule = {
/**
* used to link submodule with config
* @type {string}
*/
name: MODULE_NAME,

sharedIdFactory: undefined,

/**
* decode the stored id value for passing to bid requests
* @function
* @param {string} value
* @returns {{sharedid:string}} or undefined if value doesn't exists
*/
decode(value) {
return (value && typeof value['sharedid'] === 'string') ? { 'sharedid': value['sharedid'] } : undefined;
},

/**
* performs action to obtain id and return a value.
* @function
* @param {SubmoduleParams} [configParams]
* @returns {sharedId}
*/
getId: function(configParams) {
let sharedId = this.sharedIdGenerator();
return {
id: sharedId
}
},
/**
* the shared id generator factory.
* @returns {*}
*/
sharedIdGenerator: function () {
SKOCHERI marked this conversation as resolved.
Show resolved Hide resolved
if (!this.sharedIdFactory) {
this.sharedIdFactory = this.factory();
}

return this.sharedIdFactory();
},

/**
* the factory to generate unique identifier based on time and current pseudorandom number
* @param {string} the current pseudorandom number generator
* @returns {function(*=): *}
*/
factory: function (currPrng) {
if (!currPrng) {
currPrng = this.detectPrng();
}
return function ulid(seedTime) {
if (isNaN(seedTime)) {
seedTime = Date.now();
}
return this.encodeTime(seedTime, TIME_LEN) + this.encodeRandom(RANDOM_LEN, currPrng);
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in sharedIdGenerator we pull out sharedIdFactory to its own, independent, class method. Here we are defining ulid inline. Is this necessary? if not, I might suggest pulling it into a separate method and reference it here instead.

},
/**
* creates and logs the error message
* @function
* @param {string} error message
* @returns {Error}
*/
createError: function(message) {
utils.logError(message);
const err = new Error(message);
err.source = 'sharedId';
return err;
},
/**
* gets a a random charcter from generated pseudorandom number
* @param {string} the generated pseudorandom number
* @returns {string}
*/
randomChar: function(prng) {
let rand = Math.floor(prng() * ENCODING_LEN);
if (rand === ENCODING_LEN) {
rand = ENCODING_LEN - 1;
}
return ENCODING.charAt(rand);
},
/**
* encodes the time based on the length
* @param now
* @param len
* @returns {string} encoded time.
*/
encodeTime: function (now, len) {
if (isNaN(now)) {
throw new Error(now + ' must be a number');
}

if (Number.isInteger(now) === false) {
throw this.createError('time must be an integer');
}

if (now > TIME_MAX) {
throw this.createError('cannot encode time greater than ' + TIME_MAX);
}
if (now < 0) {
throw this.createError('time must be positive');
}

if (Number.isInteger(len) === false) {
throw this.createError('length must be an integer');
}
if (len < 0) {
throw this.createError('length must be positive');
}

let mod;
let str = '';
for (; len > 0; len--) {
mod = now % ENCODING_LEN;
str = ENCODING.charAt(mod) + str;
now = (now - mod) / ENCODING_LEN;
}
return str;
},

/**
* encodes random character
* @param len
* @param prng
* @returns {string}
*/
encodeRandom: function (len, prng) {
let str = '';
for (; len > 0; len--) {
str = this.randomChar(prng) + str;
}
return str;
},
/**
* detects the pseudorandom number generator and generates the random number
* @function
* @param {string} error message
* @returns {string} a random number
*/
detectPrng: function (root) {
if (!root) {
root = typeof window !== 'undefined' ? window : null;
}
const browserCrypto = root && (root.crypto || root.msCrypto);
if (browserCrypto) {
return () => {
const buffer = new Uint8Array(1);
browserCrypto.getRandomValues(buffer);
return buffer[0] / 0xff;
};
}
return () => Math.random();
}
};

submodule('userId', sharedIdSubmodule);
39 changes: 39 additions & 0 deletions modules/sharedIdSystem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## Shared ID User ID Submodule

Shared ID User ID Module generates a simple UUID that can be utilized to improve user matching.
This module does not require any registration.

### Building Prebid with Shared Id Support
Your Prebid build must include the modules for both **userId** and **sharedId** 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,sharedIdSystem

### Prebid Params

Individual params may be set for the Shared ID User ID Submodule.
```
pbjs.setConfig({
usersync: {
userIds: [{
name: 'sharedId',
storage: {
name: 'sharedid',
type: 'cookie',
expires: 28
},
}]
}
});
```

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

| Params under usersync.userIds[]| Scope | Type | Description | Example |
| --- | --- | --- | --- | --- |
| name | Required | String | ID value for the Shared ID module - `"sharedId"` | `"sharedId"` |
| storage | Required | Object | The publisher must specify the local storage in which to store the results of the call to get the user ID. This can be either cookie or HTML5 storage. | |
| storage.type | Required | String | This is where the results of the user ID will be stored. The recommended method is `localStorage` by specifying `html5`. | `"html5"` |
| storage.name | Required | String | The name of the cookie or html5 local storage where the user ID will be stored. | `"sharedid"` |
| storage.expires | Optional | Integer | How long (in days) the user ID information will be stored. | `28` |
5 changes: 5 additions & 0 deletions modules/userId/eids.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ const USER_IDS_CONFIG = {
'netId': {
source: 'netid.de',
atype: 1
},
// sharedid
'sharedid': {
source: 'sharedid.org',
atype: 1
}
};

Expand Down
9 changes: 8 additions & 1 deletion modules/userId/eids.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ userIdAsEids = [
id: 'some-random-id-value',
atype: 1
}]
},
{
source: 'sharedid.org',
uids: [{
id: 'some-random-id-value',
atype: 1
}]
}
]
```
```
14 changes: 14 additions & 0 deletions modules/userId/userId.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ pbjs.setConfig({
name: '_li_pbid',
expires: 60
}
}, {
name: 'sharedId',
storage: {
type: 'cookie',
name: 'sharedid',
expires: 28
}
}],
syncDelay: 5000,
auctionDelay: 1000
Expand Down Expand Up @@ -113,6 +120,13 @@ pbjs.setConfig({
name: '_li_pbid',
expires: 60
}
}, {
name: 'sharedId',
storage: {
type: 'cookie',
name: 'sharedid',
expires: 28
}
}],
syncDelay: 5000
}
Expand Down
11 changes: 11 additions & 0 deletions test/spec/modules/eids_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,17 @@ describe('eids array generation for known sub-modules', function() {
uids: [{id: 'some-random-id-value', atype: 1}]
});
});
it('Sharedid', function() {
const userId = {
sharedid: 'test_sharedId'
};
const newEids = createEidsArray(userId);
expect(newEids.length).to.equal(1);
expect(newEids[0]).to.deep.equal({
source: 'sharedid.org',
uids: [{id: 'test_sharedId', atype: 1}]
});
});
});

describe('Negative case', function() {
Expand Down
Loading