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

Digitrust id integration #3739

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 233 additions & 0 deletions modules/digiTrustIdLoader.js
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;
Copy link
Contributor

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:

// add import
import {attachIdSystem} from './userId.js';

// add submodule to the userId module before the setConfig for userSync.userIds is set (ideally when the .js file inits)
attachIdSystem(digitrustIdModule);

Copy link
Contributor Author

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.

}

testHook.exposeLoader = exposeLoader;
testHook.initMockDigitrust = initMockDigitrust;

// Flag the config to indicate DigiTrust loader is present to the Id system.
exposeLoader();
74 changes: 74 additions & 0 deletions modules/digiTrustIdLoader.md
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
});
});

```




47 changes: 47 additions & 0 deletions test/spec/modules/digiTrustLoader_spec.js
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;
});
});
});