From 180b79cad570a38f6dcda1f2060d26ab1f9a1688 Mon Sep 17 00:00:00 2001 From: Reinout Stevens Date: Wed, 2 Dec 2020 12:13:51 +0100 Subject: [PATCH 1/2] align locator + fix remove listener --- modules/consentManagementUsp.js | 85 +++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 30 deletions(-) diff --git a/modules/consentManagementUsp.js b/modules/consentManagementUsp.js index 3edacb41549..bfcb1372c02 100644 --- a/modules/consentManagementUsp.js +++ b/modules/consentManagementUsp.js @@ -44,6 +44,34 @@ 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 = {}; @@ -61,13 +89,19 @@ 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) @@ -76,26 +110,22 @@ function lookupUspConsent(uspSuccess, uspError, hookConfig) { // - 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) { @@ -107,19 +137,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; @@ -130,11 +160,6 @@ function lookupUspConsent(uspSuccess, uspError, hookConfig) { } } } - - function uspapiCallback(consentObject, success) { - window.removeEventListener('message', readPostMessageResponse, false); - moduleCallback(consentObject, success); - } } } From 73a88a3b5fb2478c9c3f0fec0467346737ce521b Mon Sep 17 00:00:00 2001 From: Reinout Stevens Date: Wed, 2 Dec 2020 12:20:41 +0100 Subject: [PATCH 2/2] update comment --- modules/consentManagementUsp.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/consentManagementUsp.js b/modules/consentManagementUsp.js index bfcb1372c02..cba9c2758d0 100644 --- a/modules/consentManagementUsp.js +++ b/modules/consentManagementUsp.js @@ -57,6 +57,7 @@ function lookupUspConsent(uspSuccess, uspError, hookConfig) { break; } } catch (e) {} + try { if (f.frames['__uspapiLocator']) { uspapiFrame = f; @@ -106,10 +107,10 @@ function lookupUspConsent(uspSuccess, uspError, hookConfig) { // 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 + if (utils.isFn(uspapiFunction)) { utils.logInfo('Detected USP CMP is directly accessible, calling it now...'); uspapiFunction(