Skip to content

Commit

Permalink
Revert "TCFv2.0 Purpose 7 (prebid#5444)"
Browse files Browse the repository at this point in the history
This reverts commit 13eae5b.
  • Loading branch information
BrightMountainMediaInc committed Sep 14, 2020
1 parent 1547698 commit 966065b
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 242 deletions.
3 changes: 1 addition & 2 deletions modules/appnexusAnalyticsAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ var appnexusAdapter = adapter({

adapterManager.registerAnalyticsAdapter({
adapter: appnexusAdapter,
code: 'appnexus',
gvlid: 32
code: 'appnexus'
});

export default appnexusAdapter;
119 changes: 10 additions & 109 deletions modules/gdprEnforcement.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,9 @@ import { EVENTS } from '../src/constants.json';

const TCF2 = {
'purpose1': { id: 1, name: 'storage' },
'purpose2': { id: 2, name: 'basicAds' },
'purpose7': { id: 7, name: 'measurement' }
'purpose2': { id: 2, name: 'basicAds' }
}

/*
These rules would be used if `consentManagement.gdpr.rules` is undefined by the publisher.
*/
const DEFAULT_RULES = [{
purpose: 'storage',
enforcePurpose: true,
Expand All @@ -37,21 +33,9 @@ const DEFAULT_RULES = [{

export let purpose1Rule;
export let purpose2Rule;
export let purpose7Rule;

export let enforcementRules;

const storageBlocked = [];
const biddersBlocked = [];
const analyticsBlocked = [];

let addedDeviceAccessHook = false;
export let enforcementRules;

/**
* Returns gvlId for Bid Adapters. If a bidder does not have an associated gvlId, it returns 'undefined'.
* @param {string=} bidderCode - The 'code' property on the Bidder spec.
* @retuns {number} gvlId
*/
function getGvlid(bidderCode) {
let gvlid;
bidderCode = bidderCode || config.getCurrentBidder();
Expand All @@ -69,11 +53,6 @@ function getGvlid(bidderCode) {
return gvlid;
}

/**
* Returns gvlId for userId module. If a userId modules does not have an associated gvlId, it returns 'undefined'.
* @param {Object} userIdModule
* @retuns {number} gvlId
*/
function getGvlidForUserIdModule(userIdModule) {
let gvlId;
const gvlMapping = config.getConfig('gvlMapping');
Expand All @@ -85,22 +64,6 @@ function getGvlidForUserIdModule(userIdModule) {
return gvlId;
}

/**
* Returns gvlId for analytics adapters. If a analytics adapter does not have an associated gvlId, it returns 'undefined'.
* @param {string} code - 'provider' property on the analytics adapter config
* @returns {number} gvlId
*/
function getGvlidForAnalyticsAdapter(code) {
let gvlId;
const gvlMapping = config.getConfig('gvlMapping');
if (gvlMapping && gvlMapping[code]) {
gvlId = gvlMapping[code];
} else {
gvlId = adapterManager.getAnalyticsAdapter(code).gvlid;
}
return gvlId;
}

/**
* This function takes in a rule and consentData and validates against the consentData provided. Depending on what it returns,
* the caller may decide to suppress a TCF-sensitive activity.
Expand Down Expand Up @@ -173,9 +136,8 @@ export function deviceAccessHook(fn, gvlid, moduleName, result) {
result.valid = true;
fn.call(this, gvlid, moduleName, result);
} else {
curModule && utils.logWarn(`TCF2 denied device access for ${curModule}`);
curModule && utils.logWarn(`Device access denied for ${curModule} by TCF2`);
result.valid = false;
storageBlocked.push(curModule);
fn.call(this, gvlid, moduleName, result);
}
} else {
Expand Down Expand Up @@ -206,7 +168,6 @@ export function userSyncHook(fn, ...args) {
fn.call(this, ...args);
} else {
utils.logWarn(`User sync not allowed for ${curBidder}`);
storageBlocked.push(curBidder);
}
} else {
// The module doesn't enforce TCF1.1 strings
Expand Down Expand Up @@ -234,11 +195,10 @@ export function userIdHook(fn, submodules, consentData) {
return submodule;
} else {
utils.logWarn(`User denied permission to fetch user id for ${moduleName} User id module`);
storageBlocked.push(moduleName);
}
return undefined;
}).filter(module => module)
fn.call(this, userIdModules, { ...consentData, hasValidated: true });
fn.call(this, userIdModules, {...consentData, hasValidated: true});
} else {
// The module doesn't enforce TCF1.1 strings
fn.call(this, submodules, consentData);
Expand All @@ -249,24 +209,26 @@ export function userIdHook(fn, submodules, consentData) {
}

/**
* Checks if bidders are allowed in the auction.
* Enforces "purpose 2 (Basic Ads)" of TCF v2.0 spec
* Checks if a bidder is allowed in Auction.
* Enforces "purpose 2 (basic ads)" of TCF v2.0 spec
* @param {Function} fn - Function reference to the original function.
* @param {Array<adUnits>} adUnits
*/
export function makeBidRequestsHook(fn, adUnits, ...args) {
const consentData = gdprDataHandler.getConsentData();
if (consentData && consentData.gdprApplies) {
if (consentData.apiVersion === 2) {
const disabledBidders = [];
adUnits.forEach(adUnit => {
adUnit.bids = adUnit.bids.filter(bid => {
const currBidder = bid.bidder;
const gvlId = getGvlid(currBidder);
if (includes(biddersBlocked, currBidder)) return false;
if (includes(disabledBidders, currBidder)) return false;
const isAllowed = !!validateRules(purpose2Rule, consentData, currBidder, gvlId);
if (!isAllowed) {
utils.logWarn(`TCF2 blocked auction for ${currBidder}`);
biddersBlocked.push(currBidder);
events.emit(EVENTS.BIDDER_BLOCKED, currBidder);
disabledBidders.push(currBidder);
}
return isAllowed;
});
Expand All @@ -281,64 +243,8 @@ export function makeBidRequestsHook(fn, adUnits, ...args) {
}
}

/**
* Checks if Analytics adapters are allowed to send data to their servers for furhter processing.
* Enforces "purpose 7 (Measurement)" of TCF v2.0 spec
* @param {Function} fn - Function reference to the original function.
* @param {Array<AnalyticsAdapterConfig>} config - Configuration object passed to pbjs.enableAnalytics()
*/
export function enableAnalyticsHook(fn, config) {
const consentData = gdprDataHandler.getConsentData();
if (consentData && consentData.gdprApplies) {
if (consentData.apiVersion === 2) {
if (!utils.isArray(config)) {
config = [config]
}
config = config.filter(conf => {
const analyticsAdapterCode = conf.provider;
const gvlid = getGvlidForAnalyticsAdapter(analyticsAdapterCode);
const isAllowed = !!validateRules(purpose7Rule, consentData, analyticsAdapterCode, gvlid);
if (!isAllowed) {
analyticsBlocked.push(analyticsAdapterCode);
utils.logWarn(`TCF2 blocked analytics adapter ${conf.provider}`);
}
return isAllowed;
});
fn.call(this, config);
} else {
// This module doesn't enforce TCF1.1 strings
fn.call(this, config);
}
} else {
fn.call(this, config);
}
}

/**
* Compiles the TCF2.0 enforcement results into an object, which is emitted as an event payload to "tcf2Enforcement" event.
*/
function emitTCF2FinalResults() {
// remove null and duplicate values
const formatArray = function (arr) {
return arr.filter((i, k) => i !== null && arr.indexOf(i) === k);
}
const tcf2FinalResults = {
storageBlocked: formatArray(storageBlocked),
biddersBlocked: formatArray(biddersBlocked),
analyticsBlocked: formatArray(analyticsBlocked)
};

events.emit(EVENTS.TCF2_ENFORCEMENT, tcf2FinalResults);
}

events.on(EVENTS.AUCTION_END, emitTCF2FinalResults);

/*
Set of callback functions used to detect presence of a TCF rule, passed as the second argument to find().
*/
const hasPurpose1 = (rule) => { return rule.purpose === TCF2.purpose1.name }
const hasPurpose2 = (rule) => { return rule.purpose === TCF2.purpose2.name }
const hasPurpose7 = (rule) => { return rule.purpose === TCF2.purpose7.name }

/**
* A configuration function that initializes some module variables, as well as adds hooks
Expand All @@ -355,7 +261,6 @@ export function setEnforcementConfig(config) {

purpose1Rule = find(enforcementRules, hasPurpose1);
purpose2Rule = find(enforcementRules, hasPurpose2);
purpose7Rule = find(enforcementRules, hasPurpose7);

if (!purpose1Rule) {
purpose1Rule = DEFAULT_RULES[0];
Expand All @@ -375,10 +280,6 @@ export function setEnforcementConfig(config) {
if (purpose2Rule) {
getHook('makeBidRequests').before(makeBidRequestsHook);
}

if (purpose7Rule) {
getHook('enableAnalyticsCb').before(enableAnalyticsHook);
}
}

config.getConfig('consentManagement', config => setEnforcementConfig(config.consentManagement));
12 changes: 4 additions & 8 deletions src/adapterManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -468,11 +468,11 @@ adapterManager.aliasBidAdapter = function (bidderCode, alias, options) {
}
};

adapterManager.registerAnalyticsAdapter = function ({adapter, code, gvlid}) {
adapterManager.registerAnalyticsAdapter = function ({adapter, code}) {
if (adapter && code) {
if (typeof adapter.enableAnalytics === 'function') {
adapter.code = code;
_analyticsRegistry[code] = { adapter, gvlid };
_analyticsRegistry[code] = adapter;
} else {
utils.logError(`Prebid Error: Analytics adaptor error for analytics "${code}"
analytics adapter must implement an enableAnalytics() function`);
Expand All @@ -488,24 +488,20 @@ adapterManager.enableAnalytics = function (config) {
}

utils._each(config, adapterConfig => {
var adapter = _analyticsRegistry[adapterConfig.provider].adapter;
var adapter = _analyticsRegistry[adapterConfig.provider];
if (adapter) {
adapter.enableAnalytics(adapterConfig);
} else {
utils.logError(`Prebid Error: no analytics adapter found in registry for
${adapterConfig.provider}.`);
}
});
}
};

adapterManager.getBidAdapter = function(bidder) {
return _bidderRegistry[bidder];
};

adapterManager.getAnalyticsAdapter = function(code) {
return _analyticsRegistry[code];
}

// the s2sTesting module is injected when it's loaded rather than being imported
// importing it causes the packager to include it even when it's not explicitly included in the build
export function setS2STestingModule(module) {
Expand Down
4 changes: 2 additions & 2 deletions src/constants.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
"BEFORE_REQUEST_BIDS": "beforeRequestBids",
"REQUEST_BIDS": "requestBids",
"ADD_AD_UNITS": "addAdUnits",
"AD_RENDER_FAILED": "adRenderFailed",
"TCF2_ENFORCEMENT": "tcf2Enforcement"
"AD_RENDER_FAILED" : "adRenderFailed",
"BIDDER_BLOCKED": "bidderBlocked"
},
"AD_RENDER_FAILED_REASON" : {
"PREVENT_WRITING_ON_MAIN_DOCUMENT": "preventWritingOnMainDocuemnt",
Expand Down
15 changes: 3 additions & 12 deletions src/prebid.js
Original file line number Diff line number Diff line change
Expand Up @@ -536,9 +536,8 @@ $$PREBID_GLOBAL$$.requestBids = hook('async', function ({ bidsBackHandler, timeo
auction.callBids();
});

export function executeCallbacks(fn, reqBidsConfigObj) {
export function executeStorageCallbacks(fn, reqBidsConfigObj) {
runAll(storageCallbacks);
runAll(enableAnalyticsCallbacks);
fn.call(this, reqBidsConfigObj);
function runAll(queue) {
var queued;
Expand All @@ -549,7 +548,7 @@ export function executeCallbacks(fn, reqBidsConfigObj) {
}

// This hook will execute all storage callbacks which were registered before gdpr enforcement hook was added. Some bidders, user id modules use storage functions when module is parsed but gdpr enforcement hook is not added at that stage as setConfig callbacks are yet to be called. Hence for such calls we execute all the stored callbacks just before requestBids. At this hook point we will know for sure that gdprEnforcement module is added or not
$$PREBID_GLOBAL$$.requestBids.before(executeCallbacks, 49);
$$PREBID_GLOBAL$$.requestBids.before(executeStorageCallbacks, 49);

/**
*
Expand Down Expand Up @@ -668,21 +667,13 @@ $$PREBID_GLOBAL$$.createBid = function (statusCode) {
* @param {Object} config.options The options for this particular analytics adapter. This will likely vary between adapters.
* @alias module:pbjs.enableAnalytics
*/

// Stores 'enableAnalytics' callbacks for later execution.
const enableAnalyticsCallbacks = [];

const enableAnalyticsCb = hook('async', function (config) {
$$PREBID_GLOBAL$$.enableAnalytics = function (config) {
if (config && !utils.isEmpty(config)) {
utils.logInfo('Invoking $$PREBID_GLOBAL$$.enableAnalytics for: ', config);
adapterManager.enableAnalytics(config);
} else {
utils.logError('$$PREBID_GLOBAL$$.enableAnalytics should be called with option {}');
}
}, 'enableAnalyticsCb');

$$PREBID_GLOBAL$$.enableAnalytics = function (config) {
enableAnalyticsCallbacks.push(enableAnalyticsCb.bind(this, config));
};

/**
Expand Down
Loading

0 comments on commit 966065b

Please sign in to comment.