From 0abc9539892a0481806be30833eb6c688f37a642 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Mon, 31 Jan 2022 13:40:00 -0800 Subject: [PATCH] Prebid core: bidder-specific control over storage access via `bidderSettings.allowStorage` https://github.com/prebid/Prebid.js/issues/7280 --- src/storageManager.js | 18 ++++- test/spec/unit/core/storageManager_spec.js | 76 +++++++++++++++++++++- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/storageManager.js b/src/storageManager.js index 3324e5b5a79..9313c625080 100644 --- a/src/storageManager.js +++ b/src/storageManager.js @@ -1,6 +1,8 @@ import {hook} from './hook.js'; -import { hasDeviceAccess, checkCookieSupport, logError } from './utils.js'; +import {hasDeviceAccess, checkCookieSupport, logError, logInfo} from './utils.js'; import includes from 'prebidjs-polyfill/includes.js'; +import {bidderSettings as defaultBidderSettings} from './bidderSettings.js'; +import {config} from './config.js'; const moduleTypeWhiteList = ['core', 'prebid-module']; @@ -22,13 +24,25 @@ export let storageCallbacks = []; * - Module type: Some modules may need these functions but are not vendor. e.g prebid core files in src and modules like currency. * @param {storageOptions} options */ -export function newStorageManager({gvlid, moduleName, moduleType} = {}) { +export function newStorageManager({gvlid, moduleName, moduleType} = {}, {bidderSettings = defaultBidderSettings} = {}) { + function isBidderDisallowed() { + const bidder = config.getCurrentBidder(); + if (bidder == null) { + return false; + } + const storageAllowed = bidderSettings.get(bidder, 'storageAllowed'); + return storageAllowed == null ? false : !storageAllowed; + } function isValid(cb) { if (includes(moduleTypeWhiteList, moduleType)) { let result = { valid: true } return cb(result); + } else if (isBidderDisallowed()) { + logInfo(`bidderSettings denied access to device storage for bidder '${config.getCurrentBidder()}'`); + const result = {valid: false}; + return cb(result); } else { let value; let hookDetails = { diff --git a/test/spec/unit/core/storageManager_spec.js b/test/spec/unit/core/storageManager_spec.js index 5bb766217f5..cf79a206022 100644 --- a/test/spec/unit/core/storageManager_spec.js +++ b/test/spec/unit/core/storageManager_spec.js @@ -1,8 +1,19 @@ -import { resetData, getCoreStorageManager, storageCallbacks, getStorageManager } from 'src/storageManager.js'; +import { + resetData, + getCoreStorageManager, + storageCallbacks, + getStorageManager, + newStorageManager +} from 'src/storageManager.js'; import { config } from 'src/config.js'; import * as utils from 'src/utils.js'; +import {hook} from '../../../../src/hook.js'; describe('storage manager', function() { + before(() => { + hook.ready(); + }); + beforeEach(function() { resetData(); }); @@ -95,4 +106,67 @@ describe('storage manager', function() { expect(localStorage.getItem('unrelated')).to.be.eq('dummy'); }); }); + + describe('when bidderSettings.allowStorage is defined', () => { + let mgr; + const DENIED_BIDDER = 'denied-bidder'; + const DENY_KEY = 'storageAllowed'; + + const COOKIE = 'test-cookie'; + const LS_KEY = 'test-localstorage'; + + function mockBidderSettings() { + return { + get(bidder, key) { + if (bidder === DENIED_BIDDER && key === DENY_KEY) { + return false; + } else { + return undefined; + } + } + } + } + + beforeEach(() => { + mgr = newStorageManager({}, {bidderSettings: mockBidderSettings()}); + }); + + afterEach(() => { + mgr.setCookie(COOKIE, 'delete', new Date().toUTCString()); + mgr.removeDataFromLocalStorage(LS_KEY); + }) + + Object.entries({ + disallowed: [DENIED_BIDDER, false], + allowed: ['allowed-bidder', true] + }).forEach(([test, [bidderCode, shouldWork]]) => { + const testDesc = (desc) => `should ${shouldWork ? '' : 'not'} ${desc} for ${test} bidders` + + it(testDesc('allow cookies'), () => { + config.runWithBidder(bidderCode, () => { + mgr.setCookie(COOKIE, 'value'); + expect(mgr.getCookie(COOKIE)).to.equal(shouldWork ? 'value' : null); + }); + }); + + it(testDesc('allow localStorage'), () => { + config.runWithBidder(bidderCode, () => { + mgr.setDataInLocalStorage(LS_KEY, 'value'); + expect(mgr.getDataFromLocalStorage(LS_KEY)).to.equal(shouldWork ? 'value' : null); + }) + }); + + it(testDesc('report localStorage as available'), () => { + config.runWithBidder(bidderCode, () => { + expect(mgr.hasLocalStorage()).to.equal(shouldWork); + }); + }); + + it(testDesc('report cookies as available'), () => { + config.runWithBidder(bidderCode, () => { + expect(mgr.cookiesAreEnabled()).to.equal(shouldWork); + }) + }) + }); + }) });