Skip to content

Commit

Permalink
chore: Enable GPP Multi-State Privacy String (MSPS) with U.S. Privacy (
Browse files Browse the repository at this point in the history
…#806)

* Create stub_gpp_ccpa.js

* Added stub_gpp_ccpa

* Added reference

* Added includeGppApi

* Update stub.ts

* Momentarily committing a changeset

* Momentarily log

* Fixing bug

* Update sourcepoint.ts

* Update sourcepoint.ts

* Update sourcepoint.ts

* Updated file name to stub_uspapi_ccpa

* Update early-rocks-destroy.md

* Update for aus and added _gpp

* Update sourcepoint.test.js

* Added GPPData interface

* Create new function to get gpp data

* using getGPPData

* Removing gpp

* Update getConsentState.ts

* Using GPPData

* Updated to minor

* Using tcfv2 in unknown frameworks

* Fixed test

* Update stub.ts

* Update sourcepoint.ts
  • Loading branch information
akinsola-guardian committed Jan 29, 2024
1 parent aad7433 commit 60b7d15
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 19 deletions.
7 changes: 7 additions & 0 deletions .changeset/early-rocks-destroy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@guardian/consent-management-platform': minor
---

- Adding the includeGppApi param to the sourcepoint config for CCPA.
- Updating type to include includeGppApi for the window object.
- Refactoring stub.ts to load both \_\_uspapi and \_\_gpp stub for CCPA but only load \_\_uspapi for AUS.
15 changes: 14 additions & 1 deletion src/sourcepoint.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ describe('Sourcepoint unified', () => {
beforeEach(() => {
window.__tcfapi = undefined;
window.__uspapi = undefined;
window.__gpp = undefined;
});
afterEach(() => {
window._sp_ = undefined;
Expand Down Expand Up @@ -42,11 +43,23 @@ describe('Sourcepoint unified', () => {
expect(window._sp_.config.ccpa).toBeUndefined();
expect(window.__tcfapi).toBeDefined();
expect(window.__uspapi).toBeUndefined();
} else {
expect(window.__gpp).toBeUndefined();
} else if (framework == 'ccpa') {
expect(
window._sp_.config.ccpa.targetingParams.framework,
).toEqual(framework);
expect(window._sp_.config.gdpr).toBeUndefined;
expect(window._sp_.config.ccpa.includeGppApi).toBeTruthy();
expect(window.__uspapi).toBeDefined();
expect(window.__gpp).toBeDefined();
expect(window.__tcfapi).toBeUndefined();
} else if (framework == 'aus') {
expect(
window._sp_.config.ccpa.targetingParams.framework,
).toEqual(framework);
expect(window._sp_.config.gdpr).toBeUndefined;
expect(window._sp_.config.ccpa.includeGppApi).toBeFalsy();
expect(window.__gpp).toBeUndefined();
expect(window.__uspapi).toBeDefined();
expect(window.__tcfapi).toBeUndefined();
}
Expand Down
38 changes: 25 additions & 13 deletions src/sourcepoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,21 +156,33 @@ export const init = (framework: Framework, pubData = {}): void => {

// NOTE - Contrary to the SourcePoint documentation, it's important that we add EITHER gdpr OR ccpa
// to the _sp_ object. wrapperMessagingWithoutDetection.js uses the presence of these keys to attach
// __tcfapi or __uspapi to the window object respectively. If both of these functions appear on the window,
// __tcfapi or __uspapi or _gpp to the window object respectively. If both of these functions appear on the window,
// advertisers seem to assume that __tcfapi is the one to use, breaking CCPA consent.
// https://documentation.sourcepoint.com/implementation/web-implementation/multi-campaign-web-implementation#implementation-code-snippet-overview
if (framework === 'tcfv2') {
window._sp_.config.gdpr = {
targetingParams: {
framework,
},
};
} else {
window._sp_.config.ccpa = {
targetingParams: {
framework,
},
};

switch (framework) {
case 'tcfv2':
window._sp_.config.gdpr = {
targetingParams: {
framework,
},
};
break;
case 'ccpa':
window._sp_.config.ccpa = {
includeGppApi: true,
targetingParams: {
framework,
},
};
break;
case 'aus':
window._sp_.config.ccpa = {
targetingParams: {
framework,
},
};
break;
}

// TODO use libs function loadScript,
Expand Down
17 changes: 14 additions & 3 deletions src/stub.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import { stub_ccpa } from './stub_ccpa';
import { stub_gpp_ccpa } from './stub_gpp_ccpa';
import { stub_tcfv2 } from './stub_tcfv2';
import { stub_uspapi_ccpa } from './stub_uspapi_ccpa';
import type { Framework } from './types';

export const stub = (framework: Framework): void => {
// NOTE - Contrary to the SourcePoint documentation, it's important that we only run the stub file
// for the framework currently in use. The presence of __tcfapi on the window object signals to GPT
// that it should take precedence over __uspapi
// documentation.sourcepoint.com/implementation/web-implementation/multi-campaign-web-implementation#stub-file
if (framework === 'tcfv2') stub_tcfv2();
else stub_ccpa();
switch (framework) {
case 'tcfv2':
stub_tcfv2();
break;
case 'ccpa':
stub_uspapi_ccpa();
stub_gpp_ccpa();
break;
case 'aus':
stub_uspapi_ccpa();
break;
}
};
125 changes: 125 additions & 0 deletions src/stub_gpp_ccpa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/* eslint-disable -- this is third party code */
/* istanbul ignore file */
// Reference : https://docs.sourcepoint.com/hc/en-us/articles/18007731422099-Enable-GPP-Multi-State-Privacy-String-MSPS-with-U-S-Privacy-CCPA-solution
export const stub_gpp_ccpa = () => {
(window.__gpp_addFrame = function (e) {
if (!window.frames[e]) {
if (document.body) {
var t = document.createElement('iframe');
(t.style.cssText = 'display:none'),
(t.name = e),
document.body.appendChild(t);
} else window.setTimeout(window.__gpp_addFrame, 10, e);
}
}),
(window.__gpp_stub = function () {
var e = arguments;
if (
((__gpp.queue = __gpp.queue || []),
(__gpp.events = __gpp.events || []),
!e.length || (1 == e.length && 'queue' == e[0]))
) {
return __gpp.queue;
}
if (1 == e.length && 'events' == e[0]) return __gpp.events;
var t = e[0],
p = e.length > 1 ? e[1] : null,
n = e.length > 2 ? e[2] : null;
if ('ping' === t) {
return {
gppVersion: '1.0',
cmpStatus: 'stub',
cmpDisplayStatus: 'hidden',
supportedAPIs: ['tcfeuv2', 'tcfcav2', 'uspv1'],
cmpId: 31,
};
}
if ('addEventListener' === t) {
'lastId' in __gpp || (__gpp.lastId = 0), __gpp.lastId++;
var a = __gpp.lastId;
return (
__gpp.events.push({ id: a, callback: p, parameter: n }),
{
eventName: 'listenerRegistered',
listenerId: a,
data: !0,
pingData: {
gppVersion: '1.0',
cmpStatus: 'stub',
cmpDisplayStatus: 'hidden',
supportedAPIs: ['tcfeuv2', 'tcfva', 'usnat'],
cmpId: 31,
},
}
);
}
if ('removeEventListener' === t) {
for (var s = !1, i = 0; i < __gpp.events.length; i++) {
if (__gpp.events[i].id == n) {
__gpp.events.splice(i, 1), (s = !0);
break;
}
}
return {
eventName: 'listenerRemoved',
listenerId: n,
data: s,
pingData: {
gppVersion: '1.0',
cmpStatus: 'stub',
cmpDisplayStatus: 'hidden',
supportedAPIs: ['tcfeuv2', 'tcfva', 'usnat'],
cmpId: 31,
},
};
}
return 'getGPPData' === t
? {
sectionId: 3,
gppVersion: 1,
sectionList: [],
applicableSections: [0],
gppString: '',
pingData: {
gppVersion: '1.0',
cmpStatus: 'stub',
cmpDisplayStatus: 'hidden',
supportedAPIs: ['tcfeuv2', 'tcfva', 'usnat'],
cmpId: 31,
},
}
: 'hasSection' === t || 'getSection' === t || 'getField' === t
? null
: void __gpp.queue.push([].slice.apply(e));
}),
(window.__gpp_msghandler = function (e) {
var t = 'string' == typeof e.data;
try {
var p = t ? JSON.parse(e.data) : e.data;
} catch (e) {
p = null;
}
if ('object' == typeof p && null !== p && '__gppCall' in p) {
var n = p.__gppCall;
window.__gpp(
n.command,
function (p, a) {
var s = {
__gppReturn: {
returnValue: p,
success: a,
callId: n.callId,
},
};
e.source.postMessage(t ? JSON.stringify(s) : s, '*');
},
'parameter' in n ? n.parameter : null,
'version' in n ? n.version : 1,
);
}
}),
('__gpp' in window && 'function' == typeof window.__gpp) ||
((window.__gpp = window.__gpp_stub),
window.addEventListener('message', window.__gpp_msghandler, !1),
window.__gpp_addFrame('__gppLocator'));
};
2 changes: 1 addition & 1 deletion src/stub_ccpa.js → src/stub_uspapi_ccpa.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ See the documentation on how to retrieve the latest version:
https://documentation.sourcepoint.com/implementation/web-implementation/multi-campaign-web-implementation#stub-file
*/

export const stub_ccpa = () => {
export const stub_uspapi_ccpa = () => {
(function () {
var e = false;
var c = window;
Expand Down
5 changes: 5 additions & 0 deletions src/types/ccpa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ export interface CCPAData {
version: number;
uspString: string;
}

export interface GPPData {
gppVersion: number;
gppString: string;
}
7 changes: 6 additions & 1 deletion src/types/window.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Property } from '../lib/property';
import type { EndPoint } from '../lib/sourcepointConfig';
import type { onConsent } from '../onConsent';
import type { onConsentChange } from '../onConsentChange';
import type { CCPAData } from './ccpa';
import type { CCPAData, GPPData } from './ccpa';
import type { TCData } from './tcfv2/TCData';
import type { CMP, Framework, PubData } from '.';

Expand Down Expand Up @@ -35,6 +35,7 @@ declare global {
framework: Framework;
};
ccpa?: {
includeGppApi?: boolean;
targetingParams?: {
framework: Framework;
};
Expand Down Expand Up @@ -97,5 +98,9 @@ declare global {
callback: (tcData: TCData, success: boolean) => void,
vendorIDs?: number[],
) => void;
__gpp?: (
command: string,
callback: (gppData: GPPData, success: boolean) => void,
) => void;
}
}

1 comment on commit 60b7d15

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

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

Coverage report

St.
Category Percentage Covered / Total
🟢 Statements 92.7% 254/274
🟢 Branches 83.48% 96/115
🟢 Functions 90% 63/70
🟢 Lines 92.48% 246/266

Test suite run success

328 tests passing in 16 suites.

Report generated by 🧪jest coverage report action from 60b7d15

Please sign in to comment.