diff --git a/modules/pubCommonIdSystem.js b/modules/pubCommonIdSystem.js index 339029120a8..95e539a4d6a 100644 --- a/modules/pubCommonIdSystem.js +++ b/modules/pubCommonIdSystem.js @@ -9,6 +9,7 @@ import * as utils from '../src/utils.js'; import {submodule} from '../src/hook.js'; import {getStorageManager} from '../src/storageManager.js'; import {ajax} from '../src/ajax.js'; +import { uspDataHandler, coppaDataHandler } from '../src/adapterManager.js'; const PUB_COMMON_ID = 'PublisherCommonId'; const MODULE_NAME = 'pubCommonId'; @@ -142,9 +143,18 @@ function handleResponse(pubcid, callback, config) { * @return {string} */ function sharedIdUrl(consentData) { - if (!consentData || typeof consentData.gdprApplies !== 'boolean' || !consentData.gdprApplies) return SHAREDID_URL; - - return `${SHAREDID_URL}?gdpr=1&gdpr_consent=${consentData.consentString}` + const usPrivacyString = uspDataHandler.getConsentData(); + let sharedIdUrl = SHAREDID_URL; + if (usPrivacyString && typeof usPrivacyString === 'string') { + sharedIdUrl = `${SHAREDID_URL}?us_privacy=${usPrivacyString}`; + } + if (!consentData || typeof consentData.gdprApplies !== 'boolean' || !consentData.gdprApplies) return sharedIdUrl; + if (usPrivacyString) { + sharedIdUrl = `${sharedIdUrl}&gdpr=1&gdpr_consent=${consentData.consentString}` + return sharedIdUrl; + } + sharedIdUrl = `${SHAREDID_URL}?gdpr=1&gdpr_consent=${consentData.consentString}`; + return sharedIdUrl } /** @@ -223,6 +233,11 @@ export const pubCommonIdSubmodule = { * @returns {IdResponse} */ getId: function (config = {}, consentData, storedId) { + const coppa = coppaDataHandler.getCoppa(); + if (coppa) { + utils.logInfo('PubCommonId: IDs not provided for coppa requests, exiting PubCommonId'); + return; + } const {params: {create = true, pixelUrl, enableSharedId = SHAREDID_DEFAULT_STATE} = {}} = config; let newId = storedId; if (!newId) { @@ -263,6 +278,11 @@ export const pubCommonIdSubmodule = { * @returns {IdResponse|undefined} */ extendId: function(config = {}, consentData, storedId) { + const coppa = coppaDataHandler.getCoppa(); + if (coppa) { + utils.logInfo('PubCommonId: IDs not provided for coppa requests, exiting PubCommonId'); + return; + } const {params: {extend = false, pixelUrl, enableSharedId = SHAREDID_DEFAULT_STATE} = {}} = config; if (extend) { diff --git a/modules/sharedIdSystem.js b/modules/sharedIdSystem.js index 762454af5fa..defa8d22639 100644 --- a/modules/sharedIdSystem.js +++ b/modules/sharedIdSystem.js @@ -8,6 +8,7 @@ import * as utils from '../src/utils.js' import {ajax} from '../src/ajax.js'; import {submodule} from '../src/hook.js'; +import { uspDataHandler, coppaDataHandler } from '../src/adapterManager.js'; const MODULE_NAME = 'sharedId'; const ID_SVC = 'https://id.sharedid.org/id'; @@ -282,9 +283,18 @@ function detectPrng(root) { * @return {string} */ function sharedIdUrl(consentData) { - if (!consentData || typeof consentData.gdprApplies !== 'boolean' || !consentData.gdprApplies) return ID_SVC; - - return `${ID_SVC}?gdpr=1&gdpr_consent=${consentData.consentString}` + const usPrivacyString = uspDataHandler.getConsentData(); + let sharedIdUrl = ID_SVC; + if (usPrivacyString) { + sharedIdUrl = `${ID_SVC}?us_privacy=${usPrivacyString}`; + } + if (!consentData || typeof consentData.gdprApplies !== 'boolean' || !consentData.gdprApplies) return sharedIdUrl; + if (usPrivacyString) { + sharedIdUrl = `${sharedIdUrl}&gdpr=1&gdpr_consent=${consentData.consentString}` + return sharedIdUrl; + } + sharedIdUrl = `${ID_SVC}?gdpr=1&gdpr_consent=${consentData.consentString}`; + return sharedIdUrl } /** @type {Submodule} */ @@ -318,6 +328,11 @@ export const sharedIdSubmodule = { * @returns {sharedId} */ getId(config, consentData) { + const coppa = coppaDataHandler.getCoppa(); + if (coppa) { + utils.logInfo('SharedId: IDs not provided for coppa requests, exiting SharedId'); + return; + } const resp = function (callback) { utils.logInfo('SharedId: Sharedid doesnt exists, new cookie creation'); ajax(sharedIdUrl(consentData), idGenerationCallback(callback), undefined, {method: 'GET', withCredentials: true}); @@ -333,6 +348,11 @@ export const sharedIdSubmodule = { * @returns {{callback: *}} */ extendId(config, consentData, storedId) { + const coppa = coppaDataHandler.getCoppa(); + if (coppa) { + utils.logInfo('SharedId: IDs not provided for coppa requests, exiting SharedId'); + return; + } const configParams = (config && config.params) || {}; utils.logInfo('SharedId: Existing shared id ' + storedId.id); const resp = function (callback) { diff --git a/src/adapterManager.js b/src/adapterManager.js index f7f5d821932..4ba773a9476 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -179,6 +179,12 @@ export let uspDataHandler = { } }; +export let coppaDataHandler = { + getCoppa: function() { + return !!(config.getConfig('coppa')) + } +}; + // export for testing export let clientTestAdapters = []; export const allS2SBidders = []; diff --git a/test/spec/modules/sharedIdSystem_spec.js b/test/spec/modules/sharedIdSystem_spec.js index 904d6fe1c78..ad51fe81cde 100644 --- a/test/spec/modules/sharedIdSystem_spec.js +++ b/test/spec/modules/sharedIdSystem_spec.js @@ -2,21 +2,23 @@ import { sharedIdSubmodule, } from 'modules/sharedIdSystem.js'; import { server } from 'test/mocks/xhr.js'; +import {uspDataHandler} from 'src/adapterManager'; let expect = require('chai').expect; describe('SharedId System', function() { const SHAREDID_RESPONSE = {sharedId: 'testsharedid'}; - + let uspConsentDataStub; describe('Xhr Requests from getId()', function() { let callbackSpy = sinon.spy(); beforeEach(function() { callbackSpy.resetHistory(); + uspConsentDataStub = sinon.stub(uspDataHandler, 'getConsentData'); }); afterEach(function () { - + uspConsentDataStub.restore(); }); it('should call shared id endpoint without consent data and handle a valid response', function () { @@ -51,5 +53,25 @@ describe('SharedId System', function() { expect(callbackSpy.calledOnce).to.be.true; expect(callbackSpy.lastCall.lastArg.id).to.equal(SHAREDID_RESPONSE.sharedId); }); + + it('should call shared id endpoint with usp consent data and handle a valid response', function () { + uspConsentDataStub.returns('1YYY'); + let consentData = { + gdprApplies: true, + consentString: 'abc12345234', + }; + + let submoduleCallback = sharedIdSubmodule.getId(undefined, consentData).callback; + submoduleCallback(callbackSpy); + + let request = server.requests[0]; + expect(request.url).to.equal('https://id.sharedid.org/id?us_privacy=1YYY&gdpr=1&gdpr_consent=abc12345234'); + expect(request.withCredentials).to.be.true; + + request.respond(200, {}, JSON.stringify(SHAREDID_RESPONSE)); + + expect(callbackSpy.calledOnce).to.be.true; + expect(callbackSpy.lastCall.lastArg.id).to.equal(SHAREDID_RESPONSE.sharedId); + }); }); }); diff --git a/test/spec/unit/core/adapterManager_spec.js b/test/spec/unit/core/adapterManager_spec.js index 25b2307b943..f33c9139e5f 100644 --- a/test/spec/unit/core/adapterManager_spec.js +++ b/test/spec/unit/core/adapterManager_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import adapterManager, { allS2SBidders, clientTestAdapters, gdprDataHandler } from 'src/adapterManager.js'; +import adapterManager, { allS2SBidders, clientTestAdapters, gdprDataHandler, coppaDataHandler } from 'src/adapterManager.js'; import { getAdUnits, getServerTestingConfig, @@ -1904,7 +1904,25 @@ describe('adapterManager tests', function () { expect(bidRequests[0].gdprConsent).to.be.undefined; }); }); - + describe('coppa consent module', function () { + afterEach(() => { + config.resetConfig(); + }); + it('test coppa configuration with value false', function () { + config.setConfig({ coppa: 0 }); + const coppa = coppaDataHandler.getCoppa(); + expect(coppa).to.be.false; + }); + it('test coppa configuration with value true', function () { + config.setConfig({ coppa: 1 }); + const coppa = coppaDataHandler.getCoppa(); + expect(coppa).to.be.true; + }); + it('test coppa configuration', function () { + const coppa = coppaDataHandler.getCoppa(); + expect(coppa).to.be.false; + }); + }); describe('s2sTesting - testServerOnly', () => { beforeEach(() => { config.setConfig({ s2sConfig: getServerTestingConfig(CONFIG) });