Skip to content

Commit

Permalink
consentManagementTcf: add flag to set dsarequired (prebid#11824)
Browse files Browse the repository at this point in the history
* consentManagementTcf: add flag to set dsarequired

* Fix duplication
  • Loading branch information
dgirardi authored and DecayConstant committed Jul 18, 2024
1 parent 2bdebc5 commit c45bd34
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 78 deletions.
38 changes: 38 additions & 0 deletions libraries/consentManagement/cmUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {timedAuctionHook} from '../../src/utils/perfMetrics.js';
import {logError, logInfo, logWarn} from '../../src/utils.js';

export function consentManagementHook(name, getConsent, loadConsentData) {
function loadIfMissing(cb) {
if (getConsent()) {
logInfo('User consent information already known. Pulling internally stored information...');
// eslint-disable-next-line standard/no-callback-literal
cb(false);
} else {
loadConsentData(cb);
}
}

return timedAuctionHook(name, function requestBidsHook(fn, reqBidsConfigObj) {
loadIfMissing(function (shouldCancelAuction, errMsg, ...extraArgs) {
if (errMsg) {
let log = logWarn;
if (shouldCancelAuction) {
log = logError;
errMsg = `${errMsg} Canceling auction as per consentManagement config.`;
}
log(errMsg, ...extraArgs);
}

if (shouldCancelAuction) {
fn.stopTiming();
if (typeof reqBidsConfigObj.bidsBackHandler === 'function') {
reqBidsConfigObj.bidsBackHandler();
} else {
logError('Error executing bidsBackHandler');
}
} else {
fn.call(this, reqBidsConfigObj);
}
});
});
}
40 changes: 2 additions & 38 deletions modules/consentManagementGpp.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
import {deepSetValue, isEmpty, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js';
import {config} from '../src/config.js';
import {gppDataHandler} from '../src/adapterManager.js';
import {timedAuctionHook} from '../src/utils/perfMetrics.js';
import {enrichFPD} from '../src/fpd/enrichment.js';
import {getGlobal} from '../src/prebidGlobal.js';
import {cmpClient, MODE_CALLBACK} from '../libraries/cmp/cmpClient.js';
import {GreedyPromise} from '../src/utils/promise.js';
import {buildActivityParams} from '../src/activities/params.js';
import {consentManagementHook} from '../libraries/consentManagement/cmUtils.js';

const DEFAULT_CMP = 'iab';
const DEFAULT_CONSENT_TIMEOUT = 10000;
Expand Down Expand Up @@ -228,20 +228,6 @@ function loadConsentData(cb) {
}
}

/**
* Like `loadConsentData`, but cache and re-use previously loaded data.
* @param cb
*/
function loadIfMissing(cb) {
if (consentData) {
logInfo('User consent information already known. Pulling internally stored information...');
// eslint-disable-next-line standard/no-callback-literal
cb(false);
} else {
loadConsentData(cb);
}
}

/**
* If consentManagement module is enabled (ie included in setConfig), this hook function will attempt to fetch the
* user's encoded consent string from the supported CMP. Once obtained, the module will store this
Expand All @@ -250,29 +236,7 @@ function loadIfMissing(cb) {
* @param {object} reqBidsConfigObj required; This is the same param that's used in pbjs.requestBids.
* @param {function} fn required; The next function in the chain, used by hook.js
*/
export const requestBidsHook = timedAuctionHook('gpp', function requestBidsHook(fn, reqBidsConfigObj) {
loadIfMissing(function (shouldCancelAuction, errMsg, ...extraArgs) {
if (errMsg) {
let log = logWarn;
if (shouldCancelAuction) {
log = logError;
errMsg = `${errMsg} Canceling auction as per consentManagement config.`;
}
log(errMsg, ...extraArgs);
}

if (shouldCancelAuction) {
fn.stopTiming();
if (typeof reqBidsConfigObj.bidsBackHandler === 'function') {
reqBidsConfigObj.bidsBackHandler();
} else {
logError('Error executing bidsBackHandler');
}
} else {
fn.call(this, reqBidsConfigObj);
}
});
});
export const requestBidsHook = consentManagementHook('gpp', () => consentData, loadConsentData);

function processCmpData(consentData) {
if (
Expand Down
45 changes: 7 additions & 38 deletions modules/consentManagementTcf.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import {deepSetValue, isNumber, isPlainObject, isStr, logError, logInfo, logWarn
import {config} from '../src/config.js';
import {gdprDataHandler} from '../src/adapterManager.js';
import {includes} from '../src/polyfill.js';
import {timedAuctionHook} from '../src/utils/perfMetrics.js';
import {registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js';
import {enrichFPD} from '../src/fpd/enrichment.js';
import {getGlobal} from '../src/prebidGlobal.js';
import {cmpClient} from '../libraries/cmp/cmpClient.js';
import {consentManagementHook} from '../libraries/consentManagement/cmUtils.js';

const DEFAULT_CMP = 'iab';
const DEFAULT_CONSENT_TIMEOUT = 10000;
Expand All @@ -22,6 +22,7 @@ export let userCMP;
export let consentTimeout;
export let gdprScope;
export let staticConsentData;
let dsaPlatform = false;
let actionTimeout;

let consentData;
Expand Down Expand Up @@ -156,20 +157,6 @@ function loadConsentData(cb) {
}
}

/**
* Like `loadConsentData`, but cache and re-use previously loaded data.
* @param cb
*/
function loadIfMissing(cb) {
if (consentData) {
logInfo('User consent information already known. Pulling internally stored information...');
// eslint-disable-next-line standard/no-callback-literal
cb(false);
} else {
loadConsentData(cb);
}
}

/**
* If consentManagement module is enabled (ie included in setConfig), this hook function will attempt to fetch the
* user's encoded consent string from the supported CMP. Once obtained, the module will store this
Expand All @@ -178,29 +165,7 @@ function loadIfMissing(cb) {
* @param {object} reqBidsConfigObj required; This is the same param that's used in pbjs.requestBids.
* @param {function} fn required; The next function in the chain, used by hook.js
*/
export const requestBidsHook = timedAuctionHook('gdpr', function requestBidsHook(fn, reqBidsConfigObj) {
loadIfMissing(function (shouldCancelAuction, errMsg, ...extraArgs) {
if (errMsg) {
let log = logWarn;
if (shouldCancelAuction) {
log = logError;
errMsg = `${errMsg} Canceling auction as per consentManagement config.`;
}
log(errMsg, ...extraArgs);
}

if (shouldCancelAuction) {
fn.stopTiming();
if (typeof reqBidsConfigObj.bidsBackHandler === 'function') {
reqBidsConfigObj.bidsBackHandler();
} else {
logError('Error executing bidsBackHandler');
}
} else {
fn.call(this, reqBidsConfigObj);
}
});
});
export const requestBidsHook = consentManagementHook('gdpr', () => consentData, loadConsentData);

/**
* This function checks the consent data provided by CMP to ensure it's in an expected state.
Expand Down Expand Up @@ -282,6 +247,7 @@ export function setConsentConfig(config) {

// if true, then gdprApplies should be set to true
gdprScope = config.defaultGdprScope === true;
dsaPlatform = !!config.dsaPlatform;

logInfo('consentManagement module has been activated...');

Expand Down Expand Up @@ -315,6 +281,9 @@ export function enrichFPDHook(next, fpd) {
}
deepSetValue(ortb2, 'user.ext.consent', consent.consentString);
}
if (dsaPlatform) {
deepSetValue(ortb2, 'regs.ext.dsa.dsarequired', 3);
}
return ortb2;
}));
}
Expand Down
26 changes: 24 additions & 2 deletions test/spec/fpd/gdpr_spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {gdprDataHandler} from '../../../src/adapterManager.js';
import {enrichFPDHook} from '../../../modules/consentManagementTcf.js';
import {config} from 'src/config.js';
import 'src/prebid.js';

describe('GDPR FPD enrichment', () => {
let sandbox, consent;
Expand All @@ -12,9 +14,9 @@ describe('GDPR FPD enrichment', () => {
sandbox.restore();
})

function callHook() {
function callHook(ortb2 = {}) {
let result;
enrichFPDHook((res) => { result = res }, Promise.resolve({}));
enrichFPDHook((res) => { result = res }, Promise.resolve(ortb2));
return result;
}

Expand Down Expand Up @@ -44,4 +46,24 @@ describe('GDPR FPD enrichment', () => {
})
})
});

describe('dsa', () => {
describe('when dsaPlaform is set', () => {
beforeEach(() => {
config.setConfig({
consentManagement: {
gdpr: {
dsaPlatform: true
}
}
});
});

it('sets dsarequired', () => {
return callHook().then(ortb2 => {
expect(ortb2.regs.ext.dsa.dsarequired).to.equal(3);
});
});
});
});
});

0 comments on commit c45bd34

Please sign in to comment.