Skip to content

Commit

Permalink
Improve __uspapi behavior in iframe (#6072)
Browse files Browse the repository at this point in the history
* align locator + fix remove listener

* update comment

Co-authored-by: Reinout Stevens <reinout@crazygames.com>
  • Loading branch information
ReinoutStevens and Reinout Stevens authored Jan 13, 2021
1 parent 4938e4f commit 681c8e7
Showing 1 changed file with 58 additions and 32 deletions.
90 changes: 58 additions & 32 deletions modules/consentManagementUsp.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,35 @@ function lookupStaticConsentData(cmpSuccess, cmpError, hookConfig) {
* @param {object} hookConfig contains module related variables (see comment in requestBidsHook function)
*/
function lookupUspConsent(uspSuccess, uspError, hookConfig) {
function findUsp() {
let f = window;
let uspapiFrame;
let uspapiFunction;

while (!uspapiFrame) {
try {
if (typeof f.__uspapi === 'function') {
uspapiFunction = f.__uspapi;
uspapiFrame = f;
break;
}
} catch (e) {}

try {
if (f.frames['__uspapiLocator']) {
uspapiFrame = f;
break;
}
} catch (e) {}
if (f === window.top) break;
f = f.parent;
}
return {
uspapiFrame,
uspapiFunction,
};
}

function handleUspApiResponseCallbacks() {
const uspResponse = {};

Expand All @@ -61,41 +90,43 @@ function lookupUspConsent(uspSuccess, uspError, hookConfig) {
uspResponse.usPrivacy = consentResponse.uspString;
}
afterEach();
}
},
};
}

let callbackHandler = handleUspApiResponseCallbacks();
let uspapiCallbacks = {};

let { uspapiFrame, uspapiFunction } = findUsp();

if (!uspapiFrame) {
return uspError('USP CMP not found.', hookConfig);
}

// to collect the consent information from the user, we perform a call to USPAPI
// to collect the user's consent choices represented as a string (via getUSPData)

// the following code also determines where the USPAPI is located and uses the proper workflow to communicate with it:
// - use the USPAPI locator code to see if USP's located in the current window or an ancestor window. This works in friendly or cross domain iframes
// - use the USPAPI locator code to see if USP's located in the current window or an ancestor window.
// - else assume prebid is in an iframe, and use the locator to see if the CMP is located in a higher parent window. This works in cross domain iframes.
// - if USPAPI is not found, the iframe function will call the uspError exit callback to abort the rest of the USPAPI workflow
// - try to call the __uspapi() function directly, otherwise use the postMessage() api
// find the CMP frame/window

try {
// try to call __uspapi directly
window.__uspapi('getUSPData', USPAPI_VERSION, callbackHandler.consentDataCallback);
} catch (e) {
// must not have been accessible, try using postMessage() api
let f = window;
let uspapiFrame;
while (!uspapiFrame) {
try {
if (f.frames['__uspapiLocator']) uspapiFrame = f;
} catch (e) { }
if (f === window.top) break;
f = f.parent;
}

if (!uspapiFrame) {
return uspError('USP CMP not found.', hookConfig);
}
callUspApiWhileInIframe('getUSPData', uspapiFrame, callbackHandler.consentDataCallback);
if (utils.isFn(uspapiFunction)) {
utils.logInfo('Detected USP CMP is directly accessible, calling it now...');
uspapiFunction(
'getUSPData',
USPAPI_VERSION,
callbackHandler.consentDataCallback
);
} else {
utils.logInfo(
'Detected USP CMP is outside the current iframe where Prebid.js is located, calling it now...'
);
callUspApiWhileInIframe(
'getUSPData',
uspapiFrame,
callbackHandler.consentDataCallback
);
}

function callUspApiWhileInIframe(commandName, uspapiFrame, moduleCallback) {
Expand All @@ -107,19 +138,19 @@ function lookupUspConsent(uspSuccess, uspError, hookConfig) {
__uspapiCall: {
command: cmd,
version: ver,
callId: callId
}
callId: callId,
},
};

uspapiCallbacks[callId] = callback;
uspapiFrame.postMessage(msg, '*');
}
};

/** when we get the return message, call the stashed callback */
window.addEventListener('message', readPostMessageResponse, false);

// call uspapi
window.__uspapi(commandName, USPAPI_VERSION, uspapiCallback);
window.__uspapi(commandName, USPAPI_VERSION, moduleCallback);

function readPostMessageResponse(event) {
const res = event && event.data && event.data.__uspapiReturn;
Expand All @@ -130,11 +161,6 @@ function lookupUspConsent(uspSuccess, uspError, hookConfig) {
}
}
}

function uspapiCallback(consentObject, success) {
window.removeEventListener('message', readPostMessageResponse, false);
moduleCallback(consentObject, success);
}
}
}

Expand Down

0 comments on commit 681c8e7

Please sign in to comment.