Skip to content

Commit cf5b060

Browse files
SKOCHERIskocheri
and
skocheri
authored
SharedId & PubcommonId: CCPA and COPPA support (#6632)
* SharedId & PubcommonId: CCPA and COPPA support * Updating to check consent within the submodule * Fixing review comments and adding tests * Cleaning whitespace Co-authored-by: skocheri <[email protected]>
1 parent 1778504 commit cf5b060

File tree

5 files changed

+96
-10
lines changed

5 files changed

+96
-10
lines changed

modules/pubCommonIdSystem.js

+23-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as utils from '../src/utils.js';
99
import {submodule} from '../src/hook.js';
1010
import {getStorageManager} from '../src/storageManager.js';
1111
import {ajax} from '../src/ajax.js';
12+
import { uspDataHandler, coppaDataHandler } from '../src/adapterManager.js';
1213

1314
const PUB_COMMON_ID = 'PublisherCommonId';
1415
const MODULE_NAME = 'pubCommonId';
@@ -142,9 +143,18 @@ function handleResponse(pubcid, callback, config) {
142143
* @return {string}
143144
*/
144145
function sharedIdUrl(consentData) {
145-
if (!consentData || typeof consentData.gdprApplies !== 'boolean' || !consentData.gdprApplies) return SHAREDID_URL;
146-
147-
return `${SHAREDID_URL}?gdpr=1&gdpr_consent=${consentData.consentString}`
146+
const usPrivacyString = uspDataHandler.getConsentData();
147+
let sharedIdUrl = SHAREDID_URL;
148+
if (usPrivacyString && typeof usPrivacyString === 'string') {
149+
sharedIdUrl = `${SHAREDID_URL}?us_privacy=${usPrivacyString}`;
150+
}
151+
if (!consentData || typeof consentData.gdprApplies !== 'boolean' || !consentData.gdprApplies) return sharedIdUrl;
152+
if (usPrivacyString) {
153+
sharedIdUrl = `${sharedIdUrl}&gdpr=1&gdpr_consent=${consentData.consentString}`
154+
return sharedIdUrl;
155+
}
156+
sharedIdUrl = `${SHAREDID_URL}?gdpr=1&gdpr_consent=${consentData.consentString}`;
157+
return sharedIdUrl
148158
}
149159

150160
/**
@@ -223,6 +233,11 @@ export const pubCommonIdSubmodule = {
223233
* @returns {IdResponse}
224234
*/
225235
getId: function (config = {}, consentData, storedId) {
236+
const coppa = coppaDataHandler.getCoppa();
237+
if (coppa) {
238+
utils.logInfo('PubCommonId: IDs not provided for coppa requests, exiting PubCommonId');
239+
return;
240+
}
226241
const {params: {create = true, pixelUrl, enableSharedId = SHAREDID_DEFAULT_STATE} = {}} = config;
227242
let newId = storedId;
228243
if (!newId) {
@@ -263,6 +278,11 @@ export const pubCommonIdSubmodule = {
263278
* @returns {IdResponse|undefined}
264279
*/
265280
extendId: function(config = {}, consentData, storedId) {
281+
const coppa = coppaDataHandler.getCoppa();
282+
if (coppa) {
283+
utils.logInfo('PubCommonId: IDs not provided for coppa requests, exiting PubCommonId');
284+
return;
285+
}
266286
const {params: {extend = false, pixelUrl, enableSharedId = SHAREDID_DEFAULT_STATE} = {}} = config;
267287

268288
if (extend) {

modules/sharedIdSystem.js

+23-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import * as utils from '../src/utils.js'
99
import {ajax} from '../src/ajax.js';
1010
import {submodule} from '../src/hook.js';
11+
import { uspDataHandler, coppaDataHandler } from '../src/adapterManager.js';
1112

1213
const MODULE_NAME = 'sharedId';
1314
const ID_SVC = 'https://id.sharedid.org/id';
@@ -282,9 +283,18 @@ function detectPrng(root) {
282283
* @return {string}
283284
*/
284285
function sharedIdUrl(consentData) {
285-
if (!consentData || typeof consentData.gdprApplies !== 'boolean' || !consentData.gdprApplies) return ID_SVC;
286-
287-
return `${ID_SVC}?gdpr=1&gdpr_consent=${consentData.consentString}`
286+
const usPrivacyString = uspDataHandler.getConsentData();
287+
let sharedIdUrl = ID_SVC;
288+
if (usPrivacyString) {
289+
sharedIdUrl = `${ID_SVC}?us_privacy=${usPrivacyString}`;
290+
}
291+
if (!consentData || typeof consentData.gdprApplies !== 'boolean' || !consentData.gdprApplies) return sharedIdUrl;
292+
if (usPrivacyString) {
293+
sharedIdUrl = `${sharedIdUrl}&gdpr=1&gdpr_consent=${consentData.consentString}`
294+
return sharedIdUrl;
295+
}
296+
sharedIdUrl = `${ID_SVC}?gdpr=1&gdpr_consent=${consentData.consentString}`;
297+
return sharedIdUrl
288298
}
289299

290300
/** @type {Submodule} */
@@ -318,6 +328,11 @@ export const sharedIdSubmodule = {
318328
* @returns {sharedId}
319329
*/
320330
getId(config, consentData) {
331+
const coppa = coppaDataHandler.getCoppa();
332+
if (coppa) {
333+
utils.logInfo('SharedId: IDs not provided for coppa requests, exiting SharedId');
334+
return;
335+
}
321336
const resp = function (callback) {
322337
utils.logInfo('SharedId: Sharedid doesnt exists, new cookie creation');
323338
ajax(sharedIdUrl(consentData), idGenerationCallback(callback), undefined, {method: 'GET', withCredentials: true});
@@ -333,6 +348,11 @@ export const sharedIdSubmodule = {
333348
* @returns {{callback: *}}
334349
*/
335350
extendId(config, consentData, storedId) {
351+
const coppa = coppaDataHandler.getCoppa();
352+
if (coppa) {
353+
utils.logInfo('SharedId: IDs not provided for coppa requests, exiting SharedId');
354+
return;
355+
}
336356
const configParams = (config && config.params) || {};
337357
utils.logInfo('SharedId: Existing shared id ' + storedId.id);
338358
const resp = function (callback) {

src/adapterManager.js

+6
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,12 @@ export let uspDataHandler = {
179179
}
180180
};
181181

182+
export let coppaDataHandler = {
183+
getCoppa: function() {
184+
return !!(config.getConfig('coppa'))
185+
}
186+
};
187+
182188
// export for testing
183189
export let clientTestAdapters = [];
184190
export const allS2SBidders = [];

test/spec/modules/sharedIdSystem_spec.js

+24-2
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,23 @@ import {
22
sharedIdSubmodule,
33
} from 'modules/sharedIdSystem.js';
44
import { server } from 'test/mocks/xhr.js';
5+
import {uspDataHandler} from 'src/adapterManager';
56

67
let expect = require('chai').expect;
78

89
describe('SharedId System', function() {
910
const SHAREDID_RESPONSE = {sharedId: 'testsharedid'};
10-
11+
let uspConsentDataStub;
1112
describe('Xhr Requests from getId()', function() {
1213
let callbackSpy = sinon.spy();
1314

1415
beforeEach(function() {
1516
callbackSpy.resetHistory();
17+
uspConsentDataStub = sinon.stub(uspDataHandler, 'getConsentData');
1618
});
1719

1820
afterEach(function () {
19-
21+
uspConsentDataStub.restore();
2022
});
2123

2224
it('should call shared id endpoint without consent data and handle a valid response', function () {
@@ -51,5 +53,25 @@ describe('SharedId System', function() {
5153
expect(callbackSpy.calledOnce).to.be.true;
5254
expect(callbackSpy.lastCall.lastArg.id).to.equal(SHAREDID_RESPONSE.sharedId);
5355
});
56+
57+
it('should call shared id endpoint with usp consent data and handle a valid response', function () {
58+
uspConsentDataStub.returns('1YYY');
59+
let consentData = {
60+
gdprApplies: true,
61+
consentString: 'abc12345234',
62+
};
63+
64+
let submoduleCallback = sharedIdSubmodule.getId(undefined, consentData).callback;
65+
submoduleCallback(callbackSpy);
66+
67+
let request = server.requests[0];
68+
expect(request.url).to.equal('https://id.sharedid.org/id?us_privacy=1YYY&gdpr=1&gdpr_consent=abc12345234');
69+
expect(request.withCredentials).to.be.true;
70+
71+
request.respond(200, {}, JSON.stringify(SHAREDID_RESPONSE));
72+
73+
expect(callbackSpy.calledOnce).to.be.true;
74+
expect(callbackSpy.lastCall.lastArg.id).to.equal(SHAREDID_RESPONSE.sharedId);
75+
});
5476
});
5577
});

test/spec/unit/core/adapterManager_spec.js

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect } from 'chai';
2-
import adapterManager, { allS2SBidders, clientTestAdapters, gdprDataHandler } from 'src/adapterManager.js';
2+
import adapterManager, { allS2SBidders, clientTestAdapters, gdprDataHandler, coppaDataHandler } from 'src/adapterManager.js';
33
import {
44
getAdUnits,
55
getServerTestingConfig,
@@ -1904,7 +1904,25 @@ describe('adapterManager tests', function () {
19041904
expect(bidRequests[0].gdprConsent).to.be.undefined;
19051905
});
19061906
});
1907-
1907+
describe('coppa consent module', function () {
1908+
afterEach(() => {
1909+
config.resetConfig();
1910+
});
1911+
it('test coppa configuration with value false', function () {
1912+
config.setConfig({ coppa: 0 });
1913+
const coppa = coppaDataHandler.getCoppa();
1914+
expect(coppa).to.be.false;
1915+
});
1916+
it('test coppa configuration with value true', function () {
1917+
config.setConfig({ coppa: 1 });
1918+
const coppa = coppaDataHandler.getCoppa();
1919+
expect(coppa).to.be.true;
1920+
});
1921+
it('test coppa configuration', function () {
1922+
const coppa = coppaDataHandler.getCoppa();
1923+
expect(coppa).to.be.false;
1924+
});
1925+
});
19081926
describe('s2sTesting - testServerOnly', () => {
19091927
beforeEach(() => {
19101928
config.setConfig({ s2sConfig: getServerTestingConfig(CONFIG) });

0 commit comments

Comments
 (0)