Skip to content

Commit bff1f41

Browse files
authored
Criteo Id Module: ensure all kind of privacy strings are sent to backend (#9845)
Also adding missing gdpr applies flag
1 parent d0bb0f5 commit bff1f41

File tree

2 files changed

+126
-23
lines changed

2 files changed

+126
-23
lines changed

modules/criteoIdSystem.js

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ import { timestamp, parseUrl, triggerPixel, logError } from '../src/utils.js';
99
import { ajax } from '../src/ajax.js';
1010
import { getRefererInfo } from '../src/refererDetection.js';
1111
import { submodule } from '../src/hook.js';
12-
import {getStorageManager} from '../src/storageManager.js';
13-
import {MODULE_TYPE_UID} from '../src/activities/modules.js';
12+
import { getStorageManager } from '../src/storageManager.js';
13+
import { MODULE_TYPE_UID } from '../src/activities/modules.js';
14+
import { gdprDataHandler, uspDataHandler, gppDataHandler } from '../src/adapterManager.js';
1415

1516
const gvlid = 91;
1617
const bidderCode = 'criteo';
17-
export const storage = getStorageManager({moduleType: MODULE_TYPE_UID, moduleName: bidderCode});
18+
export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: bidderCode });
1819

1920
const bididStorageKey = 'cto_bidid';
2021
const bundleStorageKey = 'cto_bundle';
@@ -77,17 +78,33 @@ function getCriteoDataFromAllStorages() {
7778
}
7879
}
7980

80-
function buildCriteoUsersyncUrl(topUrl, domain, bundle, dnaBundle, areCookiesWriteable, isLocalStorageWritable, isPublishertagPresent, gdprString) {
81-
const url = 'https://gum.criteo.com/sid/json?origin=prebid' +
81+
function buildCriteoUsersyncUrl(topUrl, domain, bundle, dnaBundle, areCookiesWriteable, isLocalStorageWritable, isPublishertagPresent) {
82+
let url = 'https://gum.criteo.com/sid/json?origin=prebid' +
8283
`${topUrl ? '&topUrl=' + encodeURIComponent(topUrl) : ''}` +
8384
`${domain ? '&domain=' + encodeURIComponent(domain) : ''}` +
8485
`${bundle ? '&bundle=' + encodeURIComponent(bundle) : ''}` +
8586
`${dnaBundle ? '&info=' + encodeURIComponent(dnaBundle) : ''}` +
86-
`${gdprString ? '&gdprString=' + encodeURIComponent(gdprString) : ''}` +
8787
`${areCookiesWriteable ? '&cw=1' : ''}` +
8888
`${isPublishertagPresent ? '&pbt=1' : ''}` +
8989
`${isLocalStorageWritable ? '&lsw=1' : ''}`;
9090

91+
const usPrivacyString = uspDataHandler.getConsentData();
92+
if (usPrivacyString) {
93+
url = url + `&us_privacy=${encodeURIComponent(usPrivacyString)}`;
94+
}
95+
96+
const gdprConsent = gdprDataHandler.getConsentData()
97+
if (gdprConsent) {
98+
url = url + `${gdprConsent.consentString ? '&gdprString=' + encodeURIComponent(gdprConsent.consentString) : ''}`;
99+
url = url + `&gdpr=${gdprConsent.gdprApplies === true ? 1 : 0}`;
100+
}
101+
102+
const gppConsent = gppDataHandler.getConsentData();
103+
if (gppConsent) {
104+
url = url + `${gppConsent.gppString ? '&gpp=' + encodeURIComponent(gppConsent.gppString) : ''}`;
105+
url = url + `${gppConsent.applicableSections ? '&gpp_sid=' + encodeURIComponent(gppConsent.applicableSections) : ''}`;
106+
}
107+
91108
return url;
92109
}
93110

@@ -116,7 +133,7 @@ function callSyncPixel(domain, pixel) {
116133
}
117134
}
118135

