-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Digitrust id integration #3739
Closed
goosemanjack
wants to merge
3
commits into
prebid:master
from
InteractiveAdvertisingBureau:digitrustIdIntegration
Closed
Digitrust id integration #3739
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
/** | ||
* DigiTrust Universal Id Submodule. | ||
* If the full DigiTrust Id library is included the standard functions | ||
* will be invoked to obtain the user's DigiTrust Id. | ||
* When the full library is not included this will fall back to the | ||
* DigiTrust Identity API and generate a mock DigiTrust object. | ||
*/ | ||
'use strict'; | ||
|
||
import { config } from 'src/config'; | ||
import * as utils from 'src/utils'; | ||
import { ajax } from 'src/ajax'; | ||
import { getGlobal } from 'src/prebidGlobal'; | ||
|
||
/** | ||
* Checks to see if the DigiTrust framework is initialized. | ||
* @function | ||
*/ | ||
function isInitialized() { | ||
if (window.DigiTrust == null) { | ||
return false; | ||
} | ||
return DigiTrust.isClient; // this is set to true after init | ||
} | ||
|
||
let retries = 0; | ||
let retryId = 0; | ||
var isMock = false; | ||
var noop = function () { | ||
}; | ||
|
||
const MAX_RETRIES = 4; | ||
const DT_ID_SVC = 'https://cdn-cf.digitru.st/id/v1'; | ||
|
||
var isFunc = function (fn) { | ||
return typeof (fn) === 'function'; | ||
} | ||
|
||
function callApi(options) { | ||
ajax( | ||
DT_ID_SVC, | ||
{ | ||
success: options.success, | ||
error: options.fail | ||
}, | ||
null, | ||
{ | ||
method: 'GET' | ||
} | ||
); | ||
} | ||
|
||
/** | ||
* Encode the Id per DigiTrust lib | ||
* @param {any} id | ||
*/ | ||
function encId(id) { | ||
try { | ||
if (typeof (id) !== 'string') { | ||
id = JSON.stringify(id); | ||
} | ||
return encodeURIComponent(btoa(id)); | ||
} catch (ex) { | ||
return id; | ||
} | ||
} | ||
|
||
/** | ||
* Writes the Identity into the expected DigiTrust cookie | ||
* @param {any} id | ||
*/ | ||
function writeDigiId(id) { | ||
var key = 'DigiTrust.v1.identity'; | ||
var date = new Date(); | ||
date.setTime(date.getTime() + 604800000); | ||
var exp = 'expires=' + date.toUTCString(); | ||
document.cookie = key + '=' + encId(id) + '; ' + exp + '; path=/;'; | ||
} | ||
|
||
/** | ||
* Set up a mock DigiTrust object | ||
* | ||
*/ | ||
function initMockDigitrust() { | ||
isMock = true; | ||
var _savedId = null; // closure variable for storing Id to avoid additional requests | ||
var mock = { | ||
isClient: true, | ||
isMock: true, | ||
getUser: function (obj, callback) { | ||
var cb = callback || noop; | ||
if (_savedId != null) { | ||
cb(_savedId); | ||
return; | ||
} | ||
|
||
var opts = { | ||
success: function (respText, result) { | ||
var idResult = { | ||
success: true | ||
} | ||
try { | ||
writeDigiId(respText); | ||
idResult.identity = JSON.parse(respText); | ||
_savedId = idResult; | ||
} catch (ex) { | ||
idResult.success = false; | ||
} | ||
cb(idResult); | ||
}, | ||
fail: function (statusErr, result) { | ||
utils.logError('DigiTrustId API error: ' + statusErr); | ||
} | ||
} | ||
|
||
callApi(opts); | ||
} | ||
} | ||
|
||
if (window) { | ||
window.DigiTrust = mock; | ||
} | ||
} | ||
|
||
/* | ||
* Internal implementation to get the Id and trigger callback | ||
*/ | ||
function getDigiTrustId(data, consentData, syncDelay, callback) { | ||
if (!isInitialized()) { | ||
if (retries >= MAX_RETRIES) { | ||
utils.logInfo('DigiTrust framework timeout. Fallback to API and mock.'); | ||
initMockDigitrust(); | ||
} else { | ||
// use expanding envelope | ||
if (retryId != 0) { | ||
clearTimeout(retryId); | ||
} | ||
|
||
retryId = setTimeout(function () { | ||
getDigiTrustId(data, consentData, syncDelay, callback); | ||
}, 100 * (1 + retries++)); | ||
return; | ||
} | ||
} | ||
|
||
var executeIdRequest = function (data, callback) { | ||
DigiTrust.getUser({ member: 'prebid' }, function (idResult) { | ||
var exp = (data && data.storage && data.storage.expires) || 60; | ||
var rslt = { | ||
data: null, | ||
expires: exp | ||
}; | ||
if (idResult && idResult.success && idResult.identity) { | ||
if (isMock) { | ||
// plug in the mock ID | ||
} | ||
|
||
if (isFunc(callback)) { | ||
rslt.data = idResult.identity; | ||
callback(rslt); | ||
} | ||
} else { | ||
// failed | ||
if (isFunc(callback)) { | ||
rslt.err = 'Failure getting id'; | ||
callback(rslt); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
executeIdRequest(data, callback); | ||
} | ||
|
||
function initializeDigiTrust(config) { | ||
var dt = window.DigiTrust; | ||
if (dt && !dt.isClient && config != null) { | ||
dt.initialize(config.init, config.callback); | ||
} else if (dt == null) { | ||
// Assume we are already on a delay and DigiTrust is not on page | ||
initMockDigitrust(); | ||
} | ||
} | ||
|
||
var testHook = {}; | ||
|
||
/** | ||
* Exposes the test hook object by attaching to the digitrustIdModule. | ||
* This method is called in the unit tests to surface internals. | ||
*/ | ||
function surfaceTestHook() { | ||
digitrustIdModule['_testHook'] = testHook; | ||
} | ||
|
||
// the Id system module | ||
export const digitrustIdModule = | ||
{ | ||
name: 'digitrust', | ||
decode: function (idData) { | ||
try { | ||
return { 'digitrustid': idData }; | ||
} catch (e) { | ||
utils.logError('DigiTrust ID submodule decode error'); | ||
} | ||
}, | ||
getId: getDigiTrustId, | ||
init: initializeDigiTrust, | ||
_testInit: surfaceTestHook | ||
} | ||
|
||
/** | ||
* Expose the loader module in the global for later retrieval | ||
*/ | ||
function exposeLoader() { | ||
let pbjs = getGlobal(); | ||
if (!pbjs) { | ||
utils.logError('DigiTrustLoader failed to find Prebid global'); | ||
return; | ||
} | ||
|
||
config.setConfig({ digitrustId: true }); | ||
|
||
if (pbjs.idsys == null) { | ||
pbjs.idsys = {}; | ||
} | ||
pbjs.idsys[digitrustIdModule.name] = digitrustIdModule; | ||
} | ||
|
||
testHook.exposeLoader = exposeLoader; | ||
testHook.initMockDigitrust = initMockDigitrust; | ||
|
||
// Flag the config to indicate DigiTrust loader is present to the Id system. | ||
exposeLoader(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
## DigiTrust Universal Id Integration | ||
|
||
Setup | ||
----- | ||
The DigiTrust Id integration for Prebid may be used with or without the full | ||
DigiTrust library. This is an optional module that must be used in conjunction | ||
with the userId module. | ||
|
||
The full DigiTrust integration requires the DigiTrust package be included. | ||
DigiTrust may be initialized in the standard manner or through the params | ||
object. | ||
|
||
You can use npm or reference the script on the cdn. | ||
|
||
npm install digitrust | ||
|
||
or | ||
|
||
<script src="https://cdn.digitru.st/prod/1.5.20/digitrust.min.js"></script> | ||
|
||
Please note that version 1.5.20 or better is required. | ||
|
||
|
||
See the [Prebid Integration Guide for DigiTrust](https://github.com/digi-trust/dt-cdn/wiki/Prebid-Integration-for-DigiTrust-Id) | ||
and the [DigiTrust wiki](https://github.com/digi-trust/dt-cdn/wiki) | ||
for further instructions. | ||
|
||
|
||
## Example Prebid Configuration for Digitrust Id | ||
``` | ||
pbjs.que.push(function() { | ||
pbjs.setConfig({ | ||
usersync: { | ||
userIds: [{ | ||
name: "digitrust", | ||
params: { | ||
init: { | ||
member: 'example_member_id', | ||
site: 'example_site_id' | ||
}, | ||
callback: function (digiTrustResult) { | ||
if (digiTrustResult.success) { | ||
console.log('Success in Digitrust init'); | ||
if (digiTrustResult.identity && digiTrustResult.identity.id != null) { | ||
console.log('DigiTrust Id (encrypted): ' + digiTrustResult.identity.id); | ||
} | ||
else { | ||
console.error('Digitrust gave success, but no identity returned'); | ||
} | ||
} | ||
else { | ||
console.error('Digitrust init failed'); | ||
} | ||
} | ||
}, | ||
storage: { | ||
type: "html5", | ||
name: "pbjsdigitrust", | ||
expires: 60 | ||
} | ||
}] | ||
} | ||
}); | ||
pbjs.addAdUnits(adUnits); | ||
pbjs.requestBids({ | ||
bidsBackHandler: sendAdserverRequest | ||
}); | ||
}); | ||
|
||
``` | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { | ||
digitrustIdModule } from 'modules/digiTrustIdLoader'; | ||
import * as utils from 'src/utils'; | ||
import { config } from 'src/config'; | ||
import { getGlobal } from 'src/prebidGlobal'; | ||
|
||
var assert = require('chai').assert; | ||
var expect = require('chai').expect; | ||
|
||
describe('DigiTrust ID Loader', function () { | ||
before(function () { | ||
digitrustIdModule['_testInit'](); | ||
}); | ||
|
||
afterEach(function () { | ||
$$PREBID_GLOBAL$$.requestBids.removeAll(); | ||
}); | ||
|
||
describe('ConfigFlagSet', function () { | ||
it('Test config for digitrust flag prior to init is undefined', function () { | ||
let val = config.getConfig('digitrustId'); | ||
|
||
expect(val).to.be.undefined; | ||
}); | ||
|
||
it('Test config for digitrust flag true after init', function () { | ||
digitrustIdModule['_testHook'].exposeLoader(); | ||
|
||
let val = config.getConfig('digitrustId'); | ||
expect(val).to.be.true; | ||
}); | ||
}); | ||
|
||
describe('DigiTrust bootstrapped', function () { | ||
it('Init creates minimal DigiTrust object', function () { | ||
let pbjs = getGlobal(); | ||
var dtTestHook = digitrustIdModule['_testHook']; | ||
expect(window.DigiTrust).to.be.undefined; | ||
|
||
dtTestHook.exposeLoader(); | ||
dtTestHook.initMockDigitrust(); | ||
|
||
expect(window.DigiTrust).to.exist; | ||
expect(window.DigiTrust.isClient).to.be.true; | ||
}); | ||
}); | ||
}); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for the sub-module registration, can you use
attachIdSystem
from the UserId Module, for example:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'm in the process of reworking. I'm going to submit a fresh PR once ready.