From 46ceadde0c396fcab590a6ad65c0d6e8b51a4d65 Mon Sep 17 00:00:00 2001 From: Allison King Date: Tue, 10 Oct 2023 15:38:20 -0400 Subject: [PATCH 1/4] Narrow vendors disclosed to only the vendors we show in the UI --- clients/fides-js/src/lib/tcf.ts | 70 ++++++++----------- .../cypress/e2e/consent-banner-tcf.cy.ts | 14 ++++ 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/clients/fides-js/src/lib/tcf.ts b/clients/fides-js/src/lib/tcf.ts index 0796ccfbc0..350e8ffcb0 100644 --- a/clients/fides-js/src/lib/tcf.ts +++ b/clients/fides-js/src/lib/tcf.ts @@ -39,17 +39,22 @@ export const generateTcString = async ({ tcModel.cmpVersion = CMP_VERSION; tcModel.consentScreen = 1; // todo- On which 'screen' consent was captured; this is a CMP proprietary number encoded into the TC string + // Narrow the GVL to say we've only showed these vendors provided by our experience + const vendorIds = [ + ...(experience.tcf_vendor_consents?.map((v) => +v.id) || []), + ...(experience.tcf_vendor_legitimate_interests?.map((v) => +v.id) || []), + ]; + tcModel.gvl.narrowVendorsTo(vendorIds); + if (tcStringPreferences) { - if ( - tcStringPreferences.vendorsConsent && - tcStringPreferences.vendorsConsent.length > 0 - ) { - tcStringPreferences.vendorsConsent.forEach((vendorId) => { - if (vendorIsGvl({ id: vendorId }, experience.gvl)) { - tcModel.vendorConsents.set(+vendorId); - } - }); - tcStringPreferences.vendorsLegint.forEach((vendorId) => { + // Set vendors on tcModel + tcStringPreferences.vendorsConsent.forEach((vendorId) => { + if (vendorIsGvl({ id: vendorId }, experience.gvl)) { + tcModel.vendorConsents.set(+vendorId); + } + }); + tcStringPreferences.vendorsLegint.forEach((vendorId) => { + if (vendorIsGvl({ id: vendorId }, experience.gvl)) { const thisVendor = experience.tcf_vendor_legitimate_interests?.filter( (v) => v.id === vendorId )[0]; @@ -70,39 +75,24 @@ export const generateTcString = async ({ tcModel.vendorLegitimateInterests.set(+vendorId); } } - }); - } + } + }); - // Set purpose consent on tcModel - if ( - tcStringPreferences.purposesConsent && - tcStringPreferences.purposesConsent.length > 0 - ) { - tcStringPreferences.purposesConsent.forEach((purposeId) => { - tcModel.purposeConsents.set(+purposeId); - }); - } - if ( - tcStringPreferences.purposesLegint && - tcStringPreferences.purposesLegint.length > 0 - ) { - tcStringPreferences.purposesLegint.forEach((purposeId) => { - const id = +purposeId; - if (!FORBIDDEN_LEGITIMATE_INTEREST_PURPOSE_IDS.includes(id)) { - tcModel.purposeLegitimateInterests.set(id); - } - }); - } + // Set purposes on tcModel + tcStringPreferences.purposesConsent.forEach((purposeId) => { + tcModel.purposeConsents.set(+purposeId); + }); + tcStringPreferences.purposesLegint.forEach((purposeId) => { + const id = +purposeId; + if (!FORBIDDEN_LEGITIMATE_INTEREST_PURPOSE_IDS.includes(id)) { + tcModel.purposeLegitimateInterests.set(id); + } + }); // Set special feature opt-ins on tcModel - if ( - tcStringPreferences.specialFeatures && - tcStringPreferences.specialFeatures.length > 0 - ) { - tcStringPreferences.specialFeatures.forEach((id) => { - tcModel.specialFeatureOptins.set(+id); - }); - } + tcStringPreferences.specialFeatures.forEach((id) => { + tcModel.specialFeatureOptins.set(+id); + }); // note that we cannot set consent for special purposes nor features because the IAB policy states // the user is not given choice by a CMP. diff --git a/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts b/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts index 3ede5896f5..2cf5e05560 100644 --- a/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts +++ b/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts @@ -384,6 +384,7 @@ describe("Fides-js TCF", () => { }); describe("saving preferences", () => { + const expectedVendorsDisclosed = "IABE"; it("can opt in to all", () => { cy.getCookie(CONSENT_COOKIE_NAME).should("not.exist"); cy.getByTestId("consent-modal").within(() => { @@ -449,6 +450,11 @@ describe("Fides-js TCF", () => { ) .property(`${SYSTEM_1.id}`) .is.eql(true); + + // Confirm vendors_disclosed section + expect( + cookieKeyConsent.tc_string?.endsWith(`.${expectedVendorsDisclosed}`) + ).to.eql(true); }); }); @@ -516,6 +522,10 @@ describe("Fides-js TCF", () => { ) .property(`${SYSTEM_1.id}`) .is.eql(false); + // Confirm vendors_disclosed section + expect( + cookieKeyConsent.tc_string?.endsWith(`.${expectedVendorsDisclosed}`) + ).to.eql(true); }); }); @@ -590,6 +600,10 @@ describe("Fides-js TCF", () => { expect( cookieKeyConsent.tcf_consent.system_consent_preferences ).to.eql({}); + // Confirm vendors_disclosed section + expect( + cookieKeyConsent.tc_string?.endsWith(`.${expectedVendorsDisclosed}`) + ).to.eql(true); }); }); }); From bde1fee2f313ff9241814ccbf99f30a71ea71eac Mon Sep 17 00:00:00 2001 From: Allison King Date: Tue, 10 Oct 2023 16:09:38 -0400 Subject: [PATCH 2/4] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5b5e529c7..d671fd7d83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ The types of changes are: - Added our CMP ID [#4233](https://github.com/ethyca/fides/pull/4233) - Allow Admin UI users to turn on Configure Consent flag [#4246](https://github.com/ethyca/fides/pull/4246) - Styling improvements for the fides.js consent banners and modals [#4222](https://github.com/ethyca/fides/pull/4222) +- Vendors disclosed string is now narrowed to only the vendors shown in the UI, not the whole GVL [#4250](https://github.com/ethyca/fides/pull/4250) ### Fixed - TCF overlay can initialize its consent preferences from a cookie [#4124](https://github.com/ethyca/fides/pull/4124) From 133f2131c7ddfd4a217c585084b456b1707f73cc Mon Sep 17 00:00:00 2001 From: Allison King Date: Fri, 13 Oct 2023 12:11:42 -0400 Subject: [PATCH 3/4] Filter gvl vendors by if they are gvl --- clients/fides-js/src/lib/tcf.ts | 13 ++++++------ clients/fides-js/src/lib/tcf/vendors.ts | 21 +++++++++++++++++++ .../cypress/e2e/consent-banner-tcf.cy.ts | 8 +++---- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/clients/fides-js/src/lib/tcf.ts b/clients/fides-js/src/lib/tcf.ts index 29268bfe44..d1acb8613a 100644 --- a/clients/fides-js/src/lib/tcf.ts +++ b/clients/fides-js/src/lib/tcf.ts @@ -10,7 +10,12 @@ import { TCModel, TCString, GVL } from "@iabtechlabtcf/core"; import { makeStub } from "./tcf/stub"; import { EnabledIds } from "./tcf/types"; -import { decodeVendorId, vendorIsAc, vendorGvlEntry } from "./tcf/vendors"; +import { + decodeVendorId, + vendorIsAc, + vendorGvlEntry, + uniqueGvlVendorIds, +} from "./tcf/vendors"; import { PrivacyExperience } from "./consent-types"; import { FIDES_SEPARATOR } from "./tcf/constants"; import { FidesEvent } from "./events"; @@ -70,11 +75,7 @@ export const generateTcString = async ({ tcModel.consentScreen = 1; // todo- On which 'screen' consent was captured; this is a CMP proprietary number encoded into the TC string // Narrow the GVL to say we've only showed these vendors provided by our experience - const vendorIds = [ - ...(experience.tcf_vendor_consents?.map((v) => +v.id) || []), - ...(experience.tcf_vendor_legitimate_interests?.map((v) => +v.id) || []), - ]; - tcModel.gvl.narrowVendorsTo(vendorIds); + tcModel.gvl.narrowVendorsTo(uniqueGvlVendorIds(experience)); if (tcStringPreferences) { // Set vendors on tcModel diff --git a/clients/fides-js/src/lib/tcf/vendors.ts b/clients/fides-js/src/lib/tcf/vendors.ts index 531ee3573d..0c03fdd61a 100644 --- a/clients/fides-js/src/lib/tcf/vendors.ts +++ b/clients/fides-js/src/lib/tcf/vendors.ts @@ -50,6 +50,27 @@ export const vendorGvlEntry = ( export const vendorIsAc = (vendorId: TCFVendorRelationships["id"]) => decodeVendorId(vendorId).source === VendorSources.AC; +export const uniqueGvlVendorIds = (experience: PrivacyExperience): number[] => { + const { + tcf_vendor_consents: vendorConsents = [], + tcf_vendor_legitimate_interests: vendorLegints = [], + } = experience; + + // List of i.e. [gvl.2, ac.3, gvl.4] + const universalIds = Array.from( + new Set([ + ...vendorConsents.map((v) => v.id), + ...vendorLegints.map((v) => v.id), + ]) + ); + // Filter to just i.e. [gvl.2, gvl.4] + const gvlIds = universalIds.filter((uid) => + vendorGvlEntry(uid, experience.gvl) + ); + // Return [2,4] as numbers + return gvlIds.map((uid) => +decodeVendorId(uid).id); +}; + const transformVendorDataToVendorRecords = ({ consents, legints, diff --git a/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts b/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts index 4858ddd02f..52b0af3610 100644 --- a/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts +++ b/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts @@ -422,7 +422,7 @@ describe("Fides-js TCF", () => { }); describe("saving preferences", () => { - const expectedVendorsDisclosed = "IABE"; + const expectedEndOfFidesString = ".IABE,1~"; it("can opt in to all", () => { cy.getCookie(CONSENT_COOKIE_NAME).should("not.exist"); cy.getByTestId("consent-modal").within(() => { @@ -491,7 +491,7 @@ describe("Fides-js TCF", () => { // Confirm vendors_disclosed section expect( - cookieKeyConsent.tc_string?.endsWith(`.${expectedVendorsDisclosed}`) + cookieKeyConsent.fides_tc_string?.endsWith(expectedEndOfFidesString) ).to.eql(true); }); }); @@ -562,7 +562,7 @@ describe("Fides-js TCF", () => { .is.eql(false); // Confirm vendors_disclosed section expect( - cookieKeyConsent.tc_string?.endsWith(`.${expectedVendorsDisclosed}`) + cookieKeyConsent.fides_tc_string?.endsWith(expectedEndOfFidesString) ).to.eql(true); }); }); @@ -640,7 +640,7 @@ describe("Fides-js TCF", () => { ).to.eql({}); // Confirm vendors_disclosed section expect( - cookieKeyConsent.tc_string?.endsWith(`.${expectedVendorsDisclosed}`) + cookieKeyConsent.fides_tc_string?.endsWith(expectedEndOfFidesString) ).to.eql(true); }); }); From ba7f2b6fd0c47adda253109b431ddb4ab117e54b Mon Sep 17 00:00:00 2001 From: Allison King Date: Fri, 13 Oct 2023 14:07:15 -0400 Subject: [PATCH 4/4] Update changelog --- CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52f8e9b0a6..b422f0948c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,9 +17,6 @@ The types of changes are: ## [Unreleased](https://github.com/ethyca/fides/compare/2.22.0...main) -### Changed -- Vendors disclosed string is now narrowed to only the vendors shown in the UI, not the whole GVL [#4250](https://github.com/ethyca/fides/pull/4250) - ## [2.22.0](https://github.com/ethyca/fides/compare/2.21.0...2.22.0) ### Added @@ -42,6 +39,7 @@ The types of changes are: - Allow Admin UI users to turn on Configure Consent flag [#4246](https://github.com/ethyca/fides/pull/4246) - Styling improvements for the fides.js consent banners and modals [#4222](https://github.com/ethyca/fides/pull/4222) - Changed vendor form on configuring consent page to use two-part selection for consent uses [#4251](https://github.com/ethyca/fides/pull/4251) +- Vendors disclosed string is now narrowed to only the vendors shown in the UI, not the whole GVL [#4250](https://github.com/ethyca/fides/pull/4250) ### Fixed - TCF overlay can initialize its consent preferences from a cookie [#4124](https://github.com/ethyca/fides/pull/4124) @@ -52,6 +50,7 @@ The types of changes are: - Updating the unflatten_dict util to accept flattened dict values [#4200](https://github.com/ethyca/fides/pull/4200) - Minor CSS styling fixes for the consent modal [#4252](https://github.com/ethyca/fides/pull/4252) - Additional styling fixes for issues caused by a CSS reset [#4268](https://github.com/ethyca/fides/pull/4268) +- Bug where vendor legitimate interests would not be set unless vendor consents were first set [#4250](https://github.com/ethyca/fides/pull/4250) ## [2.21.0](https://github.com/ethyca/fides/compare/2.20.2...2.21.0)