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
@@ -0,0 +1,95 @@
1
+ import {prefixLog} from '../utils.js';
2
+ import {ACTIVITY_PARAM_COMPONENT} from './params.js';
3
+
4
+ export function ruleRegistry(logger = prefixLog('Activity control:')) {
5
+ const registry = {};
6
+
7
+ function getRules(activity) {
8
+ return registry[activity] = registry[activity] || [];
9
+ }
10
+
11
+ function runRule(activity, name, rule, params) {
12
+ let res;
13
+ try {
14
+ res = rule(params);
15
+ } catch (e) {
16
+ logger.logError(`Exception in rule ${name} for '${activity}'`, e);
17
+ res = {allow: false, reason: e};
18
+ }
19
+ return res && Object.assign({activity, name, component: params[ACTIVITY_PARAM_COMPONENT]}, res);
20
+ }
21
+
22
+ const dupes = {};
23
+ const DEDUPE_INTERVAL = 1000;
24
+
25
+ function logResult({activity, name, allow, reason, component}) {
26
+ const msg = `${name} ${allow ? 'allowed' : 'denied'} '${activity}' for '${component}'${reason ? ':' : ''}`;
27
+ const deduping = dupes.hasOwnProperty(msg);
28
+ if (deduping) {
29
+ clearTimeout(dupes[msg]);
30
+ }
31
+ dupes[msg] = setTimeout(() => delete dupes[msg], DEDUPE_INTERVAL);
32
+ if (!deduping) {
33
+ const parts = [msg];
34
+ reason && parts.push(reason);
35
+ (allow ? logger.logInfo : logger.logWarn).apply(logger, parts);
36
+ }
37
+ }
38
+
39
+ return [
40
+ /**
41
+ * Register an activity control rule.
42
+ *
43
+ * @param {string} activity activity name - set is defined in `activities.js`
44
+ * @param {string} ruleName a name for this rule; used for logging.
45
+ * @param {function({}): {allow: boolean, reason?: string}} rule definition function. Takes in activity
46
+ * parameters as a single map; MAY return an object {allow, reason}, where allow is true/false,
47
+ * and reason is an optional message used for logging.
48
+ *
49
+ * {allow: true} will allow this activity AS LONG AS no other rules with same or higher priority return {allow: false};
50
+ * {allow: false} will deny this activity AS LONG AS no other rules with higher priority return {allow: true};
51
+ * returning null/undefined has no effect - the decision is left to other rules.
52
+ * If no rule returns an allow value, the default is to allow the activity.
53
+ *
54
+ * @param {number} priority rule priority; lower number means higher priority
55
+ * @returns {function(void): void} a function that unregisters the rule when called.
56
+ */
57
+ function registerActivityControl(activity, ruleName, rule, priority = 10) {
58
+ const rules = getRules(activity);
59
+ const pos = rules.findIndex(([itemPriority]) => priority < itemPriority);
60
+ const entry = [priority, ruleName, rule];
61
+ rules.splice(pos < 0 ? rules.length : pos, 0, entry);
62
+ return function () {
63
+ const idx = rules.indexOf(entry);
64
+ if (idx >= 0) rules.splice(idx, 1);
65
+ }
66
+ },
67
+ /**
68
+ * Test whether an activity is allowed.
69
+ *
70
+ * @param {string} activity activity name
71
+ * @param {{}} params activity parameters; should be generated through the `activityParams` utility.
72
+ * @return {boolean} true for allow, false for deny.
73
+ */
74
+ function isActivityAllowed(activity, params) {
75
+ let lastPriority, foundAllow;
76
+ for (const [priority, name, rule] of getRules(activity)) {
77
+ if (lastPriority !== priority && foundAllow) break;
78
+ lastPriority = priority;
79
+ const ruleResult = runRule(activity, name, rule, params);
80
+ if (ruleResult) {
81
+ if (!ruleResult.allow) {
82
+ logResult(ruleResult);
83
+ return false;
84
+ } else {
85
+ foundAllow = ruleResult;
86
+ }
87
+ }
88
+ }
89
+ foundAllow && logResult(foundAllow);
90
+ return true;
91
+ }
92
+ ];
93
+ }
94
+
95
+ export const [registerActivityControl, isActivityAllowed] = ruleRegistry();
@@ -31,18 +31,28 @@ import {hook} from './hook.js';
31
31
  import {find, includes} from './polyfill.js';
32
32
  import {adunitCounter} from './adUnits.js';
33
33
  import {getRefererInfo} from './refererDetection.js';
34
- import {GdprConsentHandler, UspConsentHandler, GppConsentHandler, GDPR_GVLIDS} from './consentHandler.js';
34
+ import {GDPR_GVLIDS, GdprConsentHandler, GppConsentHandler, UspConsentHandler} from './consentHandler.js';
35
35
  import * as events from './events.js';
36
36
  import CONSTANTS from './constants.json';
37
37
  import {useMetrics} from './utils/perfMetrics.js';
38
38
  import {auctionManager} from './auctionManager.js';
39
- import {MODULE_TYPE_ANALYTICS, MODULE_TYPE_BIDDER} from './activities/modules.js';
39
+ import {MODULE_TYPE_ANALYTICS, MODULE_TYPE_BIDDER, MODULE_TYPE_PREBID} from './activities/modules.js';
40
+ import {isActivityAllowed} from './activities/rules.js';
41
+ import {ACTIVITY_FETCH_BIDS, ACTIVITY_REPORT_ANALYTICS} from './activities/activities.js';
42
+ import {ACTIVITY_PARAM_ANL_CONFIG, ACTIVITY_PARAM_S2S_NAME, activityParamsBuilder} from './activities/params.js';
43
+ import {redactor} from './activities/redactor.js';
40
44
 
45
+ const PBS_ADAPTER_NAME = 'pbsBidAdapter';
41
46
  export const PARTITIONS = {
42
47
  CLIENT: 'client',
43
48
  SERVER: 'server'
44
49
  }
45
50
 
51
+ export const dep = {
52
+ isAllowed: isActivityAllowed,
53
+ redact: redactor
54
+ }
55
+
46
56
  let adapterManager = {};
47
57
 
48
58
  let _bidderRegistry = adapterManager.bidderRegistry = {};
@@ -57,6 +67,8 @@ config.getConfig('s2sConfig', config => {
57
67
 
58
68
  var _analyticsRegistry = {};
59
69
 
70
+ const activityParams = activityParamsBuilder((alias) => adapterManager.resolveAlias(alias));
71
+
60
72
  /**
61
73
  * @typedef {object} LabelDescriptor
62
74
  * @property {boolean} labelAll describes whether or not this object expects all labels to match, or any label to match
@@ -139,7 +151,7 @@ function getAdUnitCopyForPrebidServer(adUnits, s2sConfig) {
139
151
 
140
152
  adUnitsCopy.forEach((adUnit) => {
141
153
  // filter out client side bids
142
- const s2sBids = adUnit.bids.filter((b) => b.module === 'pbsBidAdapter' && b.params?.configName === s2sConfig.configName);
154
+ const s2sBids = adUnit.bids.filter((b) => b.module === PBS_ADAPTER_NAME && b.params?.configName === s2sConfig.configName);
143
155
  if (s2sBids.length === 1) {
144
156
  adUnit.s2sBid = s2sBids[0];
145
157
  hasModuleBids = true;
@@ -237,6 +249,10 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a
237
249
  if (FEATURES.NATIVE) {
238
250
  decorateAdUnitsWithNativeParams(adUnits);
239
251
  }
252
+
253
+ // filter out bidders that cannot participate in the auction
254
+ adUnits.forEach(au => au.bids = au.bids.filter((bid) => !bid.bidder || dep.isAllowed(ACTIVITY_FETCH_BIDS, activityParams(MODULE_TYPE_BIDDER, bid.bidder))))
255
+
240
256
  adUnits = setupAdUnitMediaTypes(adUnits, labels);
241
257
 
242
258
  let {[PARTITIONS.CLIENT]: clientBidders, [PARTITIONS.SERVER]: serverBidders} = partitionBidders(adUnits, _s2sConfigs);
@@ -252,14 +268,24 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a
252
268
  const bidderOrtb2 = ortb2Fragments.bidder || {};
253
269
 
254
270
  function addOrtb2(bidderRequest) {
255
- const fpd = Object.freeze(mergeDeep({}, ortb2, bidderOrtb2[bidderRequest.bidderCode]));
271
+ const redact = dep.redact(activityParams(MODULE_TYPE_BIDDER, bidderRequest.bidderCode));
272
+ const fpd = Object.freeze(redact.ortb2(mergeDeep({}, ortb2, bidderOrtb2[bidderRequest.bidderCode])));
256
273
  bidderRequest.ortb2 = fpd;
257
- bidderRequest.bids.forEach((bid) => bid.ortb2 = fpd);
274
+ bidderRequest.bids = bidderRequest.bids.map((bid) => {
275
+ bid.ortb2 = fpd;
276
+ return redact.bidRequest(bid);
277
+ })
258
278
  return bidderRequest;
259
279
  }
260
280
 
281
+ function isS2SAllowed(s2sConfig) {
282
+ return dep.isAllowed(ACTIVITY_FETCH_BIDS, activityParams(MODULE_TYPE_PREBID, PBS_ADAPTER_NAME, {
283
+ [ACTIVITY_PARAM_S2S_NAME]: s2sConfig.configName
284
+ }));
285
+ }
286
+
261
287
  _s2sConfigs.forEach(s2sConfig => {
262
- if (s2sConfig && s2sConfig.enabled) {
288
+ if (s2sConfig && s2sConfig.enabled && isS2SAllowed(s2sConfig)) {
263
289
  let {adUnits: adUnitsS2SCopy, hasModuleBids} = getAdUnitCopyForPrebidServer(adUnits, s2sConfig);
264
290
 
265
291
  // uniquePbsTid is so we know which server to send which bids to during the callBids function
@@ -338,7 +364,6 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a
338
364
  bidRequest['gppConsent'] = gppDataHandler.getConsentData();
339
365
  }
340
366
  });
341
-
342
367
  return bidRequests;
343
368
  }, 'makeBidRequests');
344
369
 
@@ -529,6 +554,16 @@ adapterManager.aliasBidAdapter = function (bidderCode, alias, options) {
529
554
  }
530
555
  };
531
556
 
557
+ adapterManager.resolveAlias = function (alias) {
558
+ let code = alias;
559
+ let visited;
560
+ while (_aliasRegistry[code] && (!visited || !visited.has(code))) {
561
+ code = _aliasRegistry[code];
562
+ (visited = visited || new Set()).add(code);
563
+ }
564
+ return code;
565
+ }
566
+
532
567
  adapterManager.registerAnalyticsAdapter = function ({adapter, code, gvlid}) {
533
568
  if (adapter && code) {
534
569
  if (typeof adapter.enableAnalytics === 'function') {
@@ -552,7 +587,9 @@ adapterManager.enableAnalytics = function (config) {
552
587
  _each(config, adapterConfig => {
553
588
  const entry = _analyticsRegistry[adapterConfig.provider];
554
589
  if (entry && entry.adapter) {
555
- entry.adapter.enableAnalytics(adapterConfig);
590
+ if (dep.isAllowed(ACTIVITY_REPORT_ANALYTICS, activityParams(MODULE_TYPE_ANALYTICS, adapterConfig.provider, {[ACTIVITY_PARAM_ANL_CONFIG]: adapterConfig}))) {
591
+ entry.adapter.enableAnalytics(adapterConfig);
592
+ }
556
593
  } else {
557
594
  logError(`Prebid Error: no analytics adapter found in registry for '${adapterConfig.provider}'.`);
558
595
  }
package/src/adloader.js CHANGED
@@ -22,7 +22,8 @@ const _approvedLoadExternalJSList = [
22
22
  'improvedigital',
23
23
  'aaxBlockmeter',
24
24
  'confiant',
25
- 'arcspan'
25
+ 'arcspan',
26
+ 'clean.io'
26
27
  ]
27
28
 
28
29
  /**
@@ -1,7 +1,7 @@
1
1
  import {memoize, timestamp} from '../utils.js';
2
2
  import {getCoreStorageManager} from '../storageManager.js';
3
3
 
4
- export const coreStorage = getCoreStorageManager();
4
+ export const coreStorage = getCoreStorageManager('fpdEnrichment');
5
5
 
6
6
  /**
7
7
  * Find the root domain by testing for the topmost domain that will allow setting cookies.
package/src/native.js CHANGED
@@ -556,6 +556,21 @@ export function toOrtbNativeRequest(legacyNativeAssets) {
556
556
  return ortb;
557
557
  }
558
558
 
559
+ /**
560
+ * Greatest common divisor between two positive integers
561
+ * https://en.wikipedia.org/wiki/Euclidean_algorithm
562
+ */
563
+ function gcd(a, b) {
564
+ while (a && b && a !== b) {
565
+ if (a > b) {
566
+ a = a - b;
567
+ } else {
568
+ b = b - a;
569
+ }
570
+ }
571
+ return a || b;
572
+ }
573
+
559
574
  /**
560
575
  * This function converts an OpenRTB native request object to Prebid proprietary
561
576
  * format. The purpose of this function is to help adapters to handle the
@@ -584,12 +599,13 @@ export function fromOrtbNativeRequest(openRTBRequest) {
584
599
  if (asset.img.w && asset.img.h) {
585
600
  image.sizes = [asset.img.w, asset.img.h];
586
601
  } else if (asset.img.wmin && asset.img.hmin) {
587
- image.aspect_ratios = {
602
+ const scale = gcd(asset.img.wmin, asset.img.hmin)
603
+ image.aspect_ratios = [{
588
604
  min_width: asset.img.wmin,
589
605
  min_height: asset.img.hmin,
590
- ratio_width: asset.img.wmin,
591
- ratio_height: asset.img.hmin
592
- }
606
+ ratio_width: asset.img.wmin / scale,
607
+ ratio_height: asset.img.hmin / scale
608
+ }]
593
609
  }
594
610
 
595
611
  if (asset.img.type === NATIVE_IMAGE_TYPES.MAIN) {
package/src/prebid.js CHANGED
@@ -1004,7 +1004,7 @@ if (FEATURES.VIDEO) {
1004
1004
  const bids = fetchReceivedBids(markBidRequest, 'Improper use of markWinningBidAsUsed. It needs an adUnitCode or an adId to function.');
1005
1005
 
1006
1006
  if (bids.length > 0) {
1007
- bids[0].status = CONSTANTS.BID_STATUS.RENDERED;
1007
+ auctionManager.addWinningBid(bids[0]);
1008
1008
  }
1009
1009
  }
1010
1010
  }
@@ -1,7 +1,17 @@
1
- import {hook} from './hook.js';
2
- import {checkCookieSupport, hasDeviceAccess, logError, logInfo} from './utils.js';
3
- import {bidderSettings as defaultBidderSettings} from './bidderSettings.js';
4
- import {MODULE_TYPE_BIDDER, MODULE_TYPE_CORE} from './activities/modules.js';
1
+ import {checkCookieSupport, hasDeviceAccess, logError} from './utils.js';
2
+ import {bidderSettings} from './bidderSettings.js';
3
+ import {MODULE_TYPE_BIDDER, MODULE_TYPE_PREBID} from './activities/modules.js';
4
+ import {isActivityAllowed, registerActivityControl} from './activities/rules.js';
5
+ import {
6
+ ACTIVITY_PARAM_ADAPTER_CODE,
7
+ ACTIVITY_PARAM_COMPONENT_TYPE,
8
+ ACTIVITY_PARAM_STORAGE_TYPE
9
+ } from './activities/params.js';
10
+
11
+ import {ACTIVITY_ACCESS_DEVICE} from './activities/activities.js';
12
+ import {config} from './config.js';
13
+ import adapterManager from './adapterManager.js';
14
+ import {activityParams} from './activities/activityParams.js';
5
15
 
6
16
  export const STORAGE_TYPE_LOCALSTORAGE = 'html5';
7
17
  export const STORAGE_TYPE_COOKIES = 'cookie';
@@ -11,40 +21,19 @@ export let storageCallbacks = [];
11
21
  /*
12
22
  * Storage manager constructor. Consumers should prefer one of `getStorageManager` or `getCoreStorageManager`.
13
23
  */
14
- export function newStorageManager({moduleName, moduleType} = {}, {bidderSettings = defaultBidderSettings} = {}) {
15
- function isBidderAllowed(storageType) {
16
- if (moduleType !== MODULE_TYPE_BIDDER) {
17
- return true;
18
- }
19
- const storageAllowed = bidderSettings.get(moduleName, 'storageAllowed');
20
- if (!storageAllowed || storageAllowed === true) return !!storageAllowed;
21
- if (Array.isArray(storageAllowed)) return storageAllowed.some((e) => e === storageType);
22
- return storageAllowed === storageType;
23
- }
24
-
24
+ export function newStorageManager({moduleName, moduleType} = {}, {isAllowed = isActivityAllowed} = {}) {
25
25
  function isValid(cb, storageType) {
26
- if (!isBidderAllowed(storageType)) {
27
- logInfo(`bidderSettings denied access to device storage for bidder '${moduleName}'`);
28
- const result = {valid: false};
29
- return cb(result);
30
- } else {
31
- let value;
32
- let hookDetails = {
33
- hasEnforcementHook: false
34
- }
35
- validateStorageEnforcement(moduleType, moduleName, hookDetails, function(result) {
36
- if (result && result.hasEnforcementHook) {
37
- value = cb(result);
38
- } else {
39
- let result = {
40
- hasEnforcementHook: false,
41
- valid: hasDeviceAccess()
42
- }
43
- value = cb(result);
44
- }
45
- });
46
- return value;
26
+ let mod = moduleName;
27
+ const curBidder = config.getCurrentBidder();
28
+ if (curBidder && moduleType === MODULE_TYPE_BIDDER && adapterManager.aliasRegistry[curBidder] === moduleName) {
29
+ mod = curBidder;
47
30
  }
31
+ const result = {
32
+ valid: isAllowed(ACTIVITY_ACCESS_DEVICE, activityParams(moduleType, mod, {
33
+ [ACTIVITY_PARAM_STORAGE_TYPE]: storageType
34
+ }))
35
+ };
36
+ return cb(result);
48
37
  }
49
38
 
50
39
  function schedule(operation, storageType, done) {
@@ -228,13 +217,6 @@ export function newStorageManager({moduleName, moduleType} = {}, {bidderSettings
228
217
  }
229
218
  }
230
219
 
231
- /**
232
- * This hook validates the storage enforcement if gdprEnforcement module is included
233
- */
234
- export const validateStorageEnforcement = hook('async', function(moduleType, moduleName, hookDetails, callback) {
235
- callback(hookDetails);
236
- }, 'validateStorageEnforcement');
237
-
238
220
  /**
239
221
  * Get a storage manager for a particular module.
240
222
  *
@@ -262,9 +244,40 @@ export function getStorageManager({moduleType, moduleName, bidderCode} = {}) {
262
244
  * @param {string} moduleName Module name
263
245
  */
264
246
  export function getCoreStorageManager(moduleName) {
265
- return newStorageManager({moduleName: moduleName, moduleType: MODULE_TYPE_CORE});
247
+ return newStorageManager({moduleName: moduleName, moduleType: MODULE_TYPE_PREBID});
266
248
  }
267
249
 
250
+ /**
251
+ * Block all access to storage when deviceAccess = false
252
+ */
253
+ export function deviceAccessRule() {
254
+ if (!hasDeviceAccess()) {
255
+ return {allow: false}
256
+ }
257
+ }
258
+ registerActivityControl(ACTIVITY_ACCESS_DEVICE, 'deviceAccess config', deviceAccessRule);
259
+
260
+ /**
261
+ * By default, deny bidders accessDevice unless they enable it through bidderSettings
262
+ *
263
+ * // TODO: for backwards compat, the check is done on the adapter - rather than bidder's code.
264
+ */
265
+ export function storageAllowedRule(params, bs = bidderSettings) {
266
+ if (params[ACTIVITY_PARAM_COMPONENT_TYPE] !== MODULE_TYPE_BIDDER) return;
267
+ let allow = bs.get(params[ACTIVITY_PARAM_ADAPTER_CODE], 'storageAllowed');
268
+ if (!allow || allow === true) {
269
+ allow = !!allow
270
+ } else {
271
+ const storageType = params[ACTIVITY_PARAM_STORAGE_TYPE];
272
+ allow = Array.isArray(allow) ? allow.some((e) => e === storageType) : allow === storageType;
273
+ }
274
+ if (!allow) {
275
+ return {allow};
276
+ }
277
+ }
278
+
279
+ registerActivityControl(ACTIVITY_ACCESS_DEVICE, 'bidderSettings.*.storageAllowed', storageAllowedRule);
280
+
268
281
  export function resetData() {
269
282
  storageCallbacks = [];
270
283
  }
package/src/userSync.js CHANGED
@@ -5,6 +5,15 @@ import {
5
5
  import { config } from './config.js';
6
6
  import {includes} from './polyfill.js';
7
7
  import { getCoreStorageManager } from './storageManager.js';
8
+ import {isActivityAllowed, registerActivityControl} from './activities/rules.js';
9
+ import {ACTIVITY_SYNC_USER} from './activities/activities.js';
10
+ import {
11
+ ACTIVITY_PARAM_COMPONENT_NAME,
12
+ ACTIVITY_PARAM_COMPONENT_TYPE,
13
+ ACTIVITY_PARAM_SYNC_TYPE, ACTIVITY_PARAM_SYNC_URL
14
+ } from './activities/params.js';
15
+ import {MODULE_TYPE_BIDDER} from './activities/modules.js';
16
+ import {activityParams} from './activities/activityParams.js';
8
17
 
9
18
  export const USERSYNC_DEFAULT_CONFIG = {
10
19
  syncEnabled: true,
@@ -29,10 +38,10 @@ const storage = getCoreStorageManager('usersync');
29
38
  /**
30
39
  * Factory function which creates a new UserSyncPool.
31
40
  *
32
- * @param {UserSyncDependencies} userSyncDependencies Configuration options and dependencies which the
41
+ * @param {} deps Configuration options and dependencies which the
33
42
  * UserSync object needs in order to behave properly.
34
43
  */
35
- export function newUserSync(userSyncDependencies) {
44
+ export function newUserSync(deps) {
36
45
  let publicApi = {};
37
46
  // A queue of user syncs for each adapter
38
47
  // Let getDefaultQueue() set the defaults
@@ -50,7 +59,7 @@ export function newUserSync(userSyncDependencies) {
50
59
  };
51
60
 
52
61
  // Use what is in config by default
53
- let usConfig = userSyncDependencies.config;
62
+ let usConfig = deps.config;
54
63
  // Update if it's (re)set
55
64
  config.getConfig('userSync', (conf) => {
56
65
  // Added this logic for https://github.com/prebid/Prebid.js/issues/4864
@@ -70,6 +79,19 @@ export function newUserSync(userSyncDependencies) {
70
79
  usConfig = Object.assign(usConfig, conf.userSync);
71
80
  });
72
81
 
82
+ deps.regRule(ACTIVITY_SYNC_USER, 'userSync config', (params) => {
83
+ if (!usConfig.syncEnabled) {
84
+ return {allow: false, reason: 'syncs are disabled'}
85
+ }
86
+ if (params[ACTIVITY_PARAM_COMPONENT_TYPE] === MODULE_TYPE_BIDDER) {
87
+ const syncType = params[ACTIVITY_PARAM_SYNC_TYPE];
88
+ const bidder = params[ACTIVITY_PARAM_COMPONENT_NAME];
89
+ if (!publicApi.canBidderRegisterSync(syncType, bidder)) {
90
+ return {allow: false, reason: `${syncType} syncs are not enabled for ${bidder}`}
91
+ }
92
+ }
93
+ });
94
+
73
95
  /**
74
96
  * @function getDefaultQueue
75
97
  * @summary Returns the default empty queue
@@ -89,7 +111,7 @@ export function newUserSync(userSyncDependencies) {
89
111
  * @private
90
112
  */
91
113
  function fireSyncs() {
92
- if (!usConfig.syncEnabled || !userSyncDependencies.browserSupportsCookies) {
114
+ if (!usConfig.syncEnabled || !deps.browserSupportsCookies) {
93
115
  return;
94
116
  }
95
117
 
@@ -199,14 +221,14 @@ export function newUserSync(userSyncDependencies) {
199
221
  return logWarn(`Number of user syncs exceeded for "${bidder}"`);
200
222
  }
201
223
 
202
- const canBidderRegisterSync = publicApi.canBidderRegisterSync(type, bidder);
203
- if (!canBidderRegisterSync) {
204
- return logWarn(`Bidder "${bidder}" not permitted to register their "${type}" userSync pixels.`);
224
+ if (deps.isAllowed(ACTIVITY_SYNC_USER, activityParams(MODULE_TYPE_BIDDER, bidder, {
225
+ [ACTIVITY_PARAM_SYNC_TYPE]: type,
226
+ [ACTIVITY_PARAM_SYNC_URL]: url
227
+ }))) {
228
+ // the bidder's pixel has passed all checks and is allowed to register
229
+ queue[type].push([bidder, url]);
230
+ numAdapterBids = incrementAdapterBids(numAdapterBids, bidder);
205
231
  }
206
-
207
- // the bidder's pixel has passed all checks and is allowed to register
208
- queue[type].push([bidder, url]);
209
- numAdapterBids = incrementAdapterBids(numAdapterBids, bidder);
210
232
  };
211
233
 
212
234
  /**
@@ -320,6 +342,8 @@ export function newUserSync(userSyncDependencies) {
320
342
 
321
343
  export const userSync = newUserSync(Object.defineProperties({
322
344
  config: config.getConfig('userSync'),
345
+ isAllowed: isActivityAllowed,
346
+ regRule: registerActivityControl,
323
347
  }, {
324
348
  browserSupportsCookies: {
325
349
  get: function() {
@@ -329,13 +353,6 @@ export const userSync = newUserSync(Object.defineProperties({
329
353
  }
330
354
  }));
331
355
 
332
- /**
333
- * @typedef {Object} UserSyncDependencies
334
- *
335
- * @property {UserSyncConfig} config
336
- * @property {boolean} browserSupportsCookies True if the current browser supports cookies, and false otherwise.
337
- */
338
-
339
356
  /**
340
357
  * @typedef {Object} UserSyncConfig
341
358
  *
@@ -0,0 +1,138 @@
1
+ import {config} from 'src/config.js';
2
+ import {ruleRegistry} from '../../../src/activities/rules.js';
3
+ import {updateRulesFromConfig} from '../../../modules/allowActivities.js';
4
+ import {activityParams} from '../../../src/activities/activityParams.js';
5
+
6
+ describe('allowActivities config', () => {
7
+ const MODULE_TYPE = 'test'
8
+ const MODULE_NAME = 'testMod';
9
+ const ACTIVITY = 'testActivity';
10
+
11
+ let isAllowed, params;
12
+
13
+ beforeEach(() => {
14
+ let registerRule;
15
+ [registerRule, isAllowed] = ruleRegistry();
16
+ updateRulesFromConfig(registerRule);
17
+ params = activityParams(MODULE_TYPE, MODULE_NAME)
18
+ });
19
+
20
+ afterEach(() => {
21
+ config.resetConfig();
22
+ });
23
+
24
+ function setupActivityConfig(cfg) {
25
+ config.setConfig({
26
+ allowActivities: {
27
+ [ACTIVITY]: cfg
28
+ }
29
+ })
30
+ }
31
+
32
+ describe('default = false', () => {
33
+ it('should deny activites with no other rules', () => {
34
+ setupActivityConfig({
35
+ default: false
36
+ })
37
+ expect(isAllowed(ACTIVITY, {})).to.be.false;
38
+ });
39
+ it('should not deny activities that are explicitly allowed', () => {
40
+ setupActivityConfig({
41
+ default: false,
42
+ rules: [
43
+ {
44
+ condition({componentName}) {
45
+ return componentName === MODULE_NAME
46
+ },
47
+ allow: true
48
+ }
49
+ ]
50
+ })
51
+ expect(isAllowed(ACTIVITY, params)).to.be.true;
52
+ });
53
+ it('should be removable by a config update', () => {
54
+ setupActivityConfig({
55
+ default: false
56
+ });
57
+ setupActivityConfig({});
58
+ expect(isAllowed(ACTIVITY, params)).to.be.true;
59
+ })
60
+ });
61
+
62
+ describe('rules', () => {
63
+ it('are tested for their condition', () => {
64
+ setupActivityConfig({
65
+ rules: [{
66
+ condition({flag}) { return flag },
67
+ allow: false
68
+ }]
69
+ });
70
+ expect(isAllowed(ACTIVITY, params)).to.be.true;
71
+ params.flag = true;
72
+ expect(isAllowed(ACTIVITY, params)).to.be.false;
73
+ });
74
+
75
+ it('always apply if they have no condition', () => {
76
+ setupActivityConfig({
77
+ rules: [{allow: false}]
78
+ });
79
+ expect(isAllowed(ACTIVITY, params)).to.be.false;
80
+ });
81
+
82
+ it('do not choke when the condition throws', () => {
83
+ setupActivityConfig({
84
+ rules: [{
85
+ condition() {
86
+ throw new Error()
87
+ },
88
+ allow: true
89
+ }]
90
+ });
91
+ expect(isAllowed(ACTIVITY, params)).to.be.false;
92
+ });
93
+
94
+ it('does not pass private (underscored) parameters to condition', () => {
95
+ setupActivityConfig({
96
+ rules: [{
97
+ condition({_priv}) { return _priv },
98
+ allow: false
99
+ }]
100
+ });
101
+ params._priv = true;
102
+ expect(isAllowed(ACTIVITY, params)).to.be.true;
103
+ })
104
+
105
+ it('are evaluated in order of priority', () => {
106
+ setupActivityConfig({
107
+ rules: [{
108
+ priority: 1000,
109
+ allow: false
110
+ }, {
111
+ priority: 100,
112
+ allow: true
113
+ }]
114
+ });
115
+ expect(isAllowed(ACTIVITY, params)).to.be.true;
116
+ });
117
+
118
+ it('can be set with priority 0', () => {
119
+ setupActivityConfig({
120
+ rules: [{
121
+ allow: false
122
+ }, {
123
+ priority: 0,
124
+ allow: true
125
+ }]
126
+ });
127
+ expect(isAllowed(ACTIVITY, params)).to.be.true;
128
+ })
129
+
130
+ it('can be reset with a config update', () => {
131
+ setupActivityConfig({
132
+ allow: false
133
+ });
134
+ config.setConfig({allowActivities: {}});
135
+ expect(isAllowed(ACTIVITY, params)).to.be.true;
136
+ });
137
+ });
138
+ });