119-
function callCriteoUserSync(parsedCriteoData, gdprString, callback) {
136+
function callCriteoUserSync(parsedCriteoData, callback) {
120137
const cw = storage.cookiesAreEnabled();
121138
const lsw = storage.localStorageIsEnabled();
122139
const topUrl = extractProtocolHost(getRefererInfo().page);
@@ -131,8 +148,7 @@ function callCriteoUserSync(parsedCriteoData, gdprString, callback) {
131148
parsedCriteoData.dnaBundle,
132149
cw,
133150
lsw,
134-
isPublishertagPresent,
135-
gdprString
151+
isPublishertagPresent
136152
);
137153

138154
const callbacks = {
@@ -191,13 +207,10 @@ export const criteoIdSubmodule = {
191207
* @param {ConsentData} [consentData]
192208
* @returns {{id: {criteoId: string} | undefined}}}
193209
*/
194-
getId(config, consentData) {
195-
const hasGdprData = consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies;
196-
const gdprConsentString = hasGdprData ? consentData.consentString : undefined;
197-
210+
getId() {
198211
let localData = getCriteoDataFromAllStorages();
199212

200-
const result = (callback) => callCriteoUserSync(localData, gdprConsentString, callback);
213+
const result = (callback) => callCriteoUserSync(localData, callback);
201214

202215
return {
203216
id: localData.bidId ? { criteoId: localData.bidId } : undefined,

test/spec/modules/criteoIdSystem_spec.js

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { criteoIdSubmodule, storage } from 'modules/criteoIdSystem.js';
22
import * as utils from 'src/utils.js';
3+
import { gdprDataHandler, uspDataHandler, gppDataHandler } from '../../../src/adapterManager.js';
34
import { server } from '../../mocks/xhr';
45

56
const pastDateString = new Date(0).toString()
@@ -17,6 +18,9 @@ describe('CriteoId module', function () {
1718
let timeStampStub;
1819
let parseUrlStub;
1920
let triggerPixelStub;
21+
let gdprConsentDataStub;
22+
let uspConsentDataStub;
23+
let gppConsentDataStub;
2024

2125
beforeEach(function (done) {
2226
getCookieStub = sinon.stub(storage, 'getCookie');
@@ -27,6 +31,9 @@ describe('CriteoId module', function () {
2731
timeStampStub = sinon.stub(utils, 'timestamp').returns(nowTimestamp);
2832
parseUrlStub = sinon.stub(utils, 'parseUrl').returns({ protocol: 'https', hostname: 'testdev.com' })
2933
triggerPixelStub = sinon.stub(utils, 'triggerPixel');
34+
gdprConsentDataStub = sinon.stub(gdprDataHandler, 'getConsentData');
35+
uspConsentDataStub = sinon.stub(uspDataHandler, 'getConsentData');
36+
gppConsentDataStub = sinon.stub(gppDataHandler, 'getConsentData');
3037
done();
3138
});
3239

@@ -39,6 +46,9 @@ describe('CriteoId module', function () {
3946
timeStampStub.restore();
4047
triggerPixelStub.restore();
4148
parseUrlStub.restore();
49+
gdprConsentDataStub.restore();
50+
uspConsentDataStub.restore();
51+
gppConsentDataStub.restore();
4252
});
4353

4454
const storageTestCases = [
@@ -136,11 +146,11 @@ describe('CriteoId module', function () {
136146
}));
137147

138148
const gdprConsentTestCases = [
139-
{ consentData: { gdprApplies: true, consentString: 'expectedConsentString' }, expected: 'expectedConsentString' },
140-
{ consentData: { gdprApplies: false, consentString: 'expectedConsentString' }, expected: undefined },
141-
{ consentData: { gdprApplies: true, consentString: undefined }, expected: undefined },
142-
{ consentData: { gdprApplies: 'oui', consentString: 'expectedConsentString' }, expected: undefined },
143-
{ consentData: undefined, expected: undefined }
149+
{ consentData: { gdprApplies: true, consentString: 'expectedConsentString' }, expectedGdprConsent: 'expectedConsentString', expectedGdpr: '1' },
150+
{ consentData: { gdprApplies: false, consentString: 'expectedConsentString' }, expectedGdprConsent: 'expectedConsentString', expectedGdpr: '0' },
151+
{ consentData: { gdprApplies: true, consentString: undefined }, expectedGdprConsent: undefined, expectedGdpr: '1' },
152+
{ consentData: { gdprApplies: 'oui', consentString: 'expectedConsentString' }, expectedGdprConsent: 'expectedConsentString', expectedGdpr: '0' },
153+
{ consentData: undefined, expectedGdprConsent: undefined, expectedGdpr: undefined }
144154
];
145155

146156
it('should call sync pixels if request by backend', function () {
@@ -225,14 +235,94 @@ describe('CriteoId module', function () {
225235

226236
gdprConsentTestCases.forEach(testCase => it('should call user sync url with the gdprConsent', function () {
227237
let callBackSpy = sinon.spy();
228-
let result = criteoIdSubmodule.getId(undefined, testCase.consentData);
238+
239+
gdprConsentDataStub.returns(testCase.consentData);
240+
241+
let result = criteoIdSubmodule.getId(undefined);
242+
result.callback(callBackSpy);
243+
244+
let request = server.requests[0];
245+
246+
if (testCase.expectedGdprConsent) {
247+
expect(request.url).to.have.string(`gdprString=${testCase.expectedGdprConsent}`);
248+
} else {
249+
expect(request.url).to.not.have.string('gdprString=');
250+
}
251+
252+
if (testCase.expectedGdpr) {
253+
expect(request.url).to.have.string(`gdpr=${testCase.expectedGdpr}`);
254+
} else {
255+
expect(request.url).to.not.have.string('gdpr=');
256+
}
257+
258+
request.respond(
259+
200,
260+
{ 'Content-Type': 'application/json' },
261+
JSON.stringify({})
262+
);
263+
264+
expect(callBackSpy.calledOnce).to.be.true;
265+
}));
266+
267+
[undefined, 'abc'].forEach(usPrivacy => it('should call user sync url with the us privacy string', function () {
268+
let callBackSpy = sinon.spy();
269+
270+
uspConsentDataStub.returns(usPrivacy);
271+
272+
let result = criteoIdSubmodule.getId(undefined);
229273
result.callback(callBackSpy);
230274

231275
let request = server.requests[0];
232-
if (testCase.expected) {
233-
expect(request.url).to.have.string(`gdprString=${testCase.expected}`);
276+
277+
if (usPrivacy) {
278+
expect(request.url).to.have.string(`us_privacy=${usPrivacy}`);
279+
} else {
280+
expect(request.url).to.not.have.string('us_privacy=');
281+
}
282+
283+
request.respond(
284+
200,
285+
{ 'Content-Type': 'application/json' },
286+
JSON.stringify({})
287+
);
288+
289+
expect(callBackSpy.calledOnce).to.be.true;
290+
}));
291+
292+
[
293+
{
294+
consentData: {
295+
gppString: 'abc',
296+
applicableSections: [1]
297+
},
298+
expectedGpp: 'abc',
299+
expectedGppSid: '1'
300+
},
301+
{
302+
consentData: undefined,
303+
expectedGpp: undefined,
304+
expectedGppSid: undefined
305+
}
306+
].forEach(testCase => it('should call user sync url with the gpp string', function () {
307+
let callBackSpy = sinon.spy();
308+
309+
gppConsentDataStub.returns(testCase.consentData);
310+
311+
let result = criteoIdSubmodule.getId(undefined);
312+
result.callback(callBackSpy);
313+
314+
let request = server.requests[0];
315+
316+
if (testCase.expectedGpp) {
317+
expect(request.url).to.have.string(`gpp=${testCase.expectedGpp}`);
318+
} else {
319+
expect(request.url).to.not.have.string('gpp=');
320+
}
321+
322+
if (testCase.expectedGppSid) {
323+
expect(request.url).to.have.string(`gpp_sid=${testCase.expectedGppSid}`);
234324
} else {
235-
expect(request.url).to.not.have.string('gdprString');
325+
expect(request.url).to.not.have.string('gpp_sid=');
236326
}
237327

238328
request.respond(

0 commit comments

Comments
 (0)