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

#4674 Addition of DigiTrust vendor check for gdpr when cmp is present. #4698

Merged
merged 2 commits into from
Jan 22, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
25 changes: 25 additions & 0 deletions integrationExamples/gpt/cmp_files/purposes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"version": 1,
"purposes": [
{
"id": 25,
"name": "Custom Purpose 1",
"description": "Here's a description of the first purpose"
},
{
"id": 26,
"name": "Custom Purpose 2",
"description": "Here's a description of the second purpose"
},
{
"id": 27,
"name": "Custom Purpose 3",
"description": "Here's a description of the third purpose"
},
{
"id": 28,
"name": "Custom Purpose 4",
"description": "Here's a description of the fourth purpose"
}
]
}
1 change: 1 addition & 0 deletions integrationExamples/gpt/digitrust_Simple.html
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
{
code: 'test-div',
sizes: [[300, 250], [300, 600], [728, 90]],
mediaTypes: { banner: { sizes: [400, 600], name: 'testAdUnit'}},
bids: [
{
bidder: 'rubicon',
Expand Down
192 changes: 192 additions & 0 deletions integrationExamples/gpt/digitrust_cmp_test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<html>
<head>
<title>CMP Simple DigiTrust Prebid - No Framework</title>
<script>
(function (window) {
window.__cmp = (function () {
window.addEventListener('message', function (event) {
window.__cmp.receiveMessage(event);
});

var commandQueue = [];
var cmp = function (command, parameter, callback) {
commandQueue.push({
command: command,
parameter: parameter,
callback: callback
});
};
cmp.commandQueue = commandQueue;
cmp.receiveMessage = function (event) {
var data = event && event.data && event.data.__cmpCall;
if (data) {
commandQueue.push({
callId: data.callId,
command: data.command,
parameter: data.parameter,
event: event
});
}
};
cmp.config = {
customPurposeListLocation: './cmp_files/purposes.json',
globalVendorListLocation: 'https://vendorlist.consensu.org/vendorlist.json',
globalConsentLocation: 'http://cmp-origin-release.digitru.st/1/docs/portal.html',
storeConsentGlobally: false,
storePublisherConsentGlobally: false,
storePublisherData: true,
layout: 'footer',
logging: "debug",
blockBrowsing: false,
forceLocale: 'en',
testingMode: 'always show',
showFooterAfterSubmit: true,
};
return cmp;
}());
})(window);

window.__cmp('renderCmpIfNeeded');
</script>

<script>
var FAILSAFE_TIMEOUT = 2000;

var adUnits = [
{
code: 'test-div',
sizes: [[300, 250], [300, 600], [728, 90]],
mediaTypes: { banner: { sizes: [400, 600], name: 'testAdUnit' } },
bids: [
{
bidder: 'rubicon',
params: {
accountId: '1001',
siteId: '113932',
zoneId: '535510'
}
}
]
}
];

var pbjs = pbjs || {};
pbjs.que = pbjs.que || [];
</script>
<script src="../../build/dev/prebid.js" async></script>

<script>
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
googletag.cmd.push(function () {
googletag.pubads().disableInitialLoad();
});

pbjs.que.push(function () {
pbjs.setConfig({
debug: true,
consentManagement: {
cmpApi: 'iab',
timeout: 1000,
allowAuctionWithoutConsent: true
},
usersync: {
userIds: [{
name: "digitrust",
params: {
init: {
member: 'example_member_id',
site: 'example_site_id'
},
callback: function (digiTrustResult) {
// This callback can be used by publisher page to react to error conditions
// Or pass the DigiTrust ID on.
// If the Prebid userId system already has a managed copy of the DigiTrust ID
// this callback will not be invoked.
var elem = document.getElementById('idDiv');
var msg;
if (digiTrustResult.success) {
console.log('Success in Digitrust init');
if (digiTrustResult.identity && digiTrustResult.identity.id != null) {
msg = 'DigiTrust Id (encrypted): ' + digiTrustResult.identity.id;
elem.innerHTML = msg;
console.log(msg);
}
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
});
});

function sendAdserverRequest() {
if (pbjs.adserverRequestSent) return;
pbjs.adserverRequestSent = true;
googletag.cmd.push(function () {
pbjs.que.push(function () {
pbjs.setTargetingForGPTAsync();
googletag.pubads().refresh();
});
});
}

setTimeout(function () {
sendAdserverRequest();
}, FAILSAFE_TIMEOUT);
</script>

<script>
(function () {
var gads = document.createElement('script');
gads.async = true;
gads.type = 'text/javascript';
var useSSL = 'https:' == document.location.protocol;
gads.src = (useSSL ? 'https:' : 'http:') +
'//www.googletagservices.com/tag/js/gpt.js';
var node = document.getElementsByTagName('script')[0];
node.parentNode.insertBefore(gads, node);
})();
</script>

<script>
googletag.cmd.push(function () {
googletag.defineSlot('/112115922/FL_PB_MedRect', [[300, 250], [300, 600]], 'test-div').addService(googletag.pubads());
googletag.pubads().enableSingleRequest();
googletag.enableServices();
});
</script>
</head>

<body>
<h2>DigiTrust Prebid Sample - No Framework</h2>

<p>
This sample tests cmp behavior with simple integration path for using DigiTrust ID with Prebid.
You can use DigiTrust ID without integrating the entire DigiTrust suite.
</p>
<div id="idDiv"></div>

<div id='test-div'>
<script>
googletag.cmd.push(function () { googletag.display('test-div'); });
</script>
</div>
<script src="http://cmp-origin-release.digitru.st/1/cmp.bundle.js"></script>
</body>
</html>
48 changes: 46 additions & 2 deletions modules/digiTrustIdSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var noop = function () {

const MAX_RETRIES = 2;
const DT_ID_SVC = 'https://prebid.digitru.st/id/v1';
const DT_VENDOR_ID = 65; // cmp gvlVendorId
goosemanjack marked this conversation as resolved.
Show resolved Hide resolved

var isFunc = function (fn) {
return typeof (fn) === 'function';
Expand Down Expand Up @@ -120,7 +121,7 @@ function initDigitrustFacade(config) {
}
}

if (!isMemberIdValid) {
if (!isMemberIdValid(obj.member)) {
if (!isAsync) {
return errResp
} else {
Expand Down Expand Up @@ -159,7 +160,12 @@ function initDigitrustFacade(config) {
}
}

callApi(opts);
// check gdpr vendor here. Full DigiTrust library has vendor check built in
gdprConsent.hasConsent(null, function (hasConsent) {
if (hasConsent) {
callApi(opts);
}
})

if (!isAsync) {
return errResp; // even if it will be successful later, without a callback we report a "failure in this moment"
Expand Down Expand Up @@ -189,6 +195,43 @@ var isMemberIdValid = function (memberId) {
}
};

/**
* DigiTrust consent handler for GDPR and __cmp.
* */
var gdprConsent = {
hasConsent: function (options, consentCb) {
options = options || { consentTimeout: 1500 };
var stopTimer;
var processed = false;
var consentAnswer = false;
if (typeof (window.__cmp) !== 'undefined') {
stopTimer = setTimeout(function () {
consentAnswer = true;
consentCb(consentAnswer);
processed = true;
}, options.consentTimeout);

window.__cmp('ping', null, function(pingAnswer) {
if (pingAnswer.gdprAppliesGlobally) {
window.__cmp('getVendorConsents', [DT_VENDOR_ID], function (result) {
if (processed) { return; } // timeout before cmp answer, cancel
clearTimeout(stopTimer);
var myconsent = result.vendorConsents[DT_VENDOR_ID];
consentCb(myconsent);
});
} else {
if (processed) { return; } // timeout before cmp answer, cancel
clearTimeout(stopTimer);
consentAnswer = true;
consentCb(consentAnswer);
}
});
}
consentAnswer = true;
consentCb(consentAnswer);
}
}

/**
* Encapsulation of needed info for the callback return.
*
Expand Down Expand Up @@ -321,6 +364,7 @@ export function surfaceTestHook() {
}

testHook.initDigitrustFacade = initDigitrustFacade; // expose for unit tests
testHook.gdpr = gdprConsent;

/** @type {Submodule} */
export const digiTrustIdSubmodule = {
Expand Down
74 changes: 73 additions & 1 deletion test/spec/modules/digitrustIdSystem_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,39 @@ import {

let assert = require('chai').assert;
let expect = require('chai').expect;

const DIGI_VENDOR_ID = 65;
goosemanjack marked this conversation as resolved.
Show resolved Hide resolved
var testHook = null;

/**
* A mock implementation of IAB Consent Provider
*/
function mockCmp(command, version, callback, parameter) {
var resultVal;
if (command == 'ping') {
resultVal = {
gdprAppliesGlobally: mockCmp.stubSettings.isGlobal
};
callback(resultVal);
} else if (command == 'getVendorConsents') {
let cbResult = {
vendorConsents: []
}
cbResult.vendorConsents[version] = mockCmp.stubSettings.consents;
callback(cbResult);
}
}

mockCmp.stubSettings = {
isGlobal: false,
consents: true
};

function setupCmpMock(isGlobal, consents) {
window.__cmp = mockCmp;
mockCmp.stubSettings.isGlobal = isGlobal;
mockCmp.stubSettings.consents = consents;
}

describe('DigiTrust Id System', function () {
it('Should create the test hook', function (done) {
testHook = surfaceTestHook();
Expand Down Expand Up @@ -47,4 +77,46 @@ describe('DigiTrust Id System', function () {
expect(window.DigiTrust.isClient).to.be.true;
done();
});

it('Should allow consent when given', function (done) {
testHook = surfaceTestHook();
setupCmpMock(true, true);
var handler = function(result) {
expect(result).to.be.true;
done();
}

testHook.gdpr.hasConsent(null, handler);
});

it('Should consent if does not apply', function (done) {
testHook = surfaceTestHook();
setupCmpMock(false, true);
var handler = function (result) {
expect(result).to.be.true;
done();
}

testHook.gdpr.hasConsent(null, handler);
});

it('Should not allow consent when not given', function (done) {
testHook = surfaceTestHook();
setupCmpMock(true, false);
var handler = function (result) {
expect(result).to.be.false;
done();
}

testHook.gdpr.hasConsent(null, handler);
});
it('Should allow consent if timeout', function (done) {
window.__cmp = function () { };
var handler = function (result) {
expect(result).to.be.true;
done();
}

testHook.gdpr.hasConsent({ consentTimeout: 1 }, handler);
});
});