Skip to content

Commit

Permalink
topicsFpdModule: replace ad-hoc GDPR logic with transmitUfpd acitiv…
Browse files Browse the repository at this point in the history
…ity check; check for topics support before loading frames (#10201)

* topicsFpdModule: replace ad-hoc GDPR logic with `transmitUfpd` acitivity check; check for topics support before loading frames

* Use `enrichUfpd` instead of `transmitUfpd`
  • Loading branch information
dgirardi authored Jul 25, 2023
1 parent c063319 commit bcf080d
Show file tree
Hide file tree
Showing 2 changed files with 364 additions and 413 deletions.
69 changes: 21 additions & 48 deletions modules/topicsFpdModule.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import {logError, logWarn, mergeDeep, isEmpty, safeJSONParse, logInfo, hasDeviceAccess} from '../src/utils.js';
import {isEmpty, logError, logWarn, mergeDeep, safeJSONParse} from '../src/utils.js';
import {getRefererInfo} from '../src/refererDetection.js';
import {submodule} from '../src/hook.js';
import {GreedyPromise} from '../src/utils/promise.js';
import {config} from '../src/config.js';
import {getCoreStorageManager} from '../src/storageManager.js';
import {includes} from '../src/polyfill.js';
import {gdprDataHandler} from '../src/adapterManager.js';
import {isActivityAllowed} from '../src/activities/rules.js';
import {ACTIVITY_ENRICH_UFPD} from '../src/activities/activities.js';
import {activityParams} from '../src/activities/activityParams.js';
import {MODULE_TYPE_BIDDER} from '../src/activities/modules.js';

const MODULE_NAME = 'topicsFpd';
const DEFAULT_EXPIRATION_DAYS = 21;
const TCF_REQUIRED_PURPOSES = ['1', '2', '3', '4'];
let HAS_GDPR_CONSENT = true;
let LOAD_TOPICS_INITIALISE = false;
const HAS_DEVICE_ACCESS = hasDeviceAccess();

export function reset() {
LOAD_TOPICS_INITIALISE = false;
}

const bidderIframeList = {
maxTopicCaller: 2,
Expand Down Expand Up @@ -86,10 +90,14 @@ export function getTopicsData(name, topics, taxonomies = TAXONOMIES) {
);
}

function isTopicsSupported(doc = document) {
return 'browsingTopics' in doc && doc.featurePolicy.allowsFeature('browsing-topics')
}

export function getTopics(doc = document) {
let topics = null;
try {
if ('browsingTopics' in doc && doc.featurePolicy.allowsFeature('browsing-topics')) {
if (isTopicsSupported(doc)) {
topics = GreedyPromise.resolve(doc.browsingTopics());
}
} catch (e) {
Expand Down Expand Up @@ -126,19 +134,16 @@ export function processFpd(config, {global}, {data = topicsData} = {}) {
*/
export function getCachedTopics() {
let cachedTopicData = [];
if (!HAS_GDPR_CONSENT || !HAS_DEVICE_ACCESS) {
return cachedTopicData;
}
const topics = config.getConfig('userSync.topics') || bidderIframeList;
const bidderList = topics.bidders || [];
let storedSegments = new Map(safeJSONParse(coreStorage.getDataFromLocalStorage(topicStorageName)));
storedSegments && storedSegments.forEach((value, cachedBidder) => {
// Check bidder exist in config for cached bidder data and then only retrieve the cached data
let bidderConfigObj = bidderList.find(({bidder}) => cachedBidder == bidder)
if (bidderConfigObj) {
let bidderConfigObj = bidderList.find(({bidder}) => cachedBidder === bidder)
if (bidderConfigObj && isActivityAllowed(ACTIVITY_ENRICH_UFPD, activityParams(MODULE_TYPE_BIDDER, cachedBidder))) {
if (!isCachedDataExpired(value[lastUpdated], bidderConfigObj?.expiry || DEFAULT_EXPIRATION_DAYS)) {
Object.keys(value).forEach((segData) => {
segData != lastUpdated && cachedTopicData.push(value[segData]);
segData !== lastUpdated && cachedTopicData.push(value[segData]);
})
} else {
// delete the specific bidder map from the store and store the updated maps
Expand Down Expand Up @@ -204,55 +209,23 @@ function listenMessagesFromTopicIframe() {
window.addEventListener('message', receiveMessage, false);
}

function checkTCFv2(vendorData, requiredPurposes = TCF_REQUIRED_PURPOSES) {
const {gdprApplies, purpose} = vendorData;
if (!gdprApplies || !purpose) {
return true;
}
return requiredPurposes.map((purposeNo) => {
const purposeConsent = purpose.consents ? purpose.consents[purposeNo] : false;
if (purposeConsent) {
return true;
}
return false;
}).reduce((a, b) => a && b, true);
}

export function hasGDPRConsent() {
// Check for GDPR consent for purpose 1,2,3,4 and return false if consent has not been given
const gdprConsent = gdprDataHandler.getConsentData();
const hasGdpr = (gdprConsent && typeof gdprConsent.gdprApplies === 'boolean' && gdprConsent.gdprApplies) ? 1 : 0;
const gdprConsentString = hasGdpr ? gdprConsent.consentString : '';
if (hasGdpr) {
if ((!gdprConsentString || gdprConsentString === '') || !gdprConsent.vendorData) {
return false;
}
return checkTCFv2(gdprConsent.vendorData);
}
return true;
}

/**
* function to load the iframes of the bidder to load the topics data
*/
function loadTopicsForBidders() {
HAS_GDPR_CONSENT = hasGDPRConsent();
if (!HAS_GDPR_CONSENT || !HAS_DEVICE_ACCESS) {
logInfo('Topics Module : Consent string is required to fetch the topics from third party domains.');
return;
}
export function loadTopicsForBidders(doc = document) {
if (!isTopicsSupported(doc)) return;
const topics = config.getConfig('userSync.topics') || bidderIframeList;
if (topics) {
listenMessagesFromTopicIframe();
const randomBidders = getRandomBidders(topics.bidders || [], topics.maxTopicCaller || 1)
randomBidders && randomBidders.forEach(({ bidder, iframeURL }) => {
if (bidder && iframeURL) {
let ifrm = document.createElement('iframe');
let ifrm = doc.createElement('iframe');
ifrm.name = 'ifrm_'.concat(bidder);
ifrm.src = ''.concat(iframeURL, '?bidder=').concat(bidder);
ifrm.style.display = 'none';
setLoadedIframeURL(new URL(iframeURL).origin);
iframeURL && window.document.documentElement.appendChild(ifrm);
iframeURL && doc.documentElement.appendChild(ifrm);
}
})
} else {
Expand Down
Loading

0 comments on commit bcf080d

Please sign in to comment.