Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 3 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it guaranteed allowsFeature will always be there if browsingTopics is? So no need to safe check here?

}

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