Skip to content

Commit

Permalink
Apply GPC to cookie cache as well
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuaostrom-cb committed May 6, 2024
1 parent 71ec6d4 commit 1123645
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 16 deletions.
12 changes: 7 additions & 5 deletions packages/cookie-manager/src/CookieContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import {
TrackerType,
TrackingPreference,
} from './types';
import applyGpcToAdPref from './utils/applyGpcToAdPref';
import applyGpcToCookiePref from './utils/applyGpcToCookiePref';
import { applyGpcToAdPref } from './utils/applyGpcToAdPref';
import { applyGpcToCookiePref } from './utils/applyGpcToCookiePref';
import getAllCookies, { areRecordsEqual } from './utils/getAllCookies';
import getDefaultTrackingPreference from './utils/getDefaultTrackingPreference';
import { getDomainWithoutSubdomain, getHostname } from './utils/getDomain';
Expand All @@ -41,7 +41,7 @@ export const CookieProvider = ({ children }: Props) => {
const { config, region, shadowMode, log, onPreferenceChange } = useTrackingManager();

const POLL_INTERVAL = 500;
const [cookieValues, setCookieValues] = useState(() => getAllCookies());
const [cookieValues, setCookieValues] = useState(() => getAllCookies(region));
let priorCookieValue: Record<string, any>;
let trackingPreference: TrackingPreference;
let adTrackingPreference: AdTrackingPreference;
Expand All @@ -64,13 +64,16 @@ export const CookieProvider = ({ children }: Props) => {
useEffect(() => {
if (typeof window !== 'undefined') {
const checkCookies = () => {
const currentCookie = getAllCookies();
const currentCookie = getAllCookies(region);

if (priorCookieValue == undefined || !areRecordsEqual(priorCookieValue, currentCookie)) {
priorCookieValue = currentCookie;
setCookieValues(currentCookie);

// Grab out prefences (they wil have GPC applied if present)
trackingPreference = getTrackingPreference(currentCookie, region, config);
adTrackingPreference = getAdTrackingPreference(currentCookie, region);

setGTMVariables(trackingPreference, adTrackingPreference);
const cookiesToRemove: Array<string> = [];
Object.keys(currentCookie).forEach((c) => {
Expand Down Expand Up @@ -219,7 +222,6 @@ const getAdTrackingPreference = (

// Example: adPreference { value: 'false' }
const adPreference = adTrackingPreference || adTrackingDefault;

return applyGpcToAdPref(region, adPreference);
};

Expand Down
2 changes: 1 addition & 1 deletion packages/cookie-manager/src/utils/applyGpcToAdPref.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Region } from '../types';
import applyGpcToAdPref from './applyGpcToAdPref';
import { applyGpcToAdPref } from './applyGpcToAdPref';

describe('applyGpcToAdPref', () => {
it('removes targeting when GPC is ON in non-EU', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/cookie-manager/src/utils/applyGpcToAdPref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ const applyGpcToAdPref = (
return pref;
};

export default applyGpcToAdPref;
export { applyGpcToAdPref };
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Region, TrackingCategory } from '../types';
import applyGpcToCookiePref from './applyGpcToCookiePref';
import { applyGpcToCookiePref } from './applyGpcToCookiePref';

describe('applyGpcToCookiePref', () => {
it('removes targeting when GPC is ON in non-EU', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/cookie-manager/src/utils/applyGpcToCookiePref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ const applyGpcToCookiePref = (preference: TrackingPreference): TrackingPreferenc
return pref;
};

export default applyGpcToCookiePref;
export { applyGpcToCookiePref };
38 changes: 35 additions & 3 deletions packages/cookie-manager/src/utils/getAllCookies.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Cookies from 'js-cookie';

import getAllCookies from './getAllCookies';
import getAllCookies, { Region } from './getAllCookies';
export { Region } from '../types';

jest.mock('js-cookie', () => ({
__esModule: true,
Expand All @@ -16,17 +17,48 @@ describe('getAllCookies', () => {
const mockGet = Cookies.get as jest.MockedFunction<typeof Cookies.get>;
const value = {
region: 'DEFAULT',
consent: ['necessary', 'performance'],
consent: ['necessary', 'performance', 'targeting'],
};
const cookies = {
cm_default_preferences: JSON.stringify(value),
advertising_sharing_allowed: JSON.stringify({ value: true }),
some_cookie: 'iamastring',
another_cookie: '5',
array_cookie: JSON.stringify(['item1', 'item2']),
};
(navigator as any).globalPrivacyControl = false;

mockGet.mockImplementation(jest.fn(() => cookies));
expect(getAllCookies({})).toEqual({

expect(getAllCookies(Region.DEFAULT, {})).toEqual({
cm_default_preferences: value,
advertising_sharing_allowed: { value: true },
some_cookie: 'iamastring',
another_cookie: 5,
array_cookie: ['item1', 'item2'],
});
});

it('applies GCP to cookie values', () => {
const mockGet = Cookies.get as jest.MockedFunction<typeof Cookies.get>;
const value = {
region: 'DEFAULT',
consent: ['necessary', 'performance', 'targeting'],
};
const cookies = {
cm_default_preferences: JSON.stringify(value),
advertising_sharing_allowed: JSON.stringify({ value: true }),
some_cookie: 'iamastring',
another_cookie: '5',
array_cookie: JSON.stringify(['item1', 'item2']),
};
(navigator as any).globalPrivacyControl = true;

mockGet.mockImplementation(jest.fn(() => cookies));

expect(getAllCookies(Region.DEFAULT, {})).toEqual({
cm_default_preferences: { consent: ['necessary', 'performance'], region: 'DEFAULT' },
advertising_sharing_allowed: { value: false },
some_cookie: 'iamastring',
another_cookie: 5,
array_cookie: ['item1', 'item2'],
Expand Down
34 changes: 30 additions & 4 deletions packages/cookie-manager/src/utils/getAllCookies.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import Cookies from 'js-cookie';

export const deserializeCookies = (cookies: Record<string, string>) => {
export { Region } from '../types';

import {
ADVERTISING_SHARING_ALLOWED,
DEFAULT_CONSENT_PREFERENCES_COOKIE,
EU_CONSENT_PREFERENCES_COOKIE,
} from '../constants';
import { Region } from '../types';
import { applyGpcToAdPref } from './applyGpcToAdPref';
import { applyGpcToCookiePref } from './applyGpcToCookiePref';

export const deserializeCookies = (region: Region, cookies: Record<string, string>) => {
const parsedCookies: Record<string, any> = {};

Object.keys(cookies).forEach((c) => {
Expand All @@ -9,15 +20,30 @@ export const deserializeCookies = (cookies: Record<string, string>) => {
} catch (e) {
parsedCookies[c] = cookies[c];
}
parsedCookies[c] = filterCookieValue(region, c, parsedCookies[c]);
});
return parsedCookies;
};

export default function getAllCookies(initialCookies?: Record<string, string>) {
export default function getAllCookies(region: Region, initialCookies?: Record<string, string>) {
if (typeof window === 'undefined' && initialCookies) {
return deserializeCookies(initialCookies);
return deserializeCookies(region, initialCookies);
}
return deserializeCookies(region, Cookies.get() || {});
}

// Apply in in memory filters to the cookie values. Currently we are just apply
// Global Privacy Control (GPC) logic to ensure we are honoring GPC
function filterCookieValue(region: Region, cookieName: string, cookieValue: any) {
if (cookieName == ADVERTISING_SHARING_ALLOWED) {
cookieValue = applyGpcToAdPref(region, cookieValue);
} else if (
(region == Region.DEFAULT && cookieName == DEFAULT_CONSENT_PREFERENCES_COOKIE) ||
(region == Region.EU && cookieName == EU_CONSENT_PREFERENCES_COOKIE)
) {
cookieValue = applyGpcToCookiePref(cookieValue);
}
return deserializeCookies(Cookies.get() || {});
return cookieValue;
}

export function areRecordsEqual(
Expand Down

0 comments on commit 1123645

Please sign in to comment.