From dd2e4af88ff6365bc96d7375a886b019cd5272fd Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Mon, 13 May 2024 10:00:02 -0700 Subject: [PATCH 1/3] Validate native ortb.asset.id --- package-lock.json | 2 +- src/prebid.js | 5 ++++ test/spec/unit/pbjs_api_spec.js | 47 +++++++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5198c143442..2e1f5d8f821 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "8.48.0-pre", + "version": "8.49.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", diff --git a/src/prebid.js b/src/prebid.js index 7f2d8798e2a..6dcf9175d3c 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -142,6 +142,11 @@ function validateNativeMediaType(adUnit) { const native = validatedAdUnit.mediaTypes.native; // if native assets are specified in OpenRTB format, remove legacy assets and print a warn. if (native.ortb) { + if (native.ortb.assets?.some(asset => !isNumber(asset.id) || asset.id < 0)) { + logError(`Native asset ID must be a nonnegative integer`, adUnit); + delete validatedAdUnit.mediaTypes.native; + return validatedAdUnit; + } const legacyNativeKeys = Object.keys(NATIVE_KEYS).filter(key => NATIVE_KEYS[key].includes('hb_native_')); const nativeKeys = Object.keys(native); const intersection = nativeKeys.filter(nativeKey => legacyNativeKeys.includes(nativeKey)); diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index deb80873cfa..61d76b46deb 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -1,33 +1,32 @@ import { + createBidReceived, getAdServerTargeting, + getAdUnits, getBidRequests, getBidResponses, getBidResponsesFromAPI, getTargetingKeys, - getTargetingKeysBidLandscape, - getAdUnits, - createBidReceived + getTargetingKeysBidLandscape } from 'test/fixtures/fixtures.js'; -import { auctionManager, newAuctionManager } from 'src/auctionManager.js'; -import { targeting, newTargeting, filters } from 'src/targeting.js'; -import { config as configObj } from 'src/config.js'; +import {auctionManager, newAuctionManager} from 'src/auctionManager.js'; +import {filters, newTargeting, targeting} from 'src/targeting.js'; +import {config as configObj} from 'src/config.js'; import * as ajaxLib from 'src/ajax.js'; import * as auctionModule from 'src/auction.js'; -import { registerBidder } from 'src/adapters/bidderFactory.js'; -import {resizeRemoteCreative} from 'src/secureCreatives.js'; +import {resetAuctionState} from 'src/auction.js'; +import {registerBidder} from 'src/adapters/bidderFactory.js'; import {find} from 'src/polyfill.js'; import * as pbjsModule from 'src/prebid.js'; +import $$PREBID_GLOBAL$$ from 'src/prebid.js'; import {hook} from '../../../src/hook.js'; import {reset as resetDebugging} from '../../../src/debugging.js'; -import $$PREBID_GLOBAL$$ from 'src/prebid.js'; -import {resetAuctionState} from 'src/auction.js'; import {stubAuctionIndex} from '../../helpers/indexStub.js'; import {createBid} from '../../../src/bidfactory.js'; import {enrichFPD} from '../../../src/fpd/enrichment.js'; import {mockFpdEnrichments} from '../../helpers/fpd.js'; import {generateUUID} from '../../../src/utils.js'; import {getCreativeRenderer} from '../../../src/creativeRenderers.js'; -import { BID_STATUS, EVENTS, GRANULARITY_OPTIONS, TARGETING_KEYS } from 'src/constants.js'; +import {BID_STATUS, EVENTS, GRANULARITY_OPTIONS, TARGETING_KEYS} from 'src/constants.js'; var assert = require('chai').assert; var expect = require('chai').expect; @@ -2475,6 +2474,32 @@ describe('Unit: Prebid Module', function () { } }); + if (FEATURES.NATIVE) { + Object.entries({ + missing: {}, + negative: {id: -1}, + NaN: {id: 'garbage'} + }).forEach(([t, props]) => { + it(`should reject native ortb when asset ID is ${t}`, () => { + const adUnit = { + code: 'au', + mediaTypes: { + native: { + ortb: { + assets: [props] + } + } + }, + bids: [{bidder: 'appnexus'}] + }; + $$PREBID_GLOBAL$$.requestBids({ + adUnits: [adUnit] + }); + expect(auctionArgs.adUnits[0].bids.length).to.equal(0); + }) + }) + } + it('should throw error message and remove adUnit if adUnit.bids is not defined correctly', function () { const adUnits = [{ code: 'ad-unit-1', From 935e4ad93e480d2d6fd01d1b2781410a8240a515 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Mon, 13 May 2024 10:27:36 -0700 Subject: [PATCH 2/3] deprecate native sendTargetingKeys / types --- src/prebid.js | 22 +++++++++++++++++++--- test/spec/unit/pbjs_api_spec.js | 22 +++++++++++++++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/prebid.js b/src/prebid.js index 6dcf9175d3c..cad3f65fe13 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -138,13 +138,27 @@ function validateVideoMediaType(adUnit) { } function validateNativeMediaType(adUnit) { + function err(msg) { + logError(`Error in adUnit "${adUnit.code}": ${msg}. Removing native request from ad unit`, adUnit); + delete validatedAdUnit.mediaTypes.native; + return validatedAdUnit; + } + function checkDeprecated(onDeprecated) { + for (const key of ['sendTargetingKeys', 'types']) { + if (native.hasOwnProperty(key)) { + const res = onDeprecated(key); + if (res) return res; + } + } + } const validatedAdUnit = deepClone(adUnit); const native = validatedAdUnit.mediaTypes.native; // if native assets are specified in OpenRTB format, remove legacy assets and print a warn. if (native.ortb) { - if (native.ortb.assets?.some(asset => !isNumber(asset.id) || asset.id < 0)) { - logError(`Native asset ID must be a nonnegative integer`, adUnit); - delete validatedAdUnit.mediaTypes.native; + if (native.ortb.assets?.some(asset => !isNumber(asset.id) || asset.id < 0 || asset.id % 1 !== 0)) { + return err('native asset ID must be a nonnegative integer'); + } + if (checkDeprecated(key => err(`ORTB native requests cannot specify "${key}"`))) { return validatedAdUnit; } const legacyNativeKeys = Object.keys(NATIVE_KEYS).filter(key => NATIVE_KEYS[key].includes('hb_native_')); @@ -154,6 +168,8 @@ function validateNativeMediaType(adUnit) { logError(`when using native OpenRTB format, you cannot use legacy native properties. Deleting ${intersection} keys from request.`); intersection.forEach(legacyKey => delete validatedAdUnit.mediaTypes.native[legacyKey]); } + } else { + checkDeprecated(key => `mediaTypes.native.${key} is deprecated, consider using native ORTB instead`, adUnit); } if (native.image && native.image.sizes && !Array.isArray(native.image.sizes)) { logError('Please use an array of sizes for native.image.sizes field. Removing invalid mediaTypes.native.image.sizes property from request.'); diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 61d76b46deb..5e833dc81b6 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -2478,6 +2478,7 @@ describe('Unit: Prebid Module', function () { Object.entries({ missing: {}, negative: {id: -1}, + 'not an integer': {id: 1.23}, NaN: {id: 'garbage'} }).forEach(([t, props]) => { it(`should reject native ortb when asset ID is ${t}`, () => { @@ -2496,8 +2497,27 @@ describe('Unit: Prebid Module', function () { adUnits: [adUnit] }); expect(auctionArgs.adUnits[0].bids.length).to.equal(0); + }); + }); + + ['sendTargetingKeys', 'types'].forEach(key => { + it(`should reject native that includes both ortb and ${key}`, () => { + const adUnit = { + code: 'au', + mediaTypes: { + native: { + ortb: {}, + [key]: {} + } + }, + bids: [{bidder: 'appnexus'}] + }; + $$PREBID_GLOBAL$$.requestBids({ + adUnits: [adUnit] + }); + expect(auctionArgs.adUnits[0].bids.length).to.equal(0); }) - }) + }); } it('should throw error message and remove adUnit if adUnit.bids is not defined correctly', function () { From 48b3d891a8a3cf58e0470187c4e841ffe12cecf6 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Mon, 13 May 2024 10:36:28 -0700 Subject: [PATCH 3/3] undo package-lock changes --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 2e1f5d8f821..5198c143442 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "8.49.0-pre", + "version": "8.48.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7",