Skip to content

Commit

Permalink
Merge branch 'master' into ob-user-token-localstorage
Browse files Browse the repository at this point in the history
  • Loading branch information
markkuhar committed Sep 12, 2023
2 parents 4c653e4 + ddd6a3b commit f726669
Show file tree
Hide file tree
Showing 88 changed files with 4,505 additions and 1,651 deletions.
15 changes: 3 additions & 12 deletions integrationExamples/gpt/growthcode.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,11 @@
provider: 'growthCodeAnalytics',
options: {
pid: 'TEST01',
//url: 'http://localhost:8080/v3/pb/analytics',
trackEvents: [
'auctionInit',
'auctionEnd',
'bidAdjustment',
'bidTimeout',
'bidTimeout',
'bidRequested',
'bidResponse',
'setTargeting',
'requestBids',
'addAdUnits',
'noBid',
'bidWon',
'bidderDone']
]
}
});
pbjs.setConfig({
Expand All @@ -80,7 +71,7 @@
auctionDelay: 1000,
dataProviders: [{
name: 'growthCodeRtd',
waitForIt: true,
waitForIt: false,
params: {
pid: 'TEST01',
}
Expand Down
62 changes: 46 additions & 16 deletions libraries/cmp/cmpClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,53 @@ import {GreedyPromise} from '../../src/utils/promise.js';
* @typedef {function} CMPClient
*
* @param {{}} params CMP parameters. Currently this is a subset of {command, callback, parameter, version}.
* @returns {Promise<*>} a promise that:
* - if a `callback` param was provided, resolves (with no result) just before the first time it's run;
* - if `callback` was *not* provided, resolves to the return value of the CMP command
* @param {bool} once if true, discard cross-frame event listeners once a reply message is received.
* @returns {Promise<*>} a promise to the API's "result" - see the `mode` argument to `cmpClient` on how that's determined.
* @property {boolean} isDirect true if the CMP is directly accessible (no postMessage required)
* @property {() => void} close close the client; currently, this just stops listening for cross-frame messages.
*/

/**
* Returns a function that can interface with a CMP regardless of where it's located.
* Returns a client function that can interface with a CMP regardless of where it's located.
*
* @param apiName name of the CMP api, e.g. "__gpp"
* @param apiVersion? CMP API version
* @param apiArgs? names of the arguments taken by the api function, in order.
* @param callbackArgs? names of the cross-frame response payload properties that should be passed as callback arguments, in order
* @param mode? controls the callbacks passed to the underlying API, and how the promises returned by the client are resolved.
*
* The client behaves differently when it's provided a `callback` argument vs when it's not - for short, let's name these
* cases "subscriptions" and "one-shot calls" respectively:
*
* With `mode: MODE_MIXED` (the default), promises returned on subscriptions are resolved to undefined when the callback
* is first run (that is, the promise resolves when the CMP replies, but what it replies with is discarded and
* left for the callback to deal with). For one-shot calls, the returned promise is resolved to the API's
* return value when it's directly accessible, or with the result from the first (and, presumably, the only)
* cross-frame reply when it's not;
*
* With `mode: MODE_RETURN`, the returned promise always resolves to the API's return value - which is taken to be undefined
* when cross-frame;
*
* With `mode: MODE_CALLBACK`, the underlying API is expected to never directly return anything significant; instead,
* it should always accept a callback and - for one-shot calls - invoke it only once with the result. The client will
* automatically generate an appropriate callback for one-shot calls and use the result it's given to resolve
* the returned promise. Subscriptions are treated in the same way as MODE_MIXED.
*
* @param win
* @returns {CMPClient} CMP invocation function (or null if no CMP was found).
*/

export const MODE_MIXED = 0;
export const MODE_RETURN = 1;
export const MODE_CALLBACK = 2;

export function cmpClient(
{
apiName,
apiVersion,
apiArgs = ['command', 'callback', 'parameter', 'version'],
callbackArgs = ['returnValue', 'success'],
mode = MODE_MIXED,
},
win = window
) {
Expand Down Expand Up @@ -89,15 +114,15 @@ export function cmpClient(
}

function wrapCallback(callback, resolve, reject, preamble) {
const haveCb = typeof callback === 'function';

return function (result, success) {
preamble && preamble();
const resolver = success == null || success ? resolve : reject;
if (typeof callback === 'function') {
resolver();
return callback.apply(this, arguments);
} else {
resolver(result);
if (mode !== MODE_RETURN) {
const resolver = success == null || success ? resolve : reject;
resolver(haveCb ? undefined : result);
}
haveCb && callback.apply(this, arguments);
}
}

Expand All @@ -108,17 +133,17 @@ export function cmpClient(
return new GreedyPromise((resolve, reject) => {
const ret = cmpFrame[apiName](...resolveParams({
...params,
callback: params.callback && wrapCallback(params.callback, resolve, reject)
callback: (params.callback || mode === MODE_CALLBACK) ? wrapCallback(params.callback, resolve, reject) : undefined,
}).map(([_, val]) => val));
if (params.callback == null) {
if (mode === MODE_RETURN || (params.callback == null && mode === MODE_MIXED)) {
resolve(ret);
}
});
};
} else {
win.addEventListener('message', handleMessage, false);

client = function invokeCMPFrame(params) {
client = function invokeCMPFrame(params, once = false) {
return new GreedyPromise((resolve, reject) => {
// call CMP via postMessage
const callId = Math.random().toString();
Expand All @@ -129,11 +154,16 @@ export function cmpClient(
}
};

cmpCallbacks[callId] = wrapCallback(params?.callback, resolve, reject, params?.callback == null && (() => { delete cmpCallbacks[callId] }));
cmpCallbacks[callId] = wrapCallback(params?.callback, resolve, reject, (once || params?.callback == null) && (() => { delete cmpCallbacks[callId] }));
cmpFrame.postMessage(msg, '*');
if (mode === MODE_RETURN) resolve();
});
};
}
client.isDirect = isDirect;
return client;
return Object.assign(client, {
isDirect,
close() {
!isDirect && win.removeEventListener('message', handleMessage);
}
})
}
33 changes: 25 additions & 8 deletions libraries/mspa/activityControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ACTIVITY_TRANSMIT_PRECISE_GEO
} from '../../src/activities/activities.js';
import {gppDataHandler} from '../../src/adapterManager.js';
import {logInfo} from '../../src/utils.js';

// default interpretation for MSPA consent(s):
// https://docs.prebid.org/features/mspa-usnat.html
Expand All @@ -24,7 +25,9 @@ export function isBasicConsentDenied(cd) {
// minors 13+ who have not given consent
cd.KnownChildSensitiveDataConsents[0] === 1 ||
// minors under 13 cannot consent
isApplicable(cd.KnownChildSensitiveDataConsents[1]);
isApplicable(cd.KnownChildSensitiveDataConsents[1]) ||
// covered cannot be zero
cd.MspaCoveredTransaction === 0;
}

export function sensitiveNoticeIs(cd, value) {
Expand Down Expand Up @@ -85,26 +88,40 @@ const CONSENT_RULES = {
[ACTIVITY_ENRICH_EIDS]: isConsentDenied,
[ACTIVITY_ENRICH_UFPD]: isTransmitUfpdConsentDenied,
[ACTIVITY_TRANSMIT_PRECISE_GEO]: isTransmitGeoConsentDenied
}
};

export function mspaRule(sids, getConsent, denies, applicableSids = () => gppDataHandler.getConsentData()?.applicableSections) {
return function() {
return function () {
if (applicableSids().some(sid => sids.includes(sid))) {
const consent = getConsent();
if (consent == null) {
return {allow: false, reason: 'consent data not available'};
}
if (denies(consent)) {
return {allow: false}
return {allow: false};
}
}
}
};
}

function flatSection(subsections) {
if (subsections == null) return subsections;
return subsections.reduceRight((subsection, consent) => {
return Object.assign(consent, subsection);
}, {});
}

export function setupRules(api, sids, normalizeConsent = (c) => c, rules = CONSENT_RULES, registerRule = registerActivityControl, getConsentData = () => gppDataHandler.getConsentData()) {
const unreg = [];
const ruleName = `MSPA (GPP '${api}' for section${sids.length > 1 ? 's' : ''} ${sids.join(', ')})`;
logInfo(`Enabling activity controls for ${ruleName}`)
Object.entries(rules).forEach(([activity, denies]) => {
unreg.push(registerRule(activity, `MSPA (${api})`, mspaRule(sids, () => normalizeConsent(getConsentData()?.sectionData?.[api]), denies, () => getConsentData()?.applicableSections || [])))
})
return () => unreg.forEach(ur => ur())
unreg.push(registerRule(activity, ruleName, mspaRule(
sids,
() => normalizeConsent(flatSection(getConsentData()?.parsedSections?.[api])),
denies,
() => getConsentData()?.applicableSections || []
)));
});
return () => unreg.forEach(ur => ur());
}
17 changes: 17 additions & 0 deletions modules/cadentApertureMXBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,22 @@ export const cadentAdapter = {

return cadentData;
},

getGpp: (bidRequest, cadentData) => {
if (bidRequest.gppConsent) {
const {gppString: gpp, applicableSections: gppSid} = bidRequest.gppConsent;
if (cadentData.regs) {
cadentData.regs.gpp = gpp;
cadentData.regs.gpp_sid = gppSid;
} else {
cadentData.regs = {
gpp: gpp,
gpp_sid: gppSid
}
}
}
return cadentData;
},
getSupplyChain: (bidderRequest, cadentData) => {
if (bidderRequest.bids[0] && bidderRequest.bids[0].schain) {
cadentData.source = {
Expand Down Expand Up @@ -290,6 +306,7 @@ export const spec = {
};

cadentData = cadentAdapter.getGdpr(bidderRequest, Object.assign({}, cadentData));
cadentData = cadentAdapter.getGpp(bidderRequest, Object.assign({}, cadentData));
cadentData = cadentAdapter.getSupplyChain(bidderRequest, Object.assign({}, cadentData));
if (bidderRequest && bidderRequest.uspConsent) {
cadentData.us_privacy = bidderRequest.uspConsent;
Expand Down
1 change: 1 addition & 0 deletions modules/concertBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const spec = {
prebidVersion: '$prebid.version$',
pageUrl: bidderRequest.refererInfo.page,
screen: [window.screen.width, window.screen.height].join('x'),
browserLanguage: window.navigator.language,
debug: debugTurnedOn(),
uid: getUid(bidderRequest, validBidRequests),
optedOut: hasOptedOutOfPersonalization(),
Expand Down
Loading

0 comments on commit f726669

Please sign in to comment.