prebid.js 7.50.0 → 7.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/dist/33acrossBidAdapter.js +1 -1
  2. package/dist/33acrossIdSystem.js +1 -1
  3. package/dist/adagioBidAdapter.js +1 -1
  4. package/dist/adbookpspBidAdapter.js +1 -1
  5. package/dist/adgenerationBidAdapter.js +1 -1
  6. package/dist/adhashBidAdapter.js +1 -1
  7. package/dist/adkernelBidAdapter.js +1 -1
  8. package/dist/admanBidAdapter.js +1 -1
  9. package/dist/adnuntiusBidAdapter.js +1 -1
  10. package/dist/adqueryBidAdapter.js +1 -1
  11. package/dist/adrelevantisBidAdapter.js +1 -1
  12. package/dist/adrinoBidAdapter.js +1 -1
  13. package/dist/adriverIdSystem.js +1 -1
  14. package/dist/adtelligentBidAdapter.js +1 -1
  15. package/dist/adtrgtmeBidAdapter.js +1 -1
  16. package/dist/adxcgBidAdapter.js +1 -1
  17. package/dist/adyoulikeBidAdapter.js +1 -1
  18. package/dist/ajaBidAdapter.js +1 -1
  19. package/dist/allowActivities.js +1 -0
  20. package/dist/amxBidAdapter.js +1 -1
  21. package/dist/amxIdSystem.js +1 -1
  22. package/dist/appierAnalyticsAdapter.js +1 -1
  23. package/dist/appnexusBidAdapter.js +1 -1
  24. package/dist/asoBidAdapter.js +1 -1
  25. package/dist/axonixBidAdapter.js +1 -1
  26. package/dist/bidglassBidAdapter.js +1 -1
  27. package/dist/big-richmediaBidAdapter.js +1 -1
  28. package/dist/bridgewellBidAdapter.js +1 -1
  29. package/dist/brightMountainMediaBidAdapter.js +1 -1
  30. package/dist/carodaBidAdapter.js +1 -1
  31. package/dist/chtnwBidAdapter.js +1 -1
  32. package/dist/cleanioRtdProvider.js +1 -1
  33. package/dist/concertBidAdapter.js +1 -1
  34. package/dist/connectIdSystem.js +1 -1
  35. package/dist/connectadBidAdapter.js +1 -1
  36. package/dist/consumableBidAdapter.js +1 -1
  37. package/dist/conversantAnalyticsAdapter.js +1 -1
  38. package/dist/conversantBidAdapter.js +1 -1
  39. package/dist/craftBidAdapter.js +1 -1
  40. package/dist/criteoBidAdapter.js +1 -1
  41. package/dist/cwireBidAdapter.js +1 -1
  42. package/dist/dependencies.json +6 -0
  43. package/dist/dspxBidAdapter.js +1 -1
  44. package/dist/eplanningBidAdapter.js +1 -1
  45. package/dist/feedadBidAdapter.js +1 -1
  46. package/dist/finativeBidAdapter.js +1 -1
  47. package/dist/freewheel-sspBidAdapter.js +1 -1
  48. package/dist/gdprEnforcement.js +1 -1
  49. package/dist/glimpseBidAdapter.js +1 -1
  50. package/dist/gmosspBidAdapter.js +1 -1
  51. package/dist/goldbachBidAdapter.js +1 -1
  52. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  53. package/dist/greenbidsRtdProvider.js +1 -1
  54. package/dist/gridBidAdapter.js +1 -1
  55. package/dist/growthCodeRtdProvider.js +1 -0
  56. package/dist/gumgumBidAdapter.js +1 -1
  57. package/dist/h12mediaBidAdapter.js +1 -1
  58. package/dist/id5IdSystem.js +1 -1
  59. package/dist/improvedigitalBidAdapter.js +1 -1
  60. package/dist/inmarBidAdapter.js +1 -1
  61. package/dist/insticatorBidAdapter.js +1 -1
  62. package/dist/ixBidAdapter.js +1 -1
  63. package/dist/justpremiumBidAdapter.js +1 -1
  64. package/dist/kargoBidAdapter.js +1 -1
  65. package/dist/konduitAnalyticsAdapter.js +1 -1
  66. package/dist/kueezBidAdapter.js +1 -1
  67. package/dist/kueezRtbBidAdapter.js +1 -1
  68. package/dist/kulturemediaBidAdapter.js +1 -1
  69. package/dist/lassoBidAdapter.js +1 -1
  70. package/dist/lifestreetBidAdapter.js +1 -1
  71. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  72. package/dist/logicadBidAdapter.js +1 -1
  73. package/dist/loglyliftBidAdapter.js +1 -1
  74. package/dist/magniteAnalyticsAdapter.js +1 -1
  75. package/dist/malltvAnalyticsAdapter.js +1 -1
  76. package/dist/marsmediaBidAdapter.js +1 -1
  77. package/dist/mediafuseBidAdapter.js +1 -1
  78. package/dist/mediasquareBidAdapter.js +1 -1
  79. package/dist/mgidBidAdapter.js +1 -1
  80. package/dist/minutemediaBidAdapter.js +1 -1
  81. package/dist/minutemediaplusBidAdapter.js +1 -1
  82. package/dist/nexx360BidAdapter.js +1 -1
  83. package/dist/not-for-prod/prebid.js +144 -140
  84. package/dist/objectGuard.js +1 -0
  85. package/dist/oguryBidAdapter.js +1 -1
  86. package/dist/onetagBidAdapter.js +1 -1
  87. package/dist/ooloAnalyticsAdapter.js +1 -1
  88. package/dist/optidigitalBidAdapter.js +1 -1
  89. package/dist/outbrainBidAdapter.js +1 -1
  90. package/dist/oxxionAnalyticsAdapter.js +1 -0
  91. package/dist/pairIdSystem.js +1 -1
  92. package/dist/parrableIdSystem.js +1 -1
  93. package/dist/pixfutureBidAdapter.js +1 -1
  94. package/dist/prebid-core.js +1 -1
  95. package/dist/prebidServerBidAdapter.js +1 -1
  96. package/dist/publinkIdSystem.js +1 -1
  97. package/dist/pubmaticBidAdapter.js +1 -1
  98. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  99. package/dist/pxyzBidAdapter.js +1 -1
  100. package/dist/quantcastBidAdapter.js +1 -1
  101. package/dist/readpeakBidAdapter.js +1 -1
  102. package/dist/relaidoBidAdapter.js +1 -1
  103. package/dist/retailspotBidAdapter.js +1 -1
  104. package/dist/rhythmoneBidAdapter.js +1 -1
  105. package/dist/riseBidAdapter.js +1 -1
  106. package/dist/rtdModule.js +1 -1
  107. package/dist/rubiconAnalyticsAdapter.js +1 -1
  108. package/dist/rubiconBidAdapter.js +1 -1
  109. package/dist/seedingAllianceBidAdapter.js +1 -1
  110. package/dist/seedtagBidAdapter.js +1 -1
  111. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  112. package/dist/sharethroughBidAdapter.js +1 -1
  113. package/dist/shinezBidAdapter.js +1 -1
  114. package/dist/smaatoBidAdapter.js +1 -1
  115. package/dist/smartadserverBidAdapter.js +1 -1
  116. package/dist/smartxBidAdapter.js +1 -1
  117. package/dist/smilewantedBidAdapter.js +1 -1
  118. package/dist/sonobiBidAdapter.js +1 -1
  119. package/dist/sovrnAnalyticsAdapter.js +1 -1
  120. package/dist/sovrnBidAdapter.js +1 -1
  121. package/dist/sspBCBidAdapter.js +1 -1
  122. package/dist/stvBidAdapter.js +1 -1
  123. package/dist/sublimeBidAdapter.js +1 -1
  124. package/dist/synacormediaBidAdapter.js +1 -1
  125. package/dist/targetVideoBidAdapter.js +1 -1
  126. package/dist/teadsBidAdapter.js +1 -1
  127. package/dist/trionBidAdapter.js +1 -1
  128. package/dist/tripleliftBidAdapter.js +1 -1
  129. package/dist/ttdBidAdapter.js +1 -1
  130. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  131. package/dist/uid2IdSystem.js +1 -1
  132. package/dist/underdogmediaBidAdapter.js +1 -1
  133. package/dist/undertoneBidAdapter.js +1 -1
  134. package/dist/userId.js +1 -1
  135. package/dist/vidazooBidAdapter.js +1 -1
  136. package/dist/videobyteBidAdapter.js +1 -1
  137. package/dist/visxBidAdapter.js +1 -1
  138. package/dist/vuukleBidAdapter.js +1 -1
  139. package/dist/widespaceBidAdapter.js +1 -1
  140. package/dist/winrBidAdapter.js +1 -1
  141. package/dist/yahoosspBidAdapter.js +1 -1
  142. package/dist/yieldmoBidAdapter.js +1 -1
  143. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  144. package/dist/zeta_global_sspBidAdapter.js +1 -1
  145. package/integrationExamples/gpt/growthcode.html +20 -9
  146. package/libraries/objectGuard/objectGuard.js +108 -0
  147. package/libraries/objectGuard/ortbGuard.js +88 -0
  148. package/modules/adgenerationBidAdapter.js +14 -5
  149. package/modules/adhashBidAdapter.js +28 -17
  150. package/modules/adkernelBidAdapter.js +2 -1
  151. package/modules/admanBidAdapter.js +30 -22
  152. package/modules/adnuntiusBidAdapter.js +98 -79
  153. package/modules/adnuntiusBidAdapter.md +2 -1
  154. package/modules/adqueryBidAdapter.js +7 -1
  155. package/modules/adrinoBidAdapter.js +1 -0
  156. package/modules/adriverIdSystem.js +1 -1
  157. package/modules/adtelligentBidAdapter.js +4 -2
  158. package/modules/allowActivities.js +74 -0
  159. package/modules/appnexusBidAdapter.js +1 -0
  160. package/modules/cleanioRtdProvider.js +2 -4
  161. package/modules/connectIdSystem.js +89 -13
  162. package/modules/connectIdSystem.md +4 -7
  163. package/modules/criteoBidAdapter.js +50 -3
  164. package/modules/freewheel-sspBidAdapter.js +10 -2
  165. package/modules/gdprEnforcement.js +98 -169
  166. package/modules/growthCodeRtdProvider.js +131 -0
  167. package/modules/growthCodeRtdProvider.md +55 -0
  168. package/modules/gumgumBidAdapter.js +5 -0
  169. package/modules/ixBidAdapter.js +5 -2
  170. package/modules/minutemediaBidAdapter.js +13 -3
  171. package/modules/oxxionAnalyticsAdapter.js +212 -0
  172. package/modules/oxxionAnalyticsAdapter.md +33 -0
  173. package/modules/pairIdSystem.js +6 -6
  174. package/modules/prebidServerBidAdapter/index.js +7 -8
  175. package/modules/pubmaticBidAdapter.js +1 -0
  176. package/modules/riseBidAdapter.js +13 -3
  177. package/modules/rtbhouseBidAdapter.md +24 -0
  178. package/modules/rtdModule/index.js +12 -1
  179. package/modules/sharethroughBidAdapter.js +2 -2
  180. package/modules/smartadserverBidAdapter.js +5 -0
  181. package/modules/stvBidAdapter.js +34 -1
  182. package/modules/undertoneBidAdapter.js +9 -1
  183. package/modules/userId/index.js +69 -41
  184. package/modules/yahoosspBidAdapter.js +45 -3
  185. package/modules/yahoosspBidAdapter.md +1 -1
  186. package/modules/zeta_global_sspBidAdapter.js +1 -0
  187. package/package.json +1 -1
  188. package/src/activities/activities.js +47 -0
  189. package/src/activities/activityParams.js +8 -0
  190. package/src/activities/modules.js +1 -1
  191. package/src/activities/params.js +59 -0
  192. package/src/activities/redactor.js +157 -0
  193. package/src/activities/rules.js +95 -0
  194. package/src/adapterManager.js +45 -8
  195. package/src/adloader.js +2 -1
  196. package/src/fpd/rootDomain.js +1 -1
  197. package/src/native.js +20 -4
  198. package/src/prebid.js +1 -1
  199. package/src/storageManager.js +57 -44
  200. package/src/userSync.js +35 -18
  201. package/test/spec/activities/allowActivites_spec.js +138 -0
  202. package/test/spec/activities/objectGuard_spec.js +144 -0
  203. package/test/spec/activities/ortbGuard_spec.js +140 -0
  204. package/test/spec/activities/params_spec.js +25 -0
  205. package/test/spec/activities/redactor_spec.js +296 -0
  206. package/test/spec/activities/rules_spec.js +135 -0
  207. package/test/spec/modules/adgenerationBidAdapter_spec.js +52 -12
  208. package/test/spec/modules/adhashBidAdapter_spec.js +51 -1
  209. package/test/spec/modules/admanBidAdapter_spec.js +1 -2
  210. package/test/spec/modules/adnuntiusBidAdapter_spec.js +535 -264
  211. package/test/spec/modules/adqueryBidAdapter_spec.js +9 -0
  212. package/test/spec/modules/adrinoBidAdapter_spec.js +4 -0
  213. package/test/spec/modules/adtelligentBidAdapter_spec.js +1 -0
  214. package/test/spec/modules/cleanioRtdProvider_spec.js +7 -8
  215. package/test/spec/modules/connectIdSystem_spec.js +291 -23
  216. package/test/spec/modules/criteoBidAdapter_spec.js +134 -2
  217. package/test/spec/modules/freewheel-sspBidAdapter_spec.js +5 -2
  218. package/test/spec/modules/gdprEnforcement_spec.js +127 -414
  219. package/test/spec/modules/growthCodeRtdProvider_spec.js +127 -0
  220. package/test/spec/modules/gumgumBidAdapter_spec.js +14 -0
  221. package/test/spec/modules/ixBidAdapter_spec.js +2 -1
  222. package/test/spec/modules/minutemediaBidAdapter_spec.js +69 -1
  223. package/test/spec/modules/oxxionAnalyticsAdapter_spec.js +324 -0
  224. package/test/spec/modules/pairIdSystem_spec.js +16 -3
  225. package/test/spec/modules/prebidServerBidAdapter_spec.js +3 -1
  226. package/test/spec/modules/pubmaticBidAdapter_spec.js +7 -0
  227. package/test/spec/modules/realTimeDataModule_spec.js +1 -1
  228. package/test/spec/modules/riseBidAdapter_spec.js +69 -1
  229. package/test/spec/modules/sharethroughBidAdapter_spec.js +1 -1
  230. package/test/spec/modules/smartadserverBidAdapter_spec.js +42 -0
  231. package/test/spec/modules/stvBidAdapter_spec.js +13 -1
  232. package/test/spec/modules/undertoneBidAdapter_spec.js +57 -1
  233. package/test/spec/modules/userId_spec.js +80 -21
  234. package/test/spec/modules/yahoosspBidAdapter_spec.js +103 -51
  235. package/test/spec/modules/zeta_global_sspBidAdapter_spec.js +4 -0
  236. package/test/spec/native_spec.js +12 -12
  237. package/test/spec/unit/core/adapterManager_spec.js +181 -1
  238. package/test/spec/unit/core/storageManager_spec.js +76 -68
  239. package/test/spec/unit/pbjs_api_spec.js +15 -25
  240. package/test/spec/userSync_spec.js +45 -16
@@ -110,6 +110,7 @@
110
110
  * @property {SubmoduleConfig} config
111
111
  * @property {(Object|undefined)} idObj - cache decoded id value (this is copied to every adUnit bid)
112
112
  * @property {(function|undefined)} callback - holds reference to submodule.getId() result if it returned a function. Will be set to undefined after callback executes
113
+ * @property {StorageManager} storageMgr
113
114
  */
114
115
 
115
116
  /**
@@ -133,7 +134,12 @@ import adapterManager, {gdprDataHandler} from '../../src/adapterManager.js';
133
134
  import CONSTANTS from '../../src/constants.json';
134
135
  import {hook, module, ready as hooksReady} from '../../src/hook.js';
135
136
  import {buildEidPermissions, createEidsArray, USER_IDS_CONFIG} from './eids.js';
136
- import {getCoreStorageManager, STORAGE_TYPE_COOKIES, STORAGE_TYPE_LOCALSTORAGE} from '../../src/storageManager.js';
137
+ import {
138
+ getCoreStorageManager,
139
+ getStorageManager,
140
+ STORAGE_TYPE_COOKIES,
141
+ STORAGE_TYPE_LOCALSTORAGE
142
+ } from '../../src/storageManager.js';
137
143
  import {
138
144
  cyrb53Hash,
139
145
  deepAccess,
@@ -159,6 +165,9 @@ import {newMetrics, timedAuctionHook, useMetrics} from '../../src/utils/perfMetr
159
165
  import {findRootDomain} from '../../src/fpd/rootDomain.js';
160
166
  import {GDPR_GVLIDS} from '../../src/consentHandler.js';
161
167
  import {MODULE_TYPE_UID} from '../../src/activities/modules.js';
168
+ import {isActivityAllowed} from '../../src/activities/rules.js';
169
+ import {ACTIVITY_ENRICH_EIDS} from '../../src/activities/activities.js';
170
+ import {activityParams} from '../../src/activities/activityParams.js';
162
171
 
163
172
  const MODULE_NAME = 'User ID';
164
173
  const COOKIE = STORAGE_TYPE_COOKIES;
@@ -170,7 +179,10 @@ const CONSENT_DATA_COOKIE_STORAGE_CONFIG = {
170
179
  expires: 30 // 30 days expiration, which should match how often consent is refreshed by CMPs
171
180
  };
172
181
  export const PBJS_USER_ID_OPTOUT_NAME = '_pbjs_id_optout';
173
- export const coreStorage = getCoreStorageManager('userid');
182
+ export const coreStorage = getCoreStorageManager('userId');
183
+ export const dep = {
184
+ isAllowed: isActivityAllowed
185
+ }
174
186
 
175
187
  /** @type {boolean} */
176
188
  let addedUserIdHook = false;
@@ -220,11 +232,12 @@ export function setSubmoduleRegistry(submodules) {
220
232
  submoduleRegistry = submodules;
221
233
  }
222
234
 
223
- function cookieSetter(submodule) {
235
+ function cookieSetter(submodule, storageMgr) {
236
+ storageMgr = storageMgr || submodule.storageMgr;
224
237
  const domainOverride = (typeof submodule.submodule.domainOverride === 'function') ? submodule.submodule.domainOverride() : null;
225
238
  const name = submodule.config.storage.name;
226
239
  return function setCookie(suffix, value, expiration) {
227
- coreStorage.setCookie(name + (suffix || ''), value, expiration, 'Lax', domainOverride);
240
+ storageMgr.setCookie(name + (suffix || ''), value, expiration, 'Lax', domainOverride);
228
241
  }
229
242
  }
230
243
 
@@ -237,6 +250,7 @@ export function setStoredValue(submodule, value) {
237
250
  * @type {SubmoduleStorage}
238
251
  */
239
252
  const storage = submodule.config.storage;
253
+ const mgr = submodule.storageMgr;
240
254
 
241
255
  try {
242
256
  const expiresStr = (new Date(Date.now() + (storage.expires * (60 * 60 * 24 * 1000)))).toUTCString();
@@ -248,10 +262,10 @@ export function setStoredValue(submodule, value) {
248
262
  setCookie('_last', new Date().toUTCString(), expiresStr);
249
263
  }
250
264
  } else if (storage.type === LOCAL_STORAGE) {
251
- coreStorage.setDataInLocalStorage(`${storage.name}_exp`, expiresStr);
252
- coreStorage.setDataInLocalStorage(storage.name, encodeURIComponent(valueStr));
265
+ mgr.setDataInLocalStorage(`${storage.name}_exp`, expiresStr);
266
+ mgr.setDataInLocalStorage(storage.name, encodeURIComponent(valueStr));
253
267
  if (typeof storage.refreshInSeconds === 'number') {
254
- coreStorage.setDataInLocalStorage(`${storage.name}_last`, new Date().toUTCString());
268
+ mgr.setDataInLocalStorage(`${storage.name}_last`, new Date().toUTCString());
255
269
  }
256
270
  }
257
271
  } catch (error) {
@@ -263,7 +277,7 @@ export function deleteStoredValue(submodule) {
263
277
  let deleter, suffixes;
264
278
  switch (submodule.config?.storage?.type) {
265
279
  case COOKIE:
266
- const setCookie = cookieSetter(submodule);
280
+ const setCookie = cookieSetter(submodule, coreStorage);
267
281
  const expiry = (new Date(Date.now() - 1000 * 60 * 60 * 24)).toUTCString();
268
282
  deleter = (suffix) => setCookie(suffix, '', expiry)
269
283
  suffixes = ['', '_last'];
@@ -292,25 +306,26 @@ function setPrebidServerEidPermissions(initializedSubmodules) {
292
306
  }
293
307
 
294
308
  /**
295
- /**
296
- * @param {SubmoduleStorage} storage
309
+ * @param {SubmoduleContainer} submodule
297
310
  * @param {String|undefined} key optional key of the value
298
311
  * @returns {string}
299
312
  */
300
- function getStoredValue(storage, key = undefined) {
313
+ function getStoredValue(submodule, key = undefined) {
314
+ const mgr = submodule.storageMgr;
315
+ const storage = submodule.config.storage;
301
316
  const storedKey = key ? `${storage.name}_${key}` : storage.name;
302
317
  let storedValue;
303
318
  try {
304
319
  if (storage.type === COOKIE) {
305
- storedValue = coreStorage.getCookie(storedKey);
320
+ storedValue = mgr.getCookie(storedKey);
306
321
  } else if (storage.type === LOCAL_STORAGE) {
307
- const storedValueExp = coreStorage.getDataFromLocalStorage(`${storage.name}_exp`);
322
+ const storedValueExp = mgr.getDataFromLocalStorage(`${storage.name}_exp`);
308
323
  // empty string means no expiration set
309
324
  if (storedValueExp === '') {
310
- storedValue = coreStorage.getDataFromLocalStorage(storedKey);
325
+ storedValue = mgr.getDataFromLocalStorage(storedKey);
311
326
  } else if (storedValueExp) {
312
327
  if ((new Date(storedValueExp)).getTime() - Date.now() > 0) {
313
- storedValue = decodeURIComponent(coreStorage.getDataFromLocalStorage(storedKey));
328
+ storedValue = decodeURIComponent(mgr.getDataFromLocalStorage(storedKey));
314
329
  }
315
330
  }
316
331
  }
@@ -415,7 +430,7 @@ function processSubmoduleCallbacks(submodules, cb) {
415
430
  moduleDone();
416
431
  }
417
432
  try {
418
- submodule.callback(callbackCompleted, getStoredValue.bind(null, submodule.config?.storage));
433
+ submodule.callback(callbackCompleted, getStoredValue.bind(null, submodule));
419
434
  } catch (e) {
420
435
  logError(`Error in userID module '${submodule.submodule.name}':`, e);
421
436
  moduleDone();
@@ -773,6 +788,8 @@ function getUserIdsAsync() {
773
788
  * This hook returns updated list of submodules which are allowed to do get user id based on TCF 2 enforcement rules configured
774
789
  */
775
790
  export const validateGdprEnforcement = hook('sync', function (submodules, consentData) {
791
+ // TODO: remove the `hasValidated` check in v8. Enforcement should be OFF by default.
792
+ // https://github.com/prebid/Prebid.js/issues/9766
776
793
  return { userIdModules: submodules, hasValidated: consentData && consentData.hasValidated };
777
794
  }, 'validateGdprEnforcement');
778
795
 
@@ -781,12 +798,12 @@ function populateSubmoduleId(submodule, consentData, storedConsentData, forceRef
781
798
  // 1. storage: retrieve user id data from cookie/html storage or with the submodule's getId method
782
799
  // 2. value: pass directly to bids
783
800
  if (submodule.config.storage) {
784
- let storedId = getStoredValue(submodule.config.storage);
801
+ let storedId = getStoredValue(submodule);
785
802
  let response;
786
803
 
787
804
  let refreshNeeded = false;
788
805
  if (typeof submodule.config.storage.refreshInSeconds === 'number') {
789
- const storedDate = new Date(getStoredValue(submodule.config.storage, 'last'));
806
+ const storedDate = new Date(getStoredValue(submodule, 'last'));
790
807
  refreshNeeded = storedDate && (Date.now() - storedDate.getTime() > submodule.config.storage.refreshInSeconds * 1000);
791
808
  }
792
809
 
@@ -849,17 +866,23 @@ function initSubmodules(dest, submodules, consentData, forceRefresh = false) {
849
866
  return uidMetrics().fork().measureTime('userId.init.modules', function () {
850
867
  if (!submodules.length) return []; // to simplify log messages from here on
851
868
 
852
- // filter out submodules whose storage type is not enabled
853
- // this needs to be done here (after consent data has loaded) so that enforcement may disable storage globally
854
- const storageTypes = getActiveStorageTypes();
855
- submodules = submodules.filter((submod) => !submod.config.storage || storageTypes.has(submod.config.storage.type));
869
+ /**
870
+ * filter out submodules that:
871
+ *
872
+ * - cannot use the storage they've been set up with (storage not available / not allowed / disabled)
873
+ * - are not allowed to perform the `enrichEids` activity
874
+ */
875
+ submodules = submodules.filter((submod) => {
876
+ return (!submod.config.storage || canUseStorage(submod)) &&
877
+ dep.isAllowed(ACTIVITY_ENRICH_EIDS, activityParams(MODULE_TYPE_UID, submod.config.name));
878
+ });
856
879
 
857
880
  if (!submodules.length) {
858
- logWarn(`${MODULE_NAME} - no ID module is configured for one of the available storage types:`, Array.from(storageTypes));
881
+ logWarn(`${MODULE_NAME} - no ID module configured`);
859
882
  return [];
860
883
  }
861
884
 
862
- // another consent check, this time each module is checked for consent with its own gvlid
885
+ // TODO: remove this check in v8 (https://github.com/prebid/Prebid.js/issues/9766)
863
886
  let { userIdModules, hasValidated } = validateGdprEnforcement(submodules, consentData);
864
887
  if (!hasValidated && !hasPurpose1Consent(consentData)) {
865
888
  logWarn(`${MODULE_NAME} - gdpr permission not valid for local storage or cookies, exit module`);
@@ -940,24 +963,28 @@ function getValidSubmoduleConfigs(configRegistry, submoduleRegistry) {
940
963
 
941
964
  const ALL_STORAGE_TYPES = new Set([LOCAL_STORAGE, COOKIE]);
942
965
 
943
- function getActiveStorageTypes() {
944
- const storageTypes = [];
945
- let disabled = false;
946
- if (coreStorage.localStorageIsEnabled()) {
947
- storageTypes.push(LOCAL_STORAGE);
948
- if (coreStorage.getDataFromLocalStorage(PBJS_USER_ID_OPTOUT_NAME)) {
949
- logInfo(`${MODULE_NAME} - opt-out localStorage found, storage disabled`);
950
- disabled = true;
951
- }
952
- }
953
- if (coreStorage.cookiesAreEnabled()) {
954
- storageTypes.push(COOKIE);
955
- if (coreStorage.getCookie(PBJS_USER_ID_OPTOUT_NAME)) {
956
- logInfo(`${MODULE_NAME} - opt-out cookie found, storage disabled`);
957
- disabled = true;
958
- }
966
+ function canUseStorage(submodule) {
967
+ switch (submodule.config?.storage?.type) {
968
+ case LOCAL_STORAGE:
969
+ if (submodule.storageMgr.localStorageIsEnabled()) {
970
+ if (coreStorage.getDataFromLocalStorage(PBJS_USER_ID_OPTOUT_NAME)) {
971
+ logInfo(`${MODULE_NAME} - opt-out localStorage found, storage disabled`);
972
+ return false
973
+ }
974
+ return true;
975
+ }
976
+ break;
977
+ case COOKIE:
978
+ if (submodule.storageMgr.cookiesAreEnabled()) {
979
+ if (coreStorage.getCookie(PBJS_USER_ID_OPTOUT_NAME)) {
980
+ logInfo(`${MODULE_NAME} - opt-out cookie found, storage disabled`);
981
+ return false;
982
+ }
983
+ return true
984
+ }
985
+ break;
959
986
  }
960
- return new Set(disabled ? [] : storageTypes)
987
+ return false;
961
988
  }
962
989
 
963
990
  /**
@@ -985,6 +1012,7 @@ function updateSubmodules() {
985
1012
  config: submoduleConfig,
986
1013
  callback: undefined,
987
1014
  idObj: undefined,
1015
+ storageMgr: getStorageManager({moduleType: MODULE_TYPE_UID, moduleName: submoduleConfig.name}),
988
1016
  } : null;
989
1017
  }).filter(submodule => submodule !== null)
990
1018
  .forEach((sm) => submodules.push(sm));
@@ -101,6 +101,37 @@ function extractUserSyncUrls(syncOptions, pixels) {
101
101
  return userSyncObjects;
102
102
  }
103
103
 
104
+ /**
105
+ * @param {string} url
106
+ * @param {object} consentData
107
+ * @param {object} consentData.gpp
108
+ * @param {string} consentData.gpp.gppConsent
109
+ * @param {array} consentData.gpp.applicableSections
110
+ * @param {object} consentData.gdpr
111
+ * @param {object} consentData.gdpr.consentString
112
+ * @param {object} consentData.gdpr.gdprApplies
113
+ * @param {string} consentData.uspConsent
114
+ */
115
+ function updateConsentQueryParams(url, consentData) {
116
+ const parameterMap = {
117
+ 'gdpr_consent': consentData.gdpr.consentString,
118
+ 'gdpr': consentData.gdpr.gdprApplies ? '1' : '0',
119
+ 'us_privacy': consentData.uspConsent,
120
+ 'gpp': consentData.gpp.gppString,
121
+ 'gpp_sid': consentData.gpp.applicableSections ? consentData.gpp.applicableSections.join(',') : ''
122
+ }
123
+
124
+ const existingUrl = new URL(url);
125
+ const params = existingUrl.searchParams;
126
+
127
+ for (const [key, value] of Object.entries(parameterMap)) {
128
+ params.set(key, value);
129
+ }
130
+
131
+ existingUrl.search = params.toString();
132
+ return existingUrl.toString();
133
+ };
134
+
104
135
  function getSupportedEids(bid) {
105
136
  if (isArray(deepAccess(bid, 'userIdAsEids'))) {
106
137
  return bid.userIdAsEids.filter(eid => {
@@ -244,7 +275,9 @@ function generateOpenRtbObject(bidderRequest, bid) {
244
275
  regs: {
245
276
  ext: {
246
277
  'us_privacy': bidderRequest.uspConsent ? bidderRequest.uspConsent : '',
247
- gdpr: bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies ? 1 : 0
278
+ gdpr: bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies ? 1 : 0,
279
+ gpp: bidderRequest.gppConsent.gppString,
280
+ gpp_sid: bidderRequest.gppConsent.applicableSections
248
281
  }
249
282
  },
250
283
  source: {
@@ -518,6 +551,7 @@ function createRenderer(bidderRequest, bidResponse) {
518
551
  }
519
552
  return renderer;
520
553
  }
554
+
521
555
  /* Utility functions */
522
556
 
523
557
  export const spec = {
@@ -634,11 +668,19 @@ export const spec = {
634
668
  return response;
635
669
  },
636
670
 
637
- getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {
671
+ getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) {
638
672
  const bidResponse = !isEmpty(serverResponses) && serverResponses[0].body;
639
673
 
640
674
  if (bidResponse && bidResponse.ext && bidResponse.ext.pixels) {
641
- return extractUserSyncUrls(syncOptions, bidResponse.ext.pixels);
675
+ const userSyncObjects = extractUserSyncUrls(syncOptions, bidResponse.ext.pixels);
676
+ userSyncObjects.forEach(userSyncObject => {
677
+ userSyncObject.url = updateConsentQueryParams(userSyncObject.url, {
678
+ gpp: gppConsent,
679
+ gdpr: gdprConsent,
680
+ uspConsent: uspConsent
681
+ });
682
+ });
683
+ return userSyncObjects;
642
684
  }
643
685
 
644
686
  return [];
@@ -827,6 +827,6 @@ const adUnits = [{
827
827
  This adapter does not support passing legacy overrides via 'bidder.params.ext' since most of the data should be passed using prebid modules (First Party Data, Schain, Price Floors etc.).
828
828
  If you do not know how to pass a custom parameter that you previously used, please contact us using the information provided above.
829
829
 
830
- Thanks you,
830
+ Thank you,
831
831
  Yahoo SSP
832
832
 
@@ -36,6 +36,7 @@ const VIDEO_CUSTOM_PARAMS = {
36
36
  'battr': DATA_TYPES.ARRAY,
37
37
  'linearity': DATA_TYPES.NUMBER,
38
38
  'placement': DATA_TYPES.NUMBER,
39
+ 'plcmt': DATA_TYPES.NUMBER,
39
40
  'minbitrate': DATA_TYPES.NUMBER,
40
41
  'maxbitrate': DATA_TYPES.NUMBER,
41
42
  'skip': DATA_TYPES.NUMBER
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prebid.js",
3
- "version": "7.50.0",
3
+ "version": "7.52.0",
4
4
  "description": "Header Bidding Management Library",
5
5
  "main": "src/prebid.js",
6
6
  "scripts": {
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Activity (that are relevant for privacy) definitions
3
+ *
4
+ * ref. https://docs.google.com/document/d/1dRxFUFmhh2jGanzGZvfkK_6jtHPpHXWD7Qsi6KEugeE
5
+ * & https://github.com/prebid/Prebid.js/issues/9546
6
+ */
7
+
8
+ /**
9
+ * accessDevice: some component wants to read or write to localStorage or cookies.
10
+ */
11
+ export const ACTIVITY_ACCESS_DEVICE = 'accessDevice';
12
+ /**
13
+ * syncUser: A bid adapter wants to run a user sync.
14
+ */
15
+ export const ACTIVITY_SYNC_USER = 'syncUser';
16
+ /**
17
+ * enrichUfpd: some component wants to add user first-party data to bid requests.
18
+ */
19
+ export const ACTIVITY_ENRICH_UFPD = 'enrichUfpd';
20
+ /**
21
+ * enrichEids: some component wants to add user IDs to bid requests.
22
+ */
23
+ export const ACTIVITY_ENRICH_EIDS = 'enrichEids';
24
+ /**
25
+ * fetchBid: a bidder wants to bid.
26
+ */
27
+ export const ACTIVITY_FETCH_BIDS = 'fetchBids';
28
+
29
+ /**
30
+ * reportAnalytics: some component wants to phone home with analytics data.
31
+ */
32
+ export const ACTIVITY_REPORT_ANALYTICS = 'reportAnalytics';
33
+
34
+ /**
35
+ * some component wants access to (and send along) user IDs
36
+ */
37
+ export const ACTIVITY_TRANSMIT_EIDS = 'transmitEids'
38
+
39
+ /**
40
+ * transmitUfpd: some component wants access to (and send along) user FPD
41
+ */
42
+ export const ACTIVITY_TRANSMIT_UFPD = 'transmitUfpd';
43
+
44
+ /**
45
+ * transmitPreciseGeo: some component wants access to (and send along) geolocation info
46
+ */
47
+ export const ACTIVITY_TRANSMIT_PRECISE_GEO = 'transmitPreciseGeo';
@@ -0,0 +1,8 @@
1
+ import adapterManager from '../adapterManager.js';
2
+ import {activityParamsBuilder} from './params.js';
3
+
4
+ /**
5
+ * Utility function for building common activity parameters - broken out to its own
6
+ * file to avoid circular imports.
7
+ */
8
+ export const activityParams = activityParamsBuilder((alias) => adapterManager.resolveAlias(alias));
@@ -1,4 +1,4 @@
1
- export const MODULE_TYPE_CORE = 'core';
1
+ export const MODULE_TYPE_PREBID = 'prebid';
2
2
  export const MODULE_TYPE_BIDDER = 'bidder';
3
3
  export const MODULE_TYPE_UID = 'userId';
4
4
  export const MODULE_TYPE_RTD = 'rtd';
@@ -0,0 +1,59 @@
1
+ import {MODULE_TYPE_BIDDER} from './modules.js';
2
+
3
+ /**
4
+ * Component ID - who is trying to perform the activity?
5
+ * Relevant for all activities.
6
+ */
7
+ export const ACTIVITY_PARAM_COMPONENT = 'component';
8
+ export const ACTIVITY_PARAM_COMPONENT_TYPE = ACTIVITY_PARAM_COMPONENT + 'Type';
9
+ export const ACTIVITY_PARAM_COMPONENT_NAME = ACTIVITY_PARAM_COMPONENT + 'Name';
10
+
11
+ /**
12
+ * Code of the bid adapter that `componentName` is an alias of.
13
+ * May be the same as the component name.
14
+ *
15
+ * relevant for all activities, but only when componentType is 'bidder'.
16
+ */
17
+ export const ACTIVITY_PARAM_ADAPTER_CODE = 'adapterCode';
18
+
19
+ /**
20
+ * Storage type - either 'html5' or 'cookie'.
21
+ * Relevant for: accessDevice
22
+ */
23
+ export const ACTIVITY_PARAM_STORAGE_TYPE = 'storageType';
24
+
25
+ /**
26
+ * s2sConfig[].configName, used to identify a particular s2s instance
27
+ * relevant for: fetchBids, but only when component is 'prebid.pbsBidAdapter'
28
+ */
29
+ export const ACTIVITY_PARAM_S2S_NAME = 'configName';
30
+ /**
31
+ * user sync type - 'iframe' or 'pixel'
32
+ * relevant for: syncUser
33
+ */
34
+ export const ACTIVITY_PARAM_SYNC_TYPE = 'syncType'
35
+ /**
36
+ * user sync URL
37
+ * relevant for: syncUser
38
+ */
39
+ export const ACTIVITY_PARAM_SYNC_URL = 'syncUrl';
40
+ /**
41
+ * @private
42
+ * configuration options for analytics adapter - the argument passed to `enableAnalytics`.
43
+ * relevant for: reportAnalytics
44
+ */
45
+ export const ACTIVITY_PARAM_ANL_CONFIG = '_config';
46
+
47
+ export function activityParamsBuilder(resolveAlias) {
48
+ return function activityParams(moduleType, moduleName, params) {
49
+ const defaults = {
50
+ [ACTIVITY_PARAM_COMPONENT_TYPE]: moduleType,
51
+ [ACTIVITY_PARAM_COMPONENT_NAME]: moduleName,
52
+ [ACTIVITY_PARAM_COMPONENT]: `${moduleType}.${moduleName}`
53
+ };
54
+ if (moduleType === MODULE_TYPE_BIDDER) {
55
+ defaults[ACTIVITY_PARAM_ADAPTER_CODE] = resolveAlias(moduleName);
56
+ }
57
+ return Object.assign(defaults, params);
58
+ }
59
+ }
@@ -0,0 +1,157 @@
1
+ import {deepAccess} from '../utils.js';
2
+ import {isActivityAllowed} from './rules.js';
3
+ import {ACTIVITY_TRANSMIT_EIDS, ACTIVITY_TRANSMIT_PRECISE_GEO, ACTIVITY_TRANSMIT_UFPD} from './activities.js';
4
+
5
+ export const ORTB_UFPD_PATHS = ['user.data', 'user.ext.data'];
6
+ export const ORTB_EIDS_PATHS = ['user.eids', 'user.ext.eids'];
7
+ export const ORTB_GEO_PATHS = ['user.geo.lat', 'user.geo.lon', 'device.geo.lat', 'device.geo.lon'];
8
+
9
+ /**
10
+ * @typedef TransformationRuleDef
11
+ * @property {name}
12
+ * @property {Array[string]} paths dot-separated list of paths that this rule applies to.
13
+ * @property {function(*): boolean} applies a predicate that should return true if this rule applies
14
+ * (and the transformation defined herein should be applied). The arguments are those passed to the transformation function.
15
+ * @property {name} a name for the rule; used to debounce calls to `applies` (and avoid excessive logging):
16
+ * if a rule with the same name was already found to apply (or not), this one will (or won't) as well.
17
+ */
18
+
19
+ /**
20
+ * @typedef RedactRuleDef A rule that removes, or replaces, values from an object (modifications are done in-place).
21
+ * @augments TransformationRuleDef
22
+ * @property {function(*): *} get? substitution functions for values that should be redacted;
23
+ * takes in the original (unredacted) value as an input, and returns a substitute to use in the redacted
24
+ * version. If it returns undefined, or this option is omitted, protected paths will be removed
25
+ * from the redacted object.
26
+ */
27
+
28
+ /**
29
+ * @param {RedactRuleDef} ruleDef
30
+ * @return {TransformationRule}
31
+ */
32
+ export function redactRule(ruleDef) {
33
+ return Object.assign({
34
+ get() {},
35
+ run(root, path, object, property, applies) {
36
+ const val = object && object[property];
37
+ if (isData(val) && applies()) {
38
+ const repl = this.get(val);
39
+ if (repl === undefined) {
40
+ delete object[property];
41
+ } else {
42
+ object[property] = repl;
43
+ }
44
+ }
45
+ }
46
+ }, ruleDef)
47
+ }
48
+
49
+ /**
50
+ * @typedef TransformationRule
51
+ * @augments TransformationRuleDef
52
+ * @property {function} run rule logic - see `redactRule` for an example.
53
+ */
54
+
55
+ /**
56
+ * @typedef {Function} TransformationFunction
57
+ * @param object object to transform
58
+ * @param ...args arguments to pass down to rule's `apply` methods.
59
+ */
60
+
61
+ /**
62
+ * Return a transformation function that will apply the given rules to an object.
63
+ *
64
+ * @param {Array[TransformationRule]} rules
65
+ * @return {TransformationFunction}
66
+ */
67
+ export function objectTransformer(rules) {
68
+ rules.forEach(rule => {
69
+ rule.paths = rule.paths.map((path) => {
70
+ const parts = path.split('.');
71
+ const tail = parts.pop();
72
+ return [parts.length > 0 ? parts.join('.') : null, tail]
73
+ })
74
+ })
75
+ return function applyTransform(session, obj, ...args) {
76
+ const result = [];
77
+ rules.forEach(rule => {
78
+ if (session[rule.name] === false) return;
79
+ for (const [head, tail] of rule.paths) {
80
+ const parent = head == null ? obj : deepAccess(obj, head);
81
+ result.push(rule.run(obj, head, parent, tail, () => {
82
+ if (!session.hasOwnProperty(rule.name)) {
83
+ session[rule.name] = !!rule.applies(...args);
84
+ }
85
+ return session[rule.name]
86
+ }))
87
+ if (session[rule.name] === false) return;
88
+ }
89
+ })
90
+ return result.filter(el => el != null);
91
+ }
92
+ }
93
+
94
+ export function isData(val) {
95
+ return val != null && (typeof val !== 'object' || Object.keys(val).length > 0)
96
+ }
97
+
98
+ export function appliesWhenActivityDenied(activity, isAllowed = isActivityAllowed) {
99
+ return function applies(params) {
100
+ return !isAllowed(activity, params);
101
+ };
102
+ }
103
+
104
+ function bidRequestTransmitRules(isAllowed = isActivityAllowed) {
105
+ return [
106
+ {
107
+ name: ACTIVITY_TRANSMIT_EIDS,
108
+ paths: ['userId', 'userIdAsEids'],
109
+ applies: appliesWhenActivityDenied(ACTIVITY_TRANSMIT_EIDS, isAllowed),
110
+ }
111
+ ].map(redactRule)
112
+ }
113
+
114
+ export function ortb2TransmitRules(isAllowed = isActivityAllowed) {
115
+ return [
116
+ {
117
+ name: ACTIVITY_TRANSMIT_UFPD,
118
+ paths: ORTB_UFPD_PATHS,
119
+ applies: appliesWhenActivityDenied(ACTIVITY_TRANSMIT_UFPD, isAllowed),
120
+ },
121
+ {
122
+ name: ACTIVITY_TRANSMIT_EIDS,
123
+ paths: ORTB_EIDS_PATHS,
124
+ applies: appliesWhenActivityDenied(ACTIVITY_TRANSMIT_EIDS, isAllowed),
125
+ },
126
+ {
127
+ name: ACTIVITY_TRANSMIT_PRECISE_GEO,
128
+ paths: ORTB_GEO_PATHS,
129
+ applies: appliesWhenActivityDenied(ACTIVITY_TRANSMIT_PRECISE_GEO, isAllowed),
130
+ get(val) {
131
+ return Math.round((val + Number.EPSILON) * 100) / 100;
132
+ }
133
+ }
134
+ ].map(redactRule);
135
+ }
136
+
137
+ export function redactorFactory(isAllowed = isActivityAllowed) {
138
+ const redactOrtb2 = objectTransformer(ortb2TransmitRules(isAllowed));
139
+ const redactBidRequest = objectTransformer(bidRequestTransmitRules(isAllowed));
140
+ return function redactor(params) {
141
+ const session = {};
142
+ return {
143
+ ortb2(obj) { redactOrtb2(session, obj, params); return obj },
144
+ bidRequest(obj) { redactBidRequest(session, obj, params); return obj }
145
+ }
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Returns an object that can redact other privacy-sensitive objects according
151
+ * to activity rules.
152
+ *
153
+ * @param {{}} params activity parameters to use for activity checks
154
+ * @return {{ortb2: function({}): {}, bidRequest: function({}): {}}} methods
155
+ * that can redact disallowed data from ORTB2 and/or bid request objects.
156
+ */
157
+ export const redactor = redactorFactory();