Skip to content

Commit

Permalink
ID5 Adapter: protect against local storage writing without consent (#…
Browse files Browse the repository at this point in the history
…9587)

* id-6129: don't write to local storage without consent

* id-6129: clean up

* id-6129: clean up

* id-6129: refactor

* id-6129: use deepAccess

* id-6129: unit tests

* id-6129: logging

* id-6129: improve log
  • Loading branch information
kzhang-id5 authored Feb 28, 2023
1 parent 18db442 commit 74a1ffc
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 2 deletions.
25 changes: 25 additions & 0 deletions modules/id5IdSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ export const id5IdSubmodule = {
return undefined;
}

if (!hasWriteConsentToLocalStorage(consentData)) {
logInfo(LOG_PREFIX + 'Skipping ID5 local storage write because no consent given.')
return undefined;
}

const resp = function (cbFunction) {
new IdFetchFlow(submoduleConfig, consentData, cacheIdObj, uspDataHandler.getConsentData()).execute()
.then(response => {
Expand Down Expand Up @@ -140,6 +145,11 @@ export const id5IdSubmodule = {
extendId(config, consentData, cacheIdObj) {
hasRequiredConfig(config);

if (!hasWriteConsentToLocalStorage(consentData)) {
logInfo(LOG_PREFIX + 'No consent given for ID5 local storage writing, skipping nb increment.')
return cacheIdObj;
}

const partnerId = (config && config.params && config.params.partner) || 0;
incrementNb(partnerId);

Expand Down Expand Up @@ -376,4 +386,19 @@ export function storeInLocalStorage(key, value, expDays) {
storage.setDataInLocalStorage(`${key}`, value);
}

/**
* Check to see if we can write to local storage based on purpose consent 1, and that we have vendor consent (ID5=131)
* @param {ConsentData} consentData
* @returns {boolean}
*/
function hasWriteConsentToLocalStorage(consentData) {
const hasGdpr = consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies;
const localstorageConsent = deepAccess(consentData, `vendorData.purpose.consents.1`)
const id5VendorConsent = deepAccess(consentData, `vendorData.vendor.consents.${GVLID.toString()}`)
if (hasGdpr && (!localstorageConsent || !id5VendorConsent)) {
return false;
}
return true;
}

submodule('userId', id5IdSubmodule);
49 changes: 47 additions & 2 deletions test/spec/modules/id5IdSystem_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ describe('ID5 ID System', function () {
'signature': ID5_RESPONSE_SIGNATURE,
'link_type': ID5_RESPONSE_LINK_TYPE
};
const ALLOWED_ID5_VENDOR_DATA = {
purpose: {
consents: {
1: true
}
},
vendor: {
consents: {
131: true
}
}
}

function getId5FetchConfig(storageName = ID5_STORAGE_NAME, storageType = 'html5') {
return {
Expand Down Expand Up @@ -205,6 +217,37 @@ describe('ID5 ID System', function () {
});
});

describe('Check for valid consent', function() {
const dataConsentVals = [
[{purpose: {consents: {1: false}}}, {vendor: {consents: {131: true}}}, ' no purpose consent'],
[{purpose: {consents: {1: true}}}, {vendor: {consents: {131: false}}}, ' no vendor consent'],
[{purpose: {consents: {1: false}}}, {vendor: {consents: {131: false}}}, ' no purpose and vendor consent'],
[{purpose: {consents: undefined}}, {vendor: {consents: {131: true}}}, ' undefined purpose consent'],
[{purpose: {consents: {1: false}}}, {vendor: {consents: undefined}}], ' undefined vendor consent',
[undefined, {vendor: {consents: {131: true}}}, ' undefined purpose'],
[{purpose: {consents: {1: true}}}, {vendor: undefined}, ' undefined vendor'],
[{purpose: {consents: {1: true}}}, {vendor: {consents: {31: true}}}, ' incorrect vendor consent']
];

dataConsentVals.forEach(function([purposeConsent, vendorConsent, caseName]) {
it('should fail with invalid consent because of ' + caseName, function() {
let dataConsent = {
gdprApplies: true,
consentString: 'consentString',
vendorData: {
purposeConsent, vendorConsent
}
}
expect(id5IdSubmodule.getId(config)).is.eq(undefined);
expect(id5IdSubmodule.getId(config, dataConsent)).is.eq(undefined);

let cacheIdObject = 'cacheIdObject';
expect(id5IdSubmodule.extendId(config)).is.eq(undefined);
expect(id5IdSubmodule.extendId(config, dataConsent, cacheIdObject)).is.eq(cacheIdObject);
});
});
});

describe('Xhr Requests from getId()', function () {
const responseHeader = {'Content-Type': 'application/json'};

Expand Down Expand Up @@ -248,7 +291,8 @@ describe('ID5 ID System', function () {
let xhrServerMock = new XhrServerMock(sinon.createFakeServer())
let consentData = {
gdprApplies: true,
consentString: 'consentString'
consentString: 'consentString',
vendorData: ALLOWED_ID5_VENDOR_DATA
}

let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined);
Expand Down Expand Up @@ -297,7 +341,8 @@ describe('ID5 ID System', function () {
let xhrServerMock = new XhrServerMock(sinon.createFakeServer())
let consentData = {
gdprApplies: true,
consentString: 'consentString'
consentString: 'consentString',
vendorData: ALLOWED_ID5_VENDOR_DATA
}

let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined);
Expand Down

0 comments on commit 74a1ffc

Please sign in to comment.