| // META: script=/resources/testdriver.js |
| // META: script=/resources/testdriver-vendor.js |
| // META: script=/common/utils.js |
| // META: script=resources/ba-fledge-util.sub.js |
| // META: script=resources/fledge-util.sub.js |
| // META: script=third_party/cbor-js/cbor.js |
| // META: script=/common/subset-tests.js |
| // META: timeout=long |
| // META: variant=?1-6 |
| // META: variant=?7-10 |
| // META: variant=?11-14 |
| // META: variant=?15-18 |
| // META: variant=?19-22 |
| // META: variant=?23-26 |
| // META: variant=?27-30 |
| // META: variant=?31-34 |
| // META: variant=?35-38 |
| // META: variant=?39-42 |
| // META: variant=?43-46 |
| // META: variant=?47-50 |
| // META: variant=?51-54 |
| // META: variant=?55-58 |
| // META: variant=?59-62 |
| // META: variant=?63-66 |
| // META: variant=?67-70 |
| |
| "use strict"; |
| |
| // These tests focus on the serverResponse field in AuctionConfig, e.g. |
| // auctions involving bidding and auction services. |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); |
| const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); |
| const adsArray = |
| [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; |
| await joinInterestGroup(test, uuid, {ads: adsArray}); |
| |
| const result = await navigator.getInterestGroupAdAuctionData({ |
| coordinatorOrigin: await BA.configureCoordinator(), |
| seller: window.location.origin |
| }); |
| assert_true(result.requestId !== null); |
| assert_true(result.request.length > 0); |
| |
| let decoded = await BA.decodeInterestGroupData(result.request); |
| |
| let serverResponseMsg = { |
| 'biddingGroups': {}, |
| 'adRenderURL': adsArray[0].renderURL, |
| 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, |
| 'interestGroupOwner': window.location.origin, |
| }; |
| serverResponseMsg.biddingGroups[window.location.origin] = [0]; |
| |
| let serverResponse = |
| await BA.encodeServerResponse(serverResponseMsg, decoded); |
| |
| let hashString = await BA.payloadHash(serverResponse); |
| await BA.authorizeServerResponseHashes([hashString]); |
| |
| let auctionResult = await navigator.runAdAuction({ |
| 'seller': window.location.origin, |
| 'requestId': result.requestId, |
| 'serverResponse': serverResponse, |
| 'resolveToConfig': true, |
| }); |
| expectSuccess(auctionResult); |
| createAndNavigateFencedFrame(test, auctionResult); |
| await waitForObservedRequests(uuid, [adA]); |
| }, 'Basic B&A auction'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); |
| const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); |
| const adsArray = |
| [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; |
| await joinInterestGroup(test, uuid, {ads: adsArray}); |
| |
| const result = await navigator.getInterestGroupAdAuctionData({ |
| coordinatorOrigin: await BA.configureCoordinator(), |
| seller: window.location.origin |
| }); |
| assert_true(result.requestId !== null); |
| assert_true(result.request.length > 0); |
| |
| let decoded = await BA.decodeInterestGroupData(result.request); |
| |
| let serverResponseMsg = { |
| 'nonce': uuid, |
| 'biddingGroups': {}, |
| 'adRenderURL': adsArray[0].renderURL, |
| 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, |
| 'interestGroupOwner': window.location.origin, |
| }; |
| serverResponseMsg.biddingGroups[window.location.origin] = [0]; |
| |
| let serverResponse = |
| await BA.encodeServerResponse(serverResponseMsg, decoded); |
| |
| let hashString = await BA.payloadHash(serverResponse); |
| await BA.authorizeServerResponseNonces([uuid]); |
| |
| let auctionResult = await navigator.runAdAuction({ |
| 'seller': window.location.origin, |
| 'requestId': result.requestId, |
| 'serverResponse': serverResponse, |
| 'resolveToConfig': true, |
| }); |
| expectSuccess(auctionResult); |
| createAndNavigateFencedFrame(test, auctionResult); |
| await waitForObservedRequests(uuid, [adA]); |
| }, 'Basic B&A auction - nonces'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); |
| const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); |
| const adsArray = |
| [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; |
| await joinInterestGroup(test, uuid, {ads: adsArray}); |
| |
| const result = await navigator.getInterestGroupAdAuctionData({ |
| coordinatorOrigin: await BA.configureCoordinator(), |
| seller: window.location.origin |
| }); |
| assert_true(result.requestId !== null); |
| assert_true(result.request.length > 0); |
| |
| let decoded = await BA.decodeInterestGroupData(result.request); |
| |
| let serverResponseMsg = { |
| 'biddingGroups': {}, |
| 'adRenderURL': adsArray[0].renderURL, |
| 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, |
| 'interestGroupOwner': window.location.origin, |
| }; |
| serverResponseMsg.biddingGroups[window.location.origin] = [0]; |
| |
| let serverResponse = |
| await BA.encodeServerResponse(serverResponseMsg, decoded); |
| |
| let auctionResult = await navigator.runAdAuction({ |
| 'seller': window.location.origin, |
| 'requestId': result.requestId, |
| 'serverResponse': serverResponse, |
| 'resolveToConfig': true, |
| }); |
| expectNoWinner(auctionResult); |
| }, 'Basic B&A auction - not authorized'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); |
| const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); |
| const adsArray = |
| [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; |
| await joinInterestGroup(test, uuid, {ads: adsArray}); |
| |
| const result = await navigator.getInterestGroupAdAuctionData({ |
| coordinatorOrigin: await BA.configureCoordinator(), |
| seller: window.location.origin |
| }); |
| assert_true(result.requestId !== null); |
| assert_true(result.request.length > 0); |
| |
| let decoded = await BA.decodeInterestGroupData(result.request); |
| |
| const trackSeller = createSellerReportURL(uuid); |
| const trackBuyer = createBidderReportURL(uuid); |
| // This one should still work since the server may have run an auction with |
| // components on its own. |
| const trackComponentSeller = createSellerReportURL(uuid, 'component'); |
| let serverResponseMsg = { |
| 'biddingGroups': {}, |
| 'adRenderURL': adsArray[1].renderURL, |
| 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, |
| 'interestGroupOwner': window.location.origin, |
| 'winReportingURLs': { |
| 'buyerReportingURLs': {'reportingURL': trackBuyer}, |
| 'topLevelSellerReportingURLs': {'reportingURL': trackSeller}, |
| 'componentSellerReportingURLs': {'reportingURL': trackComponentSeller} |
| } |
| }; |
| serverResponseMsg.biddingGroups[window.location.origin] = [0]; |
| |
| let serverResponse = |
| await BA.encodeServerResponse(serverResponseMsg, decoded); |
| |
| let hashString = await BA.payloadHash(serverResponse); |
| await BA.authorizeServerResponseHashes([hashString]); |
| |
| let auctionResult = await navigator.runAdAuction({ |
| 'seller': window.location.origin, |
| 'requestId': result.requestId, |
| 'serverResponse': serverResponse, |
| 'resolveToConfig': true, |
| }); |
| expectSuccess(auctionResult); |
| createAndNavigateFencedFrame(test, auctionResult); |
| await waitForObservedRequests( |
| uuid, [adB, trackBuyer, trackSeller, trackComponentSeller]); |
| }, 'Basic B&A auction with reporting URLs'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); |
| const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); |
| const adsArray = |
| [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; |
| await joinInterestGroup(test, uuid, { |
| ads: adsArray, |
| biddingLogicURL: createBiddingScriptURL({allowComponentAuction: true}) |
| }); |
| |
| const result = await navigator.getInterestGroupAdAuctionData({ |
| coordinatorOrigin: await BA.configureCoordinator(), |
| seller: window.location.origin |
| }); |
| assert_true(result.requestId !== null); |
| assert_true(result.request.length > 0); |
| |
| let decoded = await BA.decodeInterestGroupData(result.request); |
| |
| // The server-side auction uses a bid of 10, for second ad, so it should |
| // win over the client-side component auctions bid of 9. |
| let serverResponseMsg = { |
| 'biddingGroups': {}, |
| 'adRenderURL': adsArray[1].renderURL, |
| 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, |
| 'interestGroupOwner': window.location.origin, |
| 'topLevelSeller': window.location.origin, |
| 'bid': 10, |
| }; |
| serverResponseMsg.biddingGroups[window.location.origin] = [0]; |
| |
| let serverResponse = |
| await BA.encodeServerResponse(serverResponseMsg, decoded); |
| |
| let hashString = await BA.payloadHash(serverResponse); |
| await BA.authorizeServerResponseHashes([hashString]); |
| |
| let auctionConfig = { |
| seller: window.location.origin, |
| decisionLogicURL: createDecisionScriptURL(uuid), |
| interestGroupBuyers: [], |
| resolveToConfig: true, |
| componentAuctions: [ |
| { |
| seller: window.location.origin, |
| decisionLogicURL: createDecisionScriptURL(uuid), |
| interestGroupBuyers: [window.location.origin], |
| }, |
| { |
| seller: window.location.origin, |
| requestId: result.requestId, |
| serverResponse: serverResponse, |
| } |
| ] |
| }; |
| |
| let auctionResult = await navigator.runAdAuction(auctionConfig); |
| expectSuccess(auctionResult); |
| createAndNavigateFencedFrame(test, auctionResult); |
| await waitForObservedRequests(uuid, [adB]); |
| }, 'Hybrid B&A auction'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); |
| const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); |
| const adsArray = |
| [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; |
| await joinInterestGroup(test, uuid, { |
| ads: adsArray, |
| biddingLogicURL: createBiddingScriptURL({allowComponentAuction: true}) |
| }); |
| |
| const result = await navigator.getInterestGroupAdAuctionData({ |
| coordinatorOrigin: await BA.configureCoordinator(), |
| seller: window.location.origin |
| }); |
| assert_true(result.requestId !== null); |
| assert_true(result.request.length > 0); |
| |
| let decoded = await BA.decodeInterestGroupData(result.request); |
| |
| // The server-side auction uses a bid of 10, for second ad, so it should |
| // win over the client-side component auctions bid of 9. |
| const trackServerSeller = createSellerReportURL(uuid); |
| const trackBuyer = createBidderReportURL(uuid); |
| // This one shouldn't show up. |
| const trackTopLevelServerSeller = createSellerReportURL(uuid, 'top'); |
| let serverResponseMsg = { |
| 'biddingGroups': {}, |
| 'adRenderURL': adsArray[1].renderURL, |
| 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, |
| 'interestGroupOwner': window.location.origin, |
| 'topLevelSeller': window.location.origin, |
| 'bid': 10, |
| 'winReportingURLs': { |
| 'buyerReportingURLs': {'reportingURL': trackBuyer}, |
| 'componentSellerReportingURLs': {'reportingURL': trackServerSeller}, |
| 'topLevelSellerReportingURLs': {'reportingURL': trackTopLevelServerSeller} |
| } |
| }; |
| serverResponseMsg.biddingGroups[window.location.origin] = [0]; |
| |
| let serverResponse = |
| await BA.encodeServerResponse(serverResponseMsg, decoded); |
| |
| let hashString = await BA.payloadHash(serverResponse); |
| await BA.authorizeServerResponseHashes([hashString]); |
| |
| let trackTopSeller = createSellerReportURL(uuid, 'top'); |
| let trackClientSeller = createSellerReportURL(uuid, 'client'); |
| let auctionConfig = { |
| seller: window.location.origin, |
| decisionLogicURL: createDecisionScriptURL( |
| uuid, {reportResult: `sendReportTo("${trackTopSeller}")`}), |
| interestGroupBuyers: [], |
| resolveToConfig: true, |
| componentAuctions: [ |
| { |
| seller: window.location.origin, |
| decisionLogicURL: createDecisionScriptURL( |
| uuid, {reportResult: `sendReportTo("${trackClientSeller}")`}), |
| interestGroupBuyers: [window.location.origin], |
| }, |
| { |
| seller: window.location.origin, |
| requestId: result.requestId, |
| serverResponse: serverResponse, |
| } |
| ] |
| }; |
| |
| let auctionResult = await navigator.runAdAuction(auctionConfig); |
| expectSuccess(auctionResult); |
| createAndNavigateFencedFrame(test, auctionResult); |
| await waitForObservedRequests( |
| uuid, [adB, trackBuyer, trackServerSeller, trackTopSeller]); |
| }, 'Hybrid B&A auction with reporting URLs'); |
| |
| async function runFaultInjectTest(test, fault) { |
| const uuid = generateUuid(test); |
| const adA = 'https://example.org/a'; |
| const adB = 'https://example.org/b'; |
| const adsArray = |
| [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; |
| await joinInterestGroup(test, uuid, {ads: adsArray}); |
| |
| const result = await navigator.getInterestGroupAdAuctionData({ |
| coordinatorOrigin: await BA.configureCoordinator(), |
| seller: window.location.origin |
| }); |
| assert_true(result.requestId !== null); |
| assert_true(result.request.length > 0); |
| |
| let decoded = await BA.decodeInterestGroupData(result.request); |
| |
| let serverResponseMsg = { |
| 'biddingGroups': {}, |
| 'adRenderURL': adsArray[0].renderURL, |
| 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, |
| 'interestGroupOwner': window.location.origin, |
| }; |
| serverResponseMsg.biddingGroups[window.location.origin] = [0]; |
| |
| let serverResponse = |
| await BA.encodeServerResponse(serverResponseMsg, decoded, fault); |
| |
| let hashString = await BA.payloadHash(serverResponse); |
| await BA.authorizeServerResponseHashes([hashString]); |
| |
| let auctionResult = await navigator.runAdAuction({ |
| 'seller': window.location.origin, |
| 'requestId': result.requestId, |
| 'serverResponse': serverResponse, |
| 'resolveToConfig': true, |
| }); |
| expectNoWinner(auctionResult); |
| } |
| |
| subsetTest(promise_test, async test => { |
| return runFaultInjectTest(test, BA.injectCborFault); |
| }, 'Basic B&A auction - fault inject at CBOR'); |
| |
| subsetTest(promise_test, async test => { |
| return runFaultInjectTest(test, BA.injectGzipFault); |
| }, 'Basic B&A auction - fault inject at gzip'); |
| |
| subsetTest(promise_test, async test => { |
| return runFaultInjectTest(test, BA.injectFrameFault); |
| }, 'Basic B&A auction - fault inject at framing'); |
| |
| subsetTest(promise_test, async test => { |
| return runFaultInjectTest(test, BA.injectEncryptFault); |
| }, 'Basic B&A auction - fault inject at encryption'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| const adA = 'https://example.org/a'; |
| const adB = 'https://example.org/b'; |
| const adsArray = |
| [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; |
| await joinInterestGroup(test, uuid, {ads: adsArray}); |
| |
| const result = await navigator.getInterestGroupAdAuctionData({ |
| coordinatorOrigin: await BA.configureCoordinator(), |
| seller: window.location.origin |
| }); |
| assert_true(result.requestId !== null); |
| assert_true(result.request.length > 0); |
| |
| let decoded = await BA.decodeInterestGroupData(result.request); |
| |
| let serverResponseMsg = { |
| 'biddingGroups': {}, |
| 'adRenderURL': adsArray[0].renderURL, |
| 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, |
| 'interestGroupOwner': window.location.origin, |
| }; |
| serverResponseMsg.biddingGroups[window.location.origin] = [0]; |
| |
| let serverResponse = |
| await BA.encodeServerResponse(serverResponseMsg, decoded); |
| |
| // Mess up the array for a bit before computing hash to get the wrong hash, |
| // then undo. |
| serverResponse[0] ^= 0xBE; |
| let hashString = await BA.payloadHash(serverResponse); |
| await BA.authorizeServerResponseHashes([hashString]); |
| serverResponse[0] ^= 0xBE; |
| |
| let auctionResult = await navigator.runAdAuction({ |
| 'seller': window.location.origin, |
| 'requestId': result.requestId, |
| 'serverResponse': serverResponse, |
| 'resolveToConfig': true, |
| }); |
| expectNoWinner(auctionResult); |
| }, 'Basic B&A auction - Wrong authorization'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| const adA = 'https://example.org/a'; |
| const adB = 'https://example.org/b'; |
| const adsArray = |
| [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; |
| await joinInterestGroup(test, uuid, {ads: adsArray}); |
| |
| const result = await navigator.getInterestGroupAdAuctionData({ |
| coordinatorOrigin: await BA.configureCoordinator(), |
| seller: OTHER_ORIGIN1 |
| }); |
| assert_true(result.requestId !== null); |
| assert_true(result.request.length > 0); |
| |
| let decoded = await BA.decodeInterestGroupData(result.request); |
| |
| let serverResponseMsg = { |
| 'biddingGroups': {}, |
| 'adRenderURL': adsArray[0].renderURL, |
| 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, |
| 'interestGroupOwner': window.location.origin, |
| }; |
| serverResponseMsg.biddingGroups[window.location.origin] = [0]; |
| |
| let serverResponse = |
| await BA.encodeServerResponse(serverResponseMsg, decoded); |
| |
| let hashString = await BA.payloadHash(serverResponse); |
| await BA.authorizeServerResponseHashes([hashString]); |
| |
| let auctionResult = await navigator.runAdAuction({ |
| 'seller': window.location.origin, |
| 'requestId': result.requestId, |
| 'serverResponse': serverResponse, |
| 'resolveToConfig': true, |
| }); |
| expectNoWinner(auctionResult); |
| }, 'Basic B&A auction - Wrong seller'); |
| |
| subsetTest(promise_test, async test => { |
| const uuid = generateUuid(test); |
| const adA = 'https://example.org/a'; |
| const adB = 'https://example.org/b'; |
| const adsArray = |
| [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; |
| await joinInterestGroup(test, uuid, {ads: adsArray}); |
| |
| const result = await navigator.getInterestGroupAdAuctionData({ |
| coordinatorOrigin: await BA.configureCoordinator(), |
| seller: window.location.origin |
| }); |
| assert_true(result.requestId !== null); |
| assert_true(result.request.length > 0); |
| |
| let decoded = await BA.decodeInterestGroupData(result.request); |
| |
| let serverResponseMsg = { |
| 'biddingGroups': {}, |
| 'adRenderURL': adsArray[0].renderURL, |
| 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, |
| 'interestGroupOwner': window.location.origin, |
| }; |
| serverResponseMsg.biddingGroups[window.location.origin] = [0]; |
| |
| let serverResponse = |
| await BA.encodeServerResponse(serverResponseMsg, decoded); |
| |
| let hashString = await BA.payloadHash(serverResponse); |
| await BA.authorizeServerResponseHashes([hashString]); |
| |
| let auctionResult = await navigator.runAdAuction({ |
| 'seller': window.location.origin, |
| 'requestId': token(), |
| 'serverResponse': serverResponse, |
| 'resolveToConfig': true, |
| }); |
| expectNoWinner(auctionResult); |
| }, 'Basic B&A auction - Wrong request Id'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => {msg.error = {}}); |
| }, 'Basic B&A auction - response marked as error'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { |
| msg.error = 4; |
| }); |
| }, 'Basic B&A auction - nonsense error field'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => { |
| msg.error = {message: 'oh no'}; |
| }); |
| }, 'Basic B&A auction - response marked as error, with message'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => { |
| msg.error = {message: {}}; |
| }); |
| }, 'Basic B&A auction - response marked as error, with bad message'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => {msg.isChaff = true}); |
| }, 'Basic B&A auction - response marked as chaff'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ true, msg => {msg.isChaff = false}); |
| }, 'Basic B&A auction - response marked as non-chaff'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => {msg.isChaff = 'yes'}); |
| }, 'Basic B&A auction - response marked as chaff incorrectly'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, |
| msg => {msg.topLevelSeller = 'https://example.org/'}); |
| }, 'Basic B&A auction - incorrectly includes topLevelSeller'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => {msg.topLevelSeller = 1}); |
| }, 'Basic B&A auction - non-string top-level seller invalid'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, |
| msg => {msg.topLevelSeller = 'http://example.org/'}); |
| }, 'Basic B&A auction - http:// topLevelSeller is bad, too'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => {msg.bid = '10 cents'}); |
| }, 'Basic B&A auction - non-number bid is invalid'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ true, msg => {msg.bid = 50}); |
| }, 'Basic B&A auction - positive bid is good'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => {msg.bid = -50}); |
| }, 'Basic B&A auction - negative bid is bad'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => {msg.bid = 0}); |
| }, 'Basic B&A auction - zero bid is bad'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, |
| msg => {msg.biddingGroups[window.location.origin] = []}); |
| }, 'Basic B&A auction - winning group did not bid'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, |
| msg => {msg.biddingGroups[window.location.origin] = [-1, 0]}); |
| }, 'Basic B&A auction - negative bidding group index'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, |
| msg => {msg.biddingGroups[window.location.origin] = [0, 1]}); |
| }, 'Basic B&A auction - too large bidding group index'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => { |
| msg.interestGroupName += 'not'; |
| }); |
| }, 'Basic B&A auction - wrong IG name'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, async msg => { |
| await leaveInterestGroup(); |
| }); |
| }, 'Basic B&A auction - left IG in the middle'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => { |
| msg.adRenderURL += 'not'; |
| }); |
| }, 'Basic B&A auction - ad URL not in ad'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => { |
| msg.buyerReportingId = 'bid1'; |
| }); |
| }, 'Basic B&A auction - buyerReportingId not in ad'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ true, |
| msg => { |
| msg.buyerReportingId = 'bid1'; |
| }, |
| ig => { |
| ig.ads[0].buyerReportingId = 'bid1'; |
| ig.ads[1].buyerReportingId = 'bid2'; |
| }); |
| }, 'Basic B&A auction - buyerReportingId in ad'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, |
| msg => { |
| msg.buyerReportingId = 'bid2'; |
| }, |
| ig => { |
| ig.ads[0].buyerReportingId = 'bid1'; |
| ig.ads[1].buyerReportingId = 'bid2'; |
| }); |
| }, 'Basic B&A auction - buyerReportingId in wrong ad'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => { |
| msg.buyerAndSellerReportingId = 'bsid1'; |
| }); |
| }, 'Basic B&A auction - buyerAndSellerReportingId not in ad'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ true, |
| msg => { |
| msg.buyerAndSellerReportingId = 'bsid1'; |
| }, |
| ig => { |
| ig.ads[0].buyerAndSellerReportingId = 'bsid1'; |
| ig.ads[1].buyerAndSellerReportingId = 'bsid2'; |
| }); |
| }, 'Basic B&A auction - buyerAndSellerReportingId in ad'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, |
| msg => { |
| msg.buyerAndSellerReportingId = 'bsid2'; |
| }, |
| ig => { |
| ig.ads[0].buyerAndSellerReportingId = 'bsid1'; |
| ig.ads[1].buyerAndSellerReportingId = 'bsid2'; |
| }); |
| }, 'Basic B&A auction - buyerAndSellerReportingId in wrong ad'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => { |
| msg.components = ['https://example.org']; |
| }); |
| }, 'Basic B&A auction - ad component URL not in ad'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ true, |
| msg => { |
| msg.components = ['https://example.org']; |
| }, |
| ig => { |
| ig.adComponents = [{renderURL: 'https://example.org/'}]; |
| }); |
| }, 'Basic B&A auction - ad component URL in ad'); |
| |
| subsetTest(promise_test, async test => { |
| let savedUuid; |
| let savedExpectUrls; |
| let result = await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ true, |
| (msg, uuid) => { |
| savedUuid = uuid; |
| msg.components = [ |
| createTrackerURL(window.location.origin, uuid, 'track_get', 'c_a'), |
| createTrackerURL(window.location.origin, uuid, 'track_get', 'c_c') |
| ]; |
| savedExpectUrls = msg.components; |
| }, |
| (ig, uuid) => { |
| ig.ads[0].renderURL = createRenderURL(uuid, ` |
| const componentAds = window.fence.getNestedConfigs(); |
| // Limit the number of fenced frames we try to load at once, since loading too many |
| // completely breaks some Chrome test set ups, and we only really care about 3 of them |
| // anyway. |
| // |
| // See https://crbug.com/370533823 for more context. |
| const limit = 5; |
| for (var i = 0; i < Math.min(limit, componentAds.length); ++i) { |
| let fencedFrame = document.createElement("fencedframe"); |
| fencedFrame.mode = "opaque-ads"; |
| fencedFrame.config = componentAds[i]; |
| document.body.appendChild(fencedFrame); |
| }`); |
| ig.adComponents = [ |
| { |
| renderURL: createTrackerURL( |
| window.location.origin, uuid, 'track_get', 'c_a') |
| }, |
| { |
| renderURL: createTrackerURL( |
| window.location.origin, uuid, 'track_get', 'c_c') |
| }, |
| { |
| renderURL: createTrackerURL( |
| window.location.origin, uuid, 'track_get', 'c_c') |
| } |
| ]; |
| }); |
| createAndNavigateFencedFrame(test, result); |
| await waitForObservedRequests(savedUuid, savedExpectUrls); |
| }, 'Basic B&A auction - loading winning component ads'); |
| |
| |
| subsetTest(promise_test, async test => { |
| let savedUuid; |
| let result = await BA.testWithMutatedServerResponse( |
| test, /*expectWin=*/ true, |
| (msg, uuid) => { |
| savedUuid = uuid; |
| msg.winReportingURLs = { |
| 'buyerReportingURLs': { |
| 'interactionReportingURLs': { |
| 'click': createBidderBeaconURL(uuid, 'i'), |
| 'cluck': createBidderBeaconURL(uuid, 'u') |
| } |
| }, |
| 'topLevelSellerReportingURLs': { |
| 'interactionReportingURLs': { |
| 'click': createSellerBeaconURL(uuid, 'i'), |
| 'cluck': createSellerBeaconURL(uuid, 'u') |
| } |
| } |
| }; |
| }, |
| (ig, uuid) => { |
| ig.ads[0].renderURL = createRenderURL(uuid, `window.fence.reportEvent({ |
| eventType: 'click', |
| eventData: 'click_body', |
| destination: ['seller', 'buyer'] |
| }); |
| window.fence.reportEvent({ |
| eventType: 'cluck', |
| eventData: 'cluck_body', |
| destination: ['direct-seller'] |
| });`); |
| }); |
| |
| createAndNavigateFencedFrame(test, result); |
| // The script triggers seller and buyer 'click', and seller 'cluck'. |
| // No tracker for page itself. |
| await waitForObservedRequests(savedUuid, [ |
| createBidderBeaconURL(savedUuid, 'i') + ', body: click_body', |
| createSellerBeaconURL(savedUuid, 'i') + ', body: click_body', |
| createSellerBeaconURL(savedUuid, 'u') + ', body: cluck_body' |
| ]); |
| }, 'Basic B&A auction --- beacon reporting'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, msg => { |
| msg.bidCurrency = 'cents'; |
| }); |
| }, 'Basic B&A auction - invalid ad currency'); |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { |
| msg.bidCurrency = 'USD'; |
| }); |
| }, 'Basic B&A auction - valid ad currency'); |
| |
| // Runs whatever is set in `mutators` on a minimal correct hybrid B&A/local |
| // auction, and expects either the B&A bid or local bid to win depending on |
| // expectBaWin. |
| async function testHybridAuctionWithMutatedServerResponse( |
| test, expectBaWin, mutators = { |
| responseMutator: undefined, |
| igMutator: undefined, |
| auctionConfigMutator: undefined, |
| expectUrlsMutator: undefined |
| }) { |
| const uuid = generateUuid(test); |
| const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); |
| const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); |
| const adsArray = |
| [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; |
| let interestGroup = { |
| ads: adsArray, |
| biddingLogicURL: createBiddingScriptURL({allowComponentAuction: true}) |
| }; |
| if (mutators.igMutator) { |
| mutators.igMutator(interestGroup, uuid); |
| } |
| await joinInterestGroup(test, uuid, interestGroup); |
| |
| const result = await navigator.getInterestGroupAdAuctionData({ |
| coordinatorOrigin: await BA.configureCoordinator(), |
| seller: window.location.origin |
| }); |
| assert_true(result.requestId !== null); |
| assert_true(result.request.length > 0); |
| |
| let decoded = await BA.decodeInterestGroupData(result.request); |
| |
| // The server-side auction uses a bid of 10, for second ad, so it should |
| // win over the client-side component auctions bid of 9 (unless something |
| // mutators did made the server response unacceptable). |
| let serverResponseMsg = { |
| 'biddingGroups': {}, |
| 'adRenderURL': interestGroup.ads[1].renderURL, |
| 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, |
| 'interestGroupOwner': window.location.origin, |
| 'topLevelSeller': window.location.origin, |
| 'bid': 10, |
| }; |
| serverResponseMsg.biddingGroups[window.location.origin] = [0]; |
| if (mutators.responseMutator) { |
| mutators.responseMutator(serverResponseMsg, uuid); |
| } |
| |
| let serverResponse = |
| await BA.encodeServerResponse(serverResponseMsg, decoded); |
| |
| let hashString = await BA.payloadHash(serverResponse); |
| await BA.authorizeServerResponseHashes([hashString]); |
| |
| let auctionConfig = { |
| seller: window.location.origin, |
| decisionLogicURL: createDecisionScriptURL(uuid), |
| interestGroupBuyers: [], |
| resolveToConfig: true, |
| componentAuctions: [ |
| { |
| seller: window.location.origin, |
| decisionLogicURL: createDecisionScriptURL(uuid), |
| interestGroupBuyers: [window.location.origin], |
| }, |
| { |
| seller: window.location.origin, |
| requestId: result.requestId, |
| serverResponse: serverResponse, |
| } |
| ] |
| }; |
| if (mutators.auctionConfigMutator) { |
| mutators.auctionConfigMutator(auctionConfig, uuid); |
| } |
| |
| let auctionResult = await navigator.runAdAuction(auctionConfig); |
| expectSuccess(auctionResult); |
| createAndNavigateFencedFrame(test, auctionResult); |
| let expectUrls = expectBaWin ? [adB] : [adA]; |
| if (mutators.expectUrlsMutator) { |
| mutators.expectUrlsMutator(expectUrls, uuid); |
| } |
| await waitForObservedRequests(uuid, expectUrls); |
| } |
| |
| subsetTest(promise_test, async test => { |
| await testHybridAuctionWithMutatedServerResponse( |
| test, /*expectBaWin=*/ false, { |
| responseMutator: (response) => { |
| delete response.topLevelSeller; |
| } |
| }); |
| }, 'Hybrid B&A auction --- missing top-level seller'); |
| |
| subsetTest(promise_test, async test => { |
| await testHybridAuctionWithMutatedServerResponse( |
| test, /*expectBaWin=*/ false, { |
| responseMutator: (response) => { |
| response.topLevelSeller = 'https://www.example.org/'; |
| } |
| }); |
| }, 'Hybrid B&A auction --- wrong top-level seller'); |
| |
| subsetTest(promise_test, async test => { |
| await testHybridAuctionWithMutatedServerResponse( |
| test, /*expectBaWin=*/ false, { |
| responseMutator: (response) => { |
| delete response.bid; |
| } |
| }); |
| }, 'Hybrid B&A auction --- no bid'); |
| |
| subsetTest(promise_test, async test => { |
| await testHybridAuctionWithMutatedServerResponse( |
| test, /*expectBaWin=*/ true, { |
| responseMutator: (response) => { |
| response.bidCurrency = 'USD'; |
| } |
| }); |
| }, 'Hybrid B&A auction --- currency check --- nothing configured'); |
| |
| subsetTest(promise_test, async test => { |
| await testHybridAuctionWithMutatedServerResponse( |
| test, /*expectBaWin=*/ false, { |
| responseMutator: (response) => { |
| response.bidCurrency = 'USD'; |
| }, |
| auctionConfigMutator: (auctionConfig) => { |
| auctionConfig.componentAuctions[1].sellerCurrency = 'EUR'; |
| } |
| }); |
| }, 'Hybrid B&A auction --- sellerCurrency mismatch'); |
| |
| subsetTest(promise_test, async test => { |
| await testHybridAuctionWithMutatedServerResponse( |
| test, /*expectBaWin=*/ true, { |
| auctionConfigMutator: (auctionConfig) => { |
| auctionConfig.componentAuctions[1].sellerCurrency = 'EUR'; |
| } |
| }); |
| }, 'Hybrid B&A auction --- sellerCurrency config, no bidCurrency'); |
| |
| subsetTest(promise_test, async test => { |
| await testHybridAuctionWithMutatedServerResponse( |
| test, /*expectBaWin=*/ false, { |
| responseMutator: (response) => { |
| response.bidCurrency = 'USD'; |
| }, |
| auctionConfigMutator: (auctionConfig) => { |
| auctionConfig.perBuyerCurrencies = {}; |
| auctionConfig.perBuyerCurrencies[window.location.origin] = 'EUR'; |
| } |
| }); |
| }, 'Hybrid B&A auction --- top perBuyerCurrencies mismatch'); |
| |
| subsetTest(promise_test, async test => { |
| await testHybridAuctionWithMutatedServerResponse( |
| test, /*expectBaWin=*/ true, { |
| auctionConfigMutator: (auctionConfig) => { |
| auctionConfig.perBuyerCurrencies = {}; |
| auctionConfig.perBuyerCurrencies[window.location.origin] = 'EUR'; |
| } |
| }); |
| }, 'Hybrid B&A auction --- perBuyerCurrencies config, no bidCurrency'); |
| |
| subsetTest(promise_test, async test => { |
| await testHybridAuctionWithMutatedServerResponse( |
| test, /*expectBaWin=*/ true, { |
| responseMutator: (response) => { |
| response.bidCurrency = 'USD'; |
| response.bid = 50; |
| response.adMetadata = '[1, "hello"]'; |
| }, |
| auctionConfigMutator: (auctionConfig, uuid) => { |
| let trackTopSeller = createSellerReportURL(uuid, 'top'); |
| auctionConfig.decisionLogicURL = createDecisionScriptURL(uuid, { |
| // Note: this will throw on the local bid as well as an incorrect |
| // server bid. |
| scoreAd: ` |
| let origin = '${window.location.origin}'; |
| if (!(adMetadata instanceof Array) || |
| adMetadata.length !== 2 || |
| adMetadata[0] !== 1 || |
| adMetadata[1] !== 'hello') { |
| throw 'bad adMetadata ' + JSON.stringify(adMetadata); |
| } |
| if (bid !== 50) |
| throw 'bad bid ' + bid; |
| if (browserSignals.bidCurrency !== 'USD') |
| throw 'bad currency ' + browserSignals.bidCurrency; |
| if (browserSignals.interestGroupOwner != origin) |
| throw 'bad IG owner ' + browserSignals.interestGroupOwner; |
| if (browserSignals.componentSeller != origin) { |
| throw 'bad component seller ' + |
| browserSignals.interestGroupOwner; |
| }` |
| }); |
| } |
| }); |
| }, 'Hybrid B&A auction --- bid info passed to top-level scoreAd'); |
| |
| subsetTest(promise_test, async test => { |
| await testHybridAuctionWithMutatedServerResponse( |
| test, /*expectBaWin=*/ true, { |
| responseMutator: (response) => { |
| response.bidCurrency = 'USD'; |
| response.bid = 50; |
| response.buyerAndSellerReportingId = 'bsid2'; |
| }, |
| igMutator: (ig) => { |
| ig.ads[0].buyerAndSellerReportingId = 'bsid1'; |
| ig.ads[1].buyerAndSellerReportingId = 'bsid2'; |
| }, |
| auctionConfigMutator: (auctionConfig, uuid) => { |
| let trackTopSeller = createSellerReportURL(uuid, 'top'); |
| auctionConfig.decisionLogicURL = createDecisionScriptURL(uuid, { |
| reportResult: `sendReportTo("${trackTopSeller}&" + |
| browserSignals.bid + '&' + |
| browserSignals.buyerAndSellerReportingId)` |
| }); |
| }, |
| expectUrlsMutator: (expectUrls, uuid) => { |
| expectUrls.push(createSellerReportURL(uuid, 'top') + '&50&bsid2'); |
| } |
| }); |
| }, 'Hybrid B&A auction --- bid info passed to top-level reporting'); |
| |
| subsetTest(promise_test, async test => { |
| await testHybridAuctionWithMutatedServerResponse( |
| test, /*expectBaWin=*/ true, { |
| igMutator: (ig, uuid) => { |
| ig.ads[1].renderURL = |
| createRenderURL(uuid, `window.fence.reportEvent({ |
| eventType: 'click', |
| eventData: 'click_body', |
| destination: ['component-seller', 'buyer'] |
| }); |
| window.fence.reportEvent({ |
| eventType: 'clack', |
| eventData: 'clack_body', |
| destination: ['direct-seller'] |
| });`); |
| }, |
| responseMutator: (response, uuid) => { |
| response.winReportingURLs = { |
| 'buyerReportingURLs': { |
| 'interactionReportingURLs': { |
| 'click': createBidderBeaconURL(uuid, 'i'), |
| 'clack': createBidderBeaconURL(uuid, 'a') |
| } |
| }, |
| 'componentSellerReportingURLs': { |
| 'interactionReportingURLs': { |
| 'click': createSellerBeaconURL(uuid, 'i'), |
| 'clack': createSellerBeaconURL(uuid, 'a') |
| } |
| } |
| }; |
| }, |
| expectUrlsMutator: (expectUrls, uuid) => { |
| // The script triggers seller and buyer 'click', and seller 'clack'. |
| // No tracker for page itself. |
| expectUrls.pop(); |
| expectUrls.push( |
| createBidderBeaconURL(uuid, 'i') + ', body: click_body', |
| createSellerBeaconURL(uuid, 'i') + ', body: click_body', |
| createSellerBeaconURL(uuid, 'a') + ', body: clack_body'); |
| } |
| }); |
| }, 'Hybrid B&A auction --- beacon reporting'); |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // updateIfOlderThanMs tests |
| // |
| // NOTE: Due to the lack of mock time in wpt, these tests just exercise the code |
| // paths and ensure that no crash occurs -- they don't otherwise verify |
| // behavior. |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { |
| msg.updateGroups = |
| {[window.location.origin]: [{index: 2048, updateIfOlderThanMs: 1000}]}; |
| }); |
| }, 'Basic B&A auction - updateIfOlderThanMs - invalid index'); |
| |
| |
| subsetTest(promise_test, async test => { |
| await BA.testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { |
| msg.updateGroups = { |
| [window.location.origin]: [ |
| {index: 0, updateIfOlderThanMs: 1000}, |
| {index: 1, updateIfOlderThanMs: 10000} |
| ] |
| }; |
| }); |
| }, 'Basic B&A auction - updateIfOlderThanMs'); |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // |
| // K-anonymity support tests |
| // |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| // Runs responseMutator on a minimal correct server response, and expects |
| // either success/failure based on expectWin. |
| async function kAnonTestWithMutatedServerResponse( |
| test, expectWin, responseMutator, igMutator = undefined) { |
| const uuid = generateUuid(test); |
| const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); |
| const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); |
| const adsArray = |
| [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; |
| let ig = { |
| owner: window.location.origin, |
| name: DEFAULT_INTEREST_GROUP_NAME, |
| ads: adsArray, |
| biddingLogicURL: createBiddingScriptURL({allowComponentAuction: true}) |
| }; |
| if (igMutator) { |
| igMutator(ig, uuid); |
| } |
| |
| const encoder = new TextEncoder(); |
| const adARenderKAnonKey = |
| encoder.encode(`AdBid\n${ig.owner}/\n${ig.biddingLogicURL}\n${adA}`); |
| const adBRenderKAnonKey = |
| encoder.encode(`AdBid\n${ig.owner}/\n${ig.biddingLogicURL}\n${adB}`); |
| const adARenderKAnonKeyHash = new Uint8Array( |
| await window.crypto.subtle.digest('SHA-256', adARenderKAnonKey)); |
| const adBRenderKAnonKeyHash = new Uint8Array( |
| await window.crypto.subtle.digest('SHA-256', adBRenderKAnonKey)); |
| |
| const adANameReportingIdKAnonKey = encoder.encode( |
| `NameReport\n${ig.owner}/\n${ig.biddingLogicURL}\n${adA}\n${ig.name}`); |
| const adBNameReportingIdKAnonKey = encoder.encode( |
| `NameReport\n${ig.owner}/\n${ig.biddingLogicURL}\n${adB}\n${ig.name}`); |
| const adANameReportingIdKAnonKeyHash = new Uint8Array( |
| await window.crypto.subtle.digest('SHA-256', adANameReportingIdKAnonKey)); |
| const adBNameReportingIdKAnonKeyHash = new Uint8Array( |
| await window.crypto.subtle.digest('SHA-256', adBNameReportingIdKAnonKey)); |
| |
| const adABuyerReportingIdKAnonKey = encoder.encode(`BuyerReportId\n${ |
| ig.owner}/\n${ig.biddingLogicURL}\n${adA}\n${adA.buyerReportingId}`); |
| const adBBuyerReportingIdKAnonKey = encoder.encode(`BuyerReportId\n${ |
| ig.owner}/\n${ig.biddingLogicURL}\n${adB}\n${adB.buyerReportingId}`); |
| const adABuyerReportingIdKAnonKeyHash = |
| new Uint8Array(await window.crypto.subtle.digest( |
| 'SHA-256', adABuyerReportingIdKAnonKey)); |
| const adBBuyerReportingIdKAnonKeyHash = |
| new Uint8Array(await window.crypto.subtle.digest( |
| 'SHA-256', adBBuyerReportingIdKAnonKey)); |
| |
| const adABASReportingIdKAnonKey = |
| encoder.encode(`BuyerAndSellerReportId\n${ig.owner}/\n${ |
| ig.biddingLogicURL}\n${adA}\n${adA.buyerAndSellerReportingId}`); |
| const adBBASReportingIdKAnonKey = |
| encoder.encode(`BuyerAndSellerReportId\n${ig.owner}/\n${ |
| ig.biddingLogicURL}\n${adB}\n${adB.buyerAndSellerReportingId}`); |
| const adABASReportingIdKAnonKeyHash = new Uint8Array( |
| await window.crypto.subtle.digest('SHA-256', adABASReportingIdKAnonKey)); |
| const adBBASReportingIdKAnonKeyHash = new Uint8Array( |
| await window.crypto.subtle.digest('SHA-256', adBBASReportingIdKAnonKey)); |
| |
| const hashes = { |
| adARenderKAnonKeyHash: adARenderKAnonKeyHash, |
| adBRenderKAnonKeyHash: adBRenderKAnonKeyHash, |
| adANameReportingIdKAnonKeyHash: adANameReportingIdKAnonKeyHash, |
| adBNameReportingIdKAnonKeyHash: adBNameReportingIdKAnonKeyHash, |
| adABuyerReportingIdKAnonKeyHash: adABuyerReportingIdKAnonKeyHash, |
| adBBuyerReportingIdKAnonKeyHash: adBBuyerReportingIdKAnonKeyHash, |
| adABASReportingIdKAnonKeyHash: adABASReportingIdKAnonKeyHash, |
| adBBASReportingIdKAnonKeyHash: adBBASReportingIdKAnonKeyHash |
| }; |
| |
| await joinInterestGroup(test, uuid, ig); |
| |
| const result = await navigator.getInterestGroupAdAuctionData({ |
| coordinatorOrigin: await BA.configureCoordinator(), |
| seller: window.location.origin |
| }); |
| assert_true(result.requestId !== null); |
| assert_true(result.request.length > 0); |
| |
| let decoded = await BA.decodeInterestGroupData(result.request); |
| |
| let serverResponseMsg = { |
| 'biddingGroups': {}, |
| 'adRenderURL': ig.ads[0].renderURL, |
| 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, |
| 'interestGroupOwner': window.location.origin, |
| }; |
| serverResponseMsg.biddingGroups[window.location.origin] = [0]; |
| |
| await responseMutator(serverResponseMsg, ig, hashes, uuid); |
| |
| let serverResponse = |
| await BA.encodeServerResponse(serverResponseMsg, decoded); |
| |
| let hashString = await BA.payloadHash(serverResponse); |
| await BA.authorizeServerResponseHashes([hashString]); |
| |
| let auctionResult = await navigator.runAdAuction({ |
| 'seller': window.location.origin, |
| 'interestGroupBuyers': [window.location.origin], |
| 'requestId': result.requestId, |
| 'serverResponse': serverResponse, |
| 'resolveToConfig': true, |
| }); |
| if (expectWin) { |
| expectSuccess(auctionResult); |
| return auctionResult; |
| } else { |
| expectNoWinner(auctionResult); |
| } |
| } |
| |
| subsetTest(promise_test, async test => { |
| await kAnonTestWithMutatedServerResponse( |
| test, /*expectSuccess=*/ true, (msg, ig, hashes) => { |
| msg.kAnonWinnerJoinCandidates = { |
| adRenderURLHash: hashes.adARenderKAnonKeyHash, |
| reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, |
| }; |
| }); |
| }, 'Basic B&A auction - winner with candidates'); |
| |
| subsetTest(promise_test, async test => { |
| await kAnonTestWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, (msg, ig, hashes) => { |
| msg.kAnonWinnerJoinCandidates = { |
| adRenderURLHash: new Uint8Array(), |
| reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, |
| }; |
| }); |
| }, 'Basic B&A auction - winner with bad render hash'); |
| |
| subsetTest(promise_test, async test => { |
| await kAnonTestWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, (msg, ig, hashes) => { |
| msg.kAnonWinnerJoinCandidates = { |
| adRenderURLHash: hashes.adARenderKAnonKeyHash, |
| reportingIdHash: new Uint8Array(), |
| }; |
| }); |
| }, 'Basic B&A auction - winner with bad reporting hash'); |
| |
| subsetTest(promise_test, async test => { |
| await kAnonTestWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, (msg, ig, hashes) => { |
| delete msg.adRenderURL; |
| delete msg.interestGroupName; |
| delete msg.interestGroupOwner; |
| msg.kAnonGhostWinners = [{ |
| kAnonJoinCandidates: { |
| // missing adRenderURLHash |
| reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, |
| }, |
| interestGroupIndex: 0, |
| owner: window.location.origin, |
| }] |
| }); |
| }, 'Basic B&A auction - invalid ghost winner'); |
| |
| subsetTest(promise_test, async test => { |
| await kAnonTestWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, (msg, ig, hashes) => { |
| delete msg.adRenderURL; |
| delete msg.interestGroupName; |
| delete msg.interestGroupOwner; |
| msg.kAnonGhostWinners = [{ |
| kAnonJoinCandidates: { |
| adRenderURLHash: hashes.adARenderKAnonKeyHash, |
| reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, |
| }, |
| interestGroupIndex: 0, |
| owner: window.location.origin, |
| }] |
| }); |
| }, 'Basic B&A auction - only ghost winner'); |
| |
| subsetTest(promise_test, async test => { |
| await kAnonTestWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, (msg, ig, hashes) => { |
| delete msg.adRenderURL; |
| delete msg.interestGroupName; |
| delete msg.interestGroupOwner; |
| msg.kAnonGhostWinners = [ |
| { |
| kAnonJoinCandidates: { |
| adRenderURLHash: hashes.adARenderKAnonKeyHash, |
| reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, |
| }, |
| interestGroupIndex: 0, |
| owner: window.location.origin, |
| }, |
| { |
| kAnonJoinCandidates: { |
| adRenderURLHash: hashes.adBRenderKAnonKeyHash, |
| reportingIdHash: hashes.adBNameReportingIdKAnonKeyHash, |
| }, |
| interestGroupIndex: 0, |
| owner: window.location.origin, |
| } |
| ] |
| }); |
| }, 'Basic B&A auction - multiple ghost winners'); |
| |
| subsetTest(promise_test, async test => { |
| await kAnonTestWithMutatedServerResponse( |
| test, /*expectSuccess=*/ false, (msg, ig, hashes) => { |
| delete msg.adRenderURL; |
| delete msg.interestGroupName; |
| delete msg.interestGroupOwner; |
| msg.kAnonGhostWinners = [ |
| { |
| kAnonJoinCandidates: { |
| adRenderURLHash: hashes.adARenderKAnonKeyHash, |
| reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, |
| }, |
| interestGroupIndex: 0, |
| owner: window.location.origin, |
| }, |
| { |
| kAnonJoinCandidates: { |
| // missing adRenderURLHash |
| reportingIdHash: hashes.adBNameReportingIdKAnonKeyHash, |
| }, |
| interestGroupIndex: 0, |
| owner: window.location.origin, |
| } |
| ] |
| }); |
| }, 'Basic B&A auction - second ghost winner invalid'); |
| |
| subsetTest(promise_test, async test => { |
| await kAnonTestWithMutatedServerResponse( |
| test, /*expectSuccess=*/ true, (msg, ig, hashes) => { |
| msg.kAnonWinnerJoinCandidates = { |
| adRenderURLHash: hashes.adARenderKAnonKeyHash, |
| reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, |
| }; |
| msg.kAnonGhostWinners = [{ |
| kAnonJoinCandidates: { |
| adRenderURLHash: hashes.adBRenderKAnonKeyHash, |
| reportingIdHash: hashes.adBNameReportingIdKAnonKeyHash, |
| }, |
| interestGroupIndex: 0, |
| owner: window.location.origin, |
| }]; |
| }); |
| }, 'Basic B&A auction - winner with ghost winner'); |
| |
| subsetTest(promise_test, async test => { |
| await kAnonTestWithMutatedServerResponse( |
| test, /*expectSuccess=*/ true, (msg, ig, hashes) => { |
| msg.kAnonWinnerJoinCandidates = { |
| adRenderURLHash: hashes.adARenderKAnonKeyHash, |
| reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, |
| }; |
| msg.kAnonGhostWinners = [{ |
| kAnonJoinCandidates: { |
| adRenderURLHash: hashes.adBRenderKAnonKeyHash, |
| reportingIdHash: hashes.adBNameReportingIdKAnonKeyHash, |
| }, |
| interestGroupIndex: 0, |
| owner: window.location.origin, |
| ghostWinnerForTopLevelAuction: { |
| // missing adRenderURL |
| modifiedBid: 100, |
| }, |
| }]; |
| }); |
| }, 'Basic B&A auction - invalid GhostWinnerForTopLevelAuction'); |
| |
| subsetTest(promise_test, async test => { |
| await kAnonTestWithMutatedServerResponse( |
| test, /*expectSuccess=*/ true, (msg, ig, hashes) => { |
| msg.kAnonWinnerJoinCandidates = { |
| adRenderURLHash: hashes.adARenderKAnonKeyHash, |
| reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, |
| }; |
| msg.kAnonGhostWinners = [{ |
| kAnonJoinCandidates: { |
| adRenderURLHash: hashes.adBRenderKAnonKeyHash, |
| reportingIdHash: hashes.adBNameReportingIdKAnonKeyHash, |
| }, |
| interestGroupIndex: 0, |
| owner: window.location.origin, |
| ghostWinnerForTopLevelAuction: { |
| adRenderURL: ig.ads[1].renderURL, |
| modifiedBid: 100, |
| }, |
| }]; |
| }); |
| }, 'Basic B&A auction - winner with full ghost winner'); |
| |
| // TODO(behamilton): Add Multi-seller k-anon tests. |
| // TODO(behamilton): Add k-anon tests with different reporting IDs. |
| |
| /* Some things that are not currently tested that probably should be; this is |
| not exhaustive, merely to keep track of things that come to mind as tests are |
| written: |
| |
| - forDebugOnly --- it will be straightforward now, but will break. |
| - Some of the parsing details that need to match the spec language exactly. |
| */ |