server-response.https.window.js (51106B)
1 // META: script=/resources/testdriver.js 2 // META: script=/resources/testdriver-vendor.js 3 // META: script=/common/utils.js 4 // META: script=resources/ba-fledge-util.sub.js 5 // META: script=resources/fledge-util.sub.js 6 // META: script=third_party/cbor-js/cbor.js 7 // META: script=/common/subset-tests.js 8 // META: timeout=long 9 // META: variant=?1-6 10 // META: variant=?7-10 11 // META: variant=?11-14 12 // META: variant=?15-18 13 // META: variant=?19-22 14 // META: variant=?23-26 15 // META: variant=?27-30 16 // META: variant=?31-34 17 // META: variant=?35-38 18 // META: variant=?39-42 19 // META: variant=?43-46 20 // META: variant=?47-50 21 // META: variant=?51-54 22 // META: variant=?55-58 23 // META: variant=?59-62 24 // META: variant=?63-66 25 // META: variant=?67-70 26 27 "use strict"; 28 29 // These tests focus on the serverResponse field in AuctionConfig, e.g. 30 // auctions involving bidding and auction services. 31 32 subsetTest(promise_test, async test => { 33 const uuid = generateUuid(test); 34 const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); 35 const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); 36 const adsArray = 37 [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; 38 await joinInterestGroup(test, uuid, {ads: adsArray}); 39 40 const result = await navigator.getInterestGroupAdAuctionData({ 41 coordinatorOrigin: await BA.configureCoordinator(), 42 seller: window.location.origin 43 }); 44 assert_true(result.requestId !== null); 45 assert_true(result.request.length > 0); 46 47 let decoded = await BA.decodeInterestGroupData(result.request); 48 49 let serverResponseMsg = { 50 'biddingGroups': {}, 51 'adRenderURL': adsArray[0].renderURL, 52 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, 53 'interestGroupOwner': window.location.origin, 54 }; 55 serverResponseMsg.biddingGroups[window.location.origin] = [0]; 56 57 let serverResponse = 58 await BA.encodeServerResponse(serverResponseMsg, decoded); 59 60 let hashString = await BA.payloadHash(serverResponse); 61 await BA.authorizeServerResponseHashes([hashString]); 62 63 let auctionResult = await navigator.runAdAuction({ 64 'seller': window.location.origin, 65 'requestId': result.requestId, 66 'serverResponse': serverResponse, 67 'resolveToConfig': true, 68 }); 69 expectSuccess(auctionResult); 70 createAndNavigateFencedFrame(test, auctionResult); 71 await waitForObservedRequests(uuid, [adA]); 72 }, 'Basic B&A auction'); 73 74 subsetTest(promise_test, async test => { 75 const uuid = generateUuid(test); 76 const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); 77 const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); 78 const adsArray = 79 [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; 80 await joinInterestGroup(test, uuid, {ads: adsArray}); 81 82 const result = await navigator.getInterestGroupAdAuctionData({ 83 coordinatorOrigin: await BA.configureCoordinator(), 84 seller: window.location.origin 85 }); 86 assert_true(result.requestId !== null); 87 assert_true(result.request.length > 0); 88 89 let decoded = await BA.decodeInterestGroupData(result.request); 90 91 let serverResponseMsg = { 92 'biddingGroups': {}, 93 'adRenderURL': adsArray[0].renderURL, 94 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, 95 'interestGroupOwner': window.location.origin, 96 }; 97 serverResponseMsg.biddingGroups[window.location.origin] = [0]; 98 99 let serverResponse = 100 await BA.encodeServerResponse(serverResponseMsg, decoded); 101 102 let auctionResult = await navigator.runAdAuction({ 103 'seller': window.location.origin, 104 'requestId': result.requestId, 105 'serverResponse': serverResponse, 106 'resolveToConfig': true, 107 }); 108 expectNoWinner(auctionResult); 109 }, 'Basic B&A auction - not authorized'); 110 111 subsetTest(promise_test, async test => { 112 const uuid = generateUuid(test); 113 const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); 114 const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); 115 const adsArray = 116 [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; 117 await joinInterestGroup(test, uuid, {ads: adsArray}); 118 119 const result = await navigator.getInterestGroupAdAuctionData({ 120 coordinatorOrigin: await BA.configureCoordinator(), 121 seller: window.location.origin 122 }); 123 assert_true(result.requestId !== null); 124 assert_true(result.request.length > 0); 125 126 let decoded = await BA.decodeInterestGroupData(result.request); 127 128 const trackSeller = createSellerReportURL(uuid); 129 const trackBuyer = createBidderReportURL(uuid); 130 // This one should still work since the server may have run an auction with 131 // components on its own. 132 const trackComponentSeller = createSellerReportURL(uuid, 'component'); 133 let serverResponseMsg = { 134 'biddingGroups': {}, 135 'adRenderURL': adsArray[1].renderURL, 136 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, 137 'interestGroupOwner': window.location.origin, 138 'winReportingURLs': { 139 'buyerReportingURLs': {'reportingURL': trackBuyer}, 140 'topLevelSellerReportingURLs': {'reportingURL': trackSeller}, 141 'componentSellerReportingURLs': {'reportingURL': trackComponentSeller} 142 } 143 }; 144 serverResponseMsg.biddingGroups[window.location.origin] = [0]; 145 146 let serverResponse = 147 await BA.encodeServerResponse(serverResponseMsg, decoded); 148 149 let hashString = await BA.payloadHash(serverResponse); 150 await BA.authorizeServerResponseHashes([hashString]); 151 152 let auctionResult = await navigator.runAdAuction({ 153 'seller': window.location.origin, 154 'requestId': result.requestId, 155 'serverResponse': serverResponse, 156 'resolveToConfig': true, 157 }); 158 expectSuccess(auctionResult); 159 createAndNavigateFencedFrame(test, auctionResult); 160 await waitForObservedRequests( 161 uuid, [adB, trackBuyer, trackSeller, trackComponentSeller]); 162 }, 'Basic B&A auction with reporting URLs'); 163 164 subsetTest(promise_test, async test => { 165 const uuid = generateUuid(test); 166 const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); 167 const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); 168 const adsArray = 169 [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; 170 await joinInterestGroup(test, uuid, { 171 ads: adsArray, 172 biddingLogicURL: createBiddingScriptURL({allowComponentAuction: true}) 173 }); 174 175 const result = await navigator.getInterestGroupAdAuctionData({ 176 coordinatorOrigin: await BA.configureCoordinator(), 177 seller: window.location.origin 178 }); 179 assert_true(result.requestId !== null); 180 assert_true(result.request.length > 0); 181 182 let decoded = await BA.decodeInterestGroupData(result.request); 183 184 // The server-side auction uses a bid of 10, for second ad, so it should 185 // win over the client-side component auctions bid of 9. 186 let serverResponseMsg = { 187 'biddingGroups': {}, 188 'adRenderURL': adsArray[1].renderURL, 189 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, 190 'interestGroupOwner': window.location.origin, 191 'topLevelSeller': window.location.origin, 192 'bid': 10, 193 }; 194 serverResponseMsg.biddingGroups[window.location.origin] = [0]; 195 196 let serverResponse = 197 await BA.encodeServerResponse(serverResponseMsg, decoded); 198 199 let hashString = await BA.payloadHash(serverResponse); 200 await BA.authorizeServerResponseHashes([hashString]); 201 202 let auctionConfig = { 203 seller: window.location.origin, 204 decisionLogicURL: createDecisionScriptURL(uuid), 205 interestGroupBuyers: [], 206 resolveToConfig: true, 207 componentAuctions: [ 208 { 209 seller: window.location.origin, 210 decisionLogicURL: createDecisionScriptURL(uuid), 211 interestGroupBuyers: [window.location.origin], 212 }, 213 { 214 seller: window.location.origin, 215 requestId: result.requestId, 216 serverResponse: serverResponse, 217 } 218 ] 219 }; 220 221 let auctionResult = await navigator.runAdAuction(auctionConfig); 222 expectSuccess(auctionResult); 223 createAndNavigateFencedFrame(test, auctionResult); 224 await waitForObservedRequests(uuid, [adB]); 225 }, 'Hybrid B&A auction'); 226 227 subsetTest(promise_test, async test => { 228 const uuid = generateUuid(test); 229 const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); 230 const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); 231 const adsArray = 232 [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; 233 await joinInterestGroup(test, uuid, { 234 ads: adsArray, 235 biddingLogicURL: createBiddingScriptURL({allowComponentAuction: true}) 236 }); 237 238 const result = await navigator.getInterestGroupAdAuctionData({ 239 coordinatorOrigin: await BA.configureCoordinator(), 240 seller: window.location.origin 241 }); 242 assert_true(result.requestId !== null); 243 assert_true(result.request.length > 0); 244 245 let decoded = await BA.decodeInterestGroupData(result.request); 246 247 // The server-side auction uses a bid of 10, for second ad, so it should 248 // win over the client-side component auctions bid of 9. 249 const trackServerSeller = createSellerReportURL(uuid); 250 const trackBuyer = createBidderReportURL(uuid); 251 // This one shouldn't show up. 252 const trackTopLevelServerSeller = createSellerReportURL(uuid, 'top'); 253 let serverResponseMsg = { 254 'biddingGroups': {}, 255 'adRenderURL': adsArray[1].renderURL, 256 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, 257 'interestGroupOwner': window.location.origin, 258 'topLevelSeller': window.location.origin, 259 'bid': 10, 260 'winReportingURLs': { 261 'buyerReportingURLs': {'reportingURL': trackBuyer}, 262 'componentSellerReportingURLs': {'reportingURL': trackServerSeller}, 263 'topLevelSellerReportingURLs': {'reportingURL': trackTopLevelServerSeller} 264 } 265 }; 266 serverResponseMsg.biddingGroups[window.location.origin] = [0]; 267 268 let serverResponse = 269 await BA.encodeServerResponse(serverResponseMsg, decoded); 270 271 let hashString = await BA.payloadHash(serverResponse); 272 await BA.authorizeServerResponseHashes([hashString]); 273 274 let trackTopSeller = createSellerReportURL(uuid, 'top'); 275 let trackClientSeller = createSellerReportURL(uuid, 'client'); 276 let auctionConfig = { 277 seller: window.location.origin, 278 decisionLogicURL: createDecisionScriptURL( 279 uuid, {reportResult: `sendReportTo("${trackTopSeller}")`}), 280 interestGroupBuyers: [], 281 resolveToConfig: true, 282 componentAuctions: [ 283 { 284 seller: window.location.origin, 285 decisionLogicURL: createDecisionScriptURL( 286 uuid, {reportResult: `sendReportTo("${trackClientSeller}")`}), 287 interestGroupBuyers: [window.location.origin], 288 }, 289 { 290 seller: window.location.origin, 291 requestId: result.requestId, 292 serverResponse: serverResponse, 293 } 294 ] 295 }; 296 297 let auctionResult = await navigator.runAdAuction(auctionConfig); 298 expectSuccess(auctionResult); 299 createAndNavigateFencedFrame(test, auctionResult); 300 await waitForObservedRequests( 301 uuid, [adB, trackBuyer, trackServerSeller, trackTopSeller]); 302 }, 'Hybrid B&A auction with reporting URLs'); 303 304 async function runFaultInjectTest(test, fault) { 305 const uuid = generateUuid(test); 306 const adA = 'https://example.org/a'; 307 const adB = 'https://example.org/b'; 308 const adsArray = 309 [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; 310 await joinInterestGroup(test, uuid, {ads: adsArray}); 311 312 const result = await navigator.getInterestGroupAdAuctionData({ 313 coordinatorOrigin: await BA.configureCoordinator(), 314 seller: window.location.origin 315 }); 316 assert_true(result.requestId !== null); 317 assert_true(result.request.length > 0); 318 319 let decoded = await BA.decodeInterestGroupData(result.request); 320 321 let serverResponseMsg = { 322 'biddingGroups': {}, 323 'adRenderURL': adsArray[0].renderURL, 324 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, 325 'interestGroupOwner': window.location.origin, 326 }; 327 serverResponseMsg.biddingGroups[window.location.origin] = [0]; 328 329 let serverResponse = 330 await BA.encodeServerResponse(serverResponseMsg, decoded, fault); 331 332 let hashString = await BA.payloadHash(serverResponse); 333 await BA.authorizeServerResponseHashes([hashString]); 334 335 let auctionResult = await navigator.runAdAuction({ 336 'seller': window.location.origin, 337 'requestId': result.requestId, 338 'serverResponse': serverResponse, 339 'resolveToConfig': true, 340 }); 341 expectNoWinner(auctionResult); 342 } 343 344 subsetTest(promise_test, async test => { 345 return runFaultInjectTest(test, BA.injectCborFault); 346 }, 'Basic B&A auction - fault inject at CBOR'); 347 348 subsetTest(promise_test, async test => { 349 return runFaultInjectTest(test, BA.injectGzipFault); 350 }, 'Basic B&A auction - fault inject at gzip'); 351 352 subsetTest(promise_test, async test => { 353 return runFaultInjectTest(test, BA.injectFrameFault); 354 }, 'Basic B&A auction - fault inject at framing'); 355 356 subsetTest(promise_test, async test => { 357 return runFaultInjectTest(test, BA.injectEncryptFault); 358 }, 'Basic B&A auction - fault inject at encryption'); 359 360 subsetTest(promise_test, async test => { 361 const uuid = generateUuid(test); 362 const adA = 'https://example.org/a'; 363 const adB = 'https://example.org/b'; 364 const adsArray = 365 [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; 366 await joinInterestGroup(test, uuid, {ads: adsArray}); 367 368 const result = await navigator.getInterestGroupAdAuctionData({ 369 coordinatorOrigin: await BA.configureCoordinator(), 370 seller: window.location.origin 371 }); 372 assert_true(result.requestId !== null); 373 assert_true(result.request.length > 0); 374 375 let decoded = await BA.decodeInterestGroupData(result.request); 376 377 let serverResponseMsg = { 378 'biddingGroups': {}, 379 'adRenderURL': adsArray[0].renderURL, 380 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, 381 'interestGroupOwner': window.location.origin, 382 }; 383 serverResponseMsg.biddingGroups[window.location.origin] = [0]; 384 385 let serverResponse = 386 await BA.encodeServerResponse(serverResponseMsg, decoded); 387 388 // Mess up the array for a bit before computing hash to get the wrong hash, 389 // then undo. 390 serverResponse[0] ^= 0xBE; 391 let hashString = await BA.payloadHash(serverResponse); 392 await BA.authorizeServerResponseHashes([hashString]); 393 serverResponse[0] ^= 0xBE; 394 395 let auctionResult = await navigator.runAdAuction({ 396 'seller': window.location.origin, 397 'requestId': result.requestId, 398 'serverResponse': serverResponse, 399 'resolveToConfig': true, 400 }); 401 expectNoWinner(auctionResult); 402 }, 'Basic B&A auction - Wrong authorization'); 403 404 subsetTest(promise_test, async test => { 405 const uuid = generateUuid(test); 406 const adA = 'https://example.org/a'; 407 const adB = 'https://example.org/b'; 408 const adsArray = 409 [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; 410 await joinInterestGroup(test, uuid, {ads: adsArray}); 411 412 const result = await navigator.getInterestGroupAdAuctionData({ 413 coordinatorOrigin: await BA.configureCoordinator(), 414 seller: OTHER_ORIGIN1 415 }); 416 assert_true(result.requestId !== null); 417 assert_true(result.request.length > 0); 418 419 let decoded = await BA.decodeInterestGroupData(result.request); 420 421 let serverResponseMsg = { 422 'biddingGroups': {}, 423 'adRenderURL': adsArray[0].renderURL, 424 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, 425 'interestGroupOwner': window.location.origin, 426 }; 427 serverResponseMsg.biddingGroups[window.location.origin] = [0]; 428 429 let serverResponse = 430 await BA.encodeServerResponse(serverResponseMsg, decoded); 431 432 let hashString = await BA.payloadHash(serverResponse); 433 await BA.authorizeServerResponseHashes([hashString]); 434 435 let auctionResult = await navigator.runAdAuction({ 436 'seller': window.location.origin, 437 'requestId': result.requestId, 438 'serverResponse': serverResponse, 439 'resolveToConfig': true, 440 }); 441 expectNoWinner(auctionResult); 442 }, 'Basic B&A auction - Wrong seller'); 443 444 subsetTest(promise_test, async test => { 445 const uuid = generateUuid(test); 446 const adA = 'https://example.org/a'; 447 const adB = 'https://example.org/b'; 448 const adsArray = 449 [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; 450 await joinInterestGroup(test, uuid, {ads: adsArray}); 451 452 const result = await navigator.getInterestGroupAdAuctionData({ 453 coordinatorOrigin: await BA.configureCoordinator(), 454 seller: window.location.origin 455 }); 456 assert_true(result.requestId !== null); 457 assert_true(result.request.length > 0); 458 459 let decoded = await BA.decodeInterestGroupData(result.request); 460 461 let serverResponseMsg = { 462 'biddingGroups': {}, 463 'adRenderURL': adsArray[0].renderURL, 464 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, 465 'interestGroupOwner': window.location.origin, 466 }; 467 serverResponseMsg.biddingGroups[window.location.origin] = [0]; 468 469 let serverResponse = 470 await BA.encodeServerResponse(serverResponseMsg, decoded); 471 472 let hashString = await BA.payloadHash(serverResponse); 473 await BA.authorizeServerResponseHashes([hashString]); 474 475 let auctionResult = await navigator.runAdAuction({ 476 'seller': window.location.origin, 477 'requestId': token(), 478 'serverResponse': serverResponse, 479 'resolveToConfig': true, 480 }); 481 expectNoWinner(auctionResult); 482 }, 'Basic B&A auction - Wrong request Id'); 483 484 subsetTest(promise_test, async test => { 485 await BA.testWithMutatedServerResponse( 486 test, /*expectSuccess=*/ false, msg => {msg.error = {}}); 487 }, 'Basic B&A auction - response marked as error'); 488 489 subsetTest(promise_test, async test => { 490 await BA.testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { 491 msg.error = 4; 492 }); 493 }, 'Basic B&A auction - nonsense error field'); 494 495 subsetTest(promise_test, async test => { 496 await BA.testWithMutatedServerResponse( 497 test, /*expectSuccess=*/ false, msg => { 498 msg.error = {message: 'oh no'}; 499 }); 500 }, 'Basic B&A auction - response marked as error, with message'); 501 502 subsetTest(promise_test, async test => { 503 await BA.testWithMutatedServerResponse( 504 test, /*expectSuccess=*/ false, msg => { 505 msg.error = {message: {}}; 506 }); 507 }, 'Basic B&A auction - response marked as error, with bad message'); 508 509 subsetTest(promise_test, async test => { 510 await BA.testWithMutatedServerResponse( 511 test, /*expectSuccess=*/ false, msg => {msg.isChaff = true}); 512 }, 'Basic B&A auction - response marked as chaff'); 513 514 subsetTest(promise_test, async test => { 515 await BA.testWithMutatedServerResponse( 516 test, /*expectSuccess=*/ true, msg => {msg.isChaff = false}); 517 }, 'Basic B&A auction - response marked as non-chaff'); 518 519 subsetTest(promise_test, async test => { 520 await BA.testWithMutatedServerResponse( 521 test, /*expectSuccess=*/ false, msg => {msg.isChaff = 'yes'}); 522 }, 'Basic B&A auction - response marked as chaff incorrectly'); 523 524 subsetTest(promise_test, async test => { 525 await BA.testWithMutatedServerResponse( 526 test, /*expectSuccess=*/ false, 527 msg => {msg.topLevelSeller = 'https://example.org/'}); 528 }, 'Basic B&A auction - incorrectly includes topLevelSeller'); 529 530 subsetTest(promise_test, async test => { 531 await BA.testWithMutatedServerResponse( 532 test, /*expectSuccess=*/ false, msg => {msg.topLevelSeller = 1}); 533 }, 'Basic B&A auction - non-string top-level seller invalid'); 534 535 subsetTest(promise_test, async test => { 536 await BA.testWithMutatedServerResponse( 537 test, /*expectSuccess=*/ false, 538 msg => {msg.topLevelSeller = 'http://example.org/'}); 539 }, 'Basic B&A auction - http:// topLevelSeller is bad, too'); 540 541 subsetTest(promise_test, async test => { 542 await BA.testWithMutatedServerResponse( 543 test, /*expectSuccess=*/ false, msg => {msg.bid = '10 cents'}); 544 }, 'Basic B&A auction - non-number bid is invalid'); 545 546 subsetTest(promise_test, async test => { 547 await BA.testWithMutatedServerResponse( 548 test, /*expectSuccess=*/ true, msg => {msg.bid = 50}); 549 }, 'Basic B&A auction - positive bid is good'); 550 551 subsetTest(promise_test, async test => { 552 await BA.testWithMutatedServerResponse( 553 test, /*expectSuccess=*/ false, msg => {msg.bid = -50}); 554 }, 'Basic B&A auction - negative bid is bad'); 555 556 subsetTest(promise_test, async test => { 557 await BA.testWithMutatedServerResponse( 558 test, /*expectSuccess=*/ false, msg => {msg.bid = 0}); 559 }, 'Basic B&A auction - zero bid is bad'); 560 561 subsetTest(promise_test, async test => { 562 await BA.testWithMutatedServerResponse( 563 test, /*expectSuccess=*/ false, 564 msg => {msg.biddingGroups[window.location.origin] = []}); 565 }, 'Basic B&A auction - winning group did not bid'); 566 567 subsetTest(promise_test, async test => { 568 await BA.testWithMutatedServerResponse( 569 test, /*expectSuccess=*/ false, 570 msg => {msg.biddingGroups[window.location.origin] = [-1, 0]}); 571 }, 'Basic B&A auction - negative bidding group index'); 572 573 subsetTest(promise_test, async test => { 574 await BA.testWithMutatedServerResponse( 575 test, /*expectSuccess=*/ false, 576 msg => {msg.biddingGroups[window.location.origin] = [0, 1]}); 577 }, 'Basic B&A auction - too large bidding group index'); 578 579 subsetTest(promise_test, async test => { 580 await BA.testWithMutatedServerResponse( 581 test, /*expectSuccess=*/ false, msg => { 582 msg.interestGroupName += 'not'; 583 }); 584 }, 'Basic B&A auction - wrong IG name'); 585 586 subsetTest(promise_test, async test => { 587 await BA.testWithMutatedServerResponse( 588 test, /*expectSuccess=*/ false, async msg => { 589 await leaveInterestGroup(); 590 }); 591 }, 'Basic B&A auction - left IG in the middle'); 592 593 subsetTest(promise_test, async test => { 594 await BA.testWithMutatedServerResponse( 595 test, /*expectSuccess=*/ false, msg => { 596 msg.adRenderURL += 'not'; 597 }); 598 }, 'Basic B&A auction - ad URL not in ad'); 599 600 subsetTest(promise_test, async test => { 601 await BA.testWithMutatedServerResponse( 602 test, /*expectSuccess=*/ false, msg => { 603 msg.buyerReportingId = 'bid1'; 604 }); 605 }, 'Basic B&A auction - buyerReportingId not in ad'); 606 607 subsetTest(promise_test, async test => { 608 await BA.testWithMutatedServerResponse( 609 test, /*expectSuccess=*/ true, 610 msg => { 611 msg.buyerReportingId = 'bid1'; 612 }, 613 ig => { 614 ig.ads[0].buyerReportingId = 'bid1'; 615 ig.ads[1].buyerReportingId = 'bid2'; 616 }); 617 }, 'Basic B&A auction - buyerReportingId in ad'); 618 619 subsetTest(promise_test, async test => { 620 await BA.testWithMutatedServerResponse( 621 test, /*expectSuccess=*/ false, 622 msg => { 623 msg.buyerReportingId = 'bid2'; 624 }, 625 ig => { 626 ig.ads[0].buyerReportingId = 'bid1'; 627 ig.ads[1].buyerReportingId = 'bid2'; 628 }); 629 }, 'Basic B&A auction - buyerReportingId in wrong ad'); 630 631 subsetTest(promise_test, async test => { 632 await BA.testWithMutatedServerResponse( 633 test, /*expectSuccess=*/ false, msg => { 634 msg.buyerAndSellerReportingId = 'bsid1'; 635 }); 636 }, 'Basic B&A auction - buyerAndSellerReportingId not in ad'); 637 638 subsetTest(promise_test, async test => { 639 await BA.testWithMutatedServerResponse( 640 test, /*expectSuccess=*/ true, 641 msg => { 642 msg.buyerAndSellerReportingId = 'bsid1'; 643 }, 644 ig => { 645 ig.ads[0].buyerAndSellerReportingId = 'bsid1'; 646 ig.ads[1].buyerAndSellerReportingId = 'bsid2'; 647 }); 648 }, 'Basic B&A auction - buyerAndSellerReportingId in ad'); 649 650 subsetTest(promise_test, async test => { 651 await BA.testWithMutatedServerResponse( 652 test, /*expectSuccess=*/ false, 653 msg => { 654 msg.buyerAndSellerReportingId = 'bsid2'; 655 }, 656 ig => { 657 ig.ads[0].buyerAndSellerReportingId = 'bsid1'; 658 ig.ads[1].buyerAndSellerReportingId = 'bsid2'; 659 }); 660 }, 'Basic B&A auction - buyerAndSellerReportingId in wrong ad'); 661 662 subsetTest(promise_test, async test => { 663 await BA.testWithMutatedServerResponse( 664 test, /*expectSuccess=*/ false, msg => { 665 msg.components = ['https://example.org']; 666 }); 667 }, 'Basic B&A auction - ad component URL not in ad'); 668 669 subsetTest(promise_test, async test => { 670 await BA.testWithMutatedServerResponse( 671 test, /*expectSuccess=*/ true, 672 msg => { 673 msg.components = ['https://example.org']; 674 }, 675 ig => { 676 ig.adComponents = [{renderURL: 'https://example.org/'}]; 677 }); 678 }, 'Basic B&A auction - ad component URL in ad'); 679 680 subsetTest(promise_test, async test => { 681 let savedUuid; 682 let savedExpectUrls; 683 let result = await BA.testWithMutatedServerResponse( 684 test, /*expectSuccess=*/ true, 685 (msg, uuid) => { 686 savedUuid = uuid; 687 msg.components = [ 688 createTrackerURL(window.location.origin, uuid, 'track_get', 'c_a'), 689 createTrackerURL(window.location.origin, uuid, 'track_get', 'c_c') 690 ]; 691 savedExpectUrls = msg.components; 692 }, 693 (ig, uuid) => { 694 ig.ads[0].renderURL = createRenderURL(uuid, ` 695 const componentAds = window.fence.getNestedConfigs(); 696 // Limit the number of fenced frames we try to load at once, since loading too many 697 // completely breaks some Chrome test set ups, and we only really care about 3 of them 698 // anyway. 699 // 700 // See https://crbug.com/370533823 for more context. 701 const limit = 5; 702 for (var i = 0; i < Math.min(limit, componentAds.length); ++i) { 703 let fencedFrame = document.createElement("fencedframe"); 704 fencedFrame.mode = "opaque-ads"; 705 fencedFrame.config = componentAds[i]; 706 document.body.appendChild(fencedFrame); 707 }`); 708 ig.adComponents = [ 709 { 710 renderURL: createTrackerURL( 711 window.location.origin, uuid, 'track_get', 'c_a') 712 }, 713 { 714 renderURL: createTrackerURL( 715 window.location.origin, uuid, 'track_get', 'c_c') 716 }, 717 { 718 renderURL: createTrackerURL( 719 window.location.origin, uuid, 'track_get', 'c_c') 720 } 721 ]; 722 }); 723 createAndNavigateFencedFrame(test, result); 724 await waitForObservedRequests(savedUuid, savedExpectUrls); 725 }, 'Basic B&A auction - loading winning component ads'); 726 727 728 subsetTest(promise_test, async test => { 729 let savedUuid; 730 let result = await BA.testWithMutatedServerResponse( 731 test, /*expectWin=*/ true, 732 (msg, uuid) => { 733 savedUuid = uuid; 734 msg.winReportingURLs = { 735 'buyerReportingURLs': { 736 'interactionReportingURLs': { 737 'click': createBidderBeaconURL(uuid, 'i'), 738 'cluck': createBidderBeaconURL(uuid, 'u') 739 } 740 }, 741 'topLevelSellerReportingURLs': { 742 'interactionReportingURLs': { 743 'click': createSellerBeaconURL(uuid, 'i'), 744 'cluck': createSellerBeaconURL(uuid, 'u') 745 } 746 } 747 }; 748 }, 749 (ig, uuid) => { 750 ig.ads[0].renderURL = createRenderURL(uuid, `window.fence.reportEvent({ 751 eventType: 'click', 752 eventData: 'click_body', 753 destination: ['seller', 'buyer'] 754 }); 755 window.fence.reportEvent({ 756 eventType: 'cluck', 757 eventData: 'cluck_body', 758 destination: ['direct-seller'] 759 });`); 760 }); 761 762 createAndNavigateFencedFrame(test, result); 763 // The script triggers seller and buyer 'click', and seller 'cluck'. 764 // No tracker for page itself. 765 await waitForObservedRequests(savedUuid, [ 766 createBidderBeaconURL(savedUuid, 'i') + ', body: click_body', 767 createSellerBeaconURL(savedUuid, 'i') + ', body: click_body', 768 createSellerBeaconURL(savedUuid, 'u') + ', body: cluck_body' 769 ]); 770 }, 'Basic B&A auction --- beacon reporting'); 771 772 subsetTest(promise_test, async test => { 773 await BA.testWithMutatedServerResponse( 774 test, /*expectSuccess=*/ false, msg => { 775 msg.bidCurrency = 'cents'; 776 }); 777 }, 'Basic B&A auction - invalid ad currency'); 778 779 subsetTest(promise_test, async test => { 780 await BA.testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { 781 msg.bidCurrency = 'USD'; 782 }); 783 }, 'Basic B&A auction - valid ad currency'); 784 785 // Runs whatever is set in `mutators` on a minimal correct hybrid B&A/local 786 // auction, and expects either the B&A bid or local bid to win depending on 787 // expectBaWin. 788 async function testHybridAuctionWithMutatedServerResponse( 789 test, expectBaWin, mutators = { 790 responseMutator: undefined, 791 igMutator: undefined, 792 auctionConfigMutator: undefined, 793 expectUrlsMutator: undefined 794 }) { 795 const uuid = generateUuid(test); 796 const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); 797 const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); 798 const adsArray = 799 [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; 800 let interestGroup = { 801 ads: adsArray, 802 biddingLogicURL: createBiddingScriptURL({allowComponentAuction: true}) 803 }; 804 if (mutators.igMutator) { 805 mutators.igMutator(interestGroup, uuid); 806 } 807 await joinInterestGroup(test, uuid, interestGroup); 808 809 const result = await navigator.getInterestGroupAdAuctionData({ 810 coordinatorOrigin: await BA.configureCoordinator(), 811 seller: window.location.origin 812 }); 813 assert_true(result.requestId !== null); 814 assert_true(result.request.length > 0); 815 816 let decoded = await BA.decodeInterestGroupData(result.request); 817 818 // The server-side auction uses a bid of 10, for second ad, so it should 819 // win over the client-side component auctions bid of 9 (unless something 820 // mutators did made the server response unacceptable). 821 let serverResponseMsg = { 822 'biddingGroups': {}, 823 'adRenderURL': interestGroup.ads[1].renderURL, 824 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, 825 'interestGroupOwner': window.location.origin, 826 'topLevelSeller': window.location.origin, 827 'bid': 10, 828 }; 829 serverResponseMsg.biddingGroups[window.location.origin] = [0]; 830 if (mutators.responseMutator) { 831 mutators.responseMutator(serverResponseMsg, uuid); 832 } 833 834 let serverResponse = 835 await BA.encodeServerResponse(serverResponseMsg, decoded); 836 837 let hashString = await BA.payloadHash(serverResponse); 838 await BA.authorizeServerResponseHashes([hashString]); 839 840 let auctionConfig = { 841 seller: window.location.origin, 842 decisionLogicURL: createDecisionScriptURL(uuid), 843 interestGroupBuyers: [], 844 resolveToConfig: true, 845 componentAuctions: [ 846 { 847 seller: window.location.origin, 848 decisionLogicURL: createDecisionScriptURL(uuid), 849 interestGroupBuyers: [window.location.origin], 850 }, 851 { 852 seller: window.location.origin, 853 requestId: result.requestId, 854 serverResponse: serverResponse, 855 } 856 ] 857 }; 858 if (mutators.auctionConfigMutator) { 859 mutators.auctionConfigMutator(auctionConfig, uuid); 860 } 861 862 let auctionResult = await navigator.runAdAuction(auctionConfig); 863 expectSuccess(auctionResult); 864 createAndNavigateFencedFrame(test, auctionResult); 865 let expectUrls = expectBaWin ? [adB] : [adA]; 866 if (mutators.expectUrlsMutator) { 867 mutators.expectUrlsMutator(expectUrls, uuid); 868 } 869 await waitForObservedRequests(uuid, expectUrls); 870 } 871 872 subsetTest(promise_test, async test => { 873 await testHybridAuctionWithMutatedServerResponse( 874 test, /*expectBaWin=*/ false, { 875 responseMutator: (response) => { 876 delete response.topLevelSeller; 877 } 878 }); 879 }, 'Hybrid B&A auction --- missing top-level seller'); 880 881 subsetTest(promise_test, async test => { 882 await testHybridAuctionWithMutatedServerResponse( 883 test, /*expectBaWin=*/ false, { 884 responseMutator: (response) => { 885 response.topLevelSeller = 'https://www.example.org/'; 886 } 887 }); 888 }, 'Hybrid B&A auction --- wrong top-level seller'); 889 890 subsetTest(promise_test, async test => { 891 await testHybridAuctionWithMutatedServerResponse( 892 test, /*expectBaWin=*/ false, { 893 responseMutator: (response) => { 894 delete response.bid; 895 } 896 }); 897 }, 'Hybrid B&A auction --- no bid'); 898 899 subsetTest(promise_test, async test => { 900 await testHybridAuctionWithMutatedServerResponse( 901 test, /*expectBaWin=*/ true, { 902 responseMutator: (response) => { 903 response.bidCurrency = 'USD'; 904 } 905 }); 906 }, 'Hybrid B&A auction --- currency check --- nothing configured'); 907 908 subsetTest(promise_test, async test => { 909 await testHybridAuctionWithMutatedServerResponse( 910 test, /*expectBaWin=*/ false, { 911 responseMutator: (response) => { 912 response.bidCurrency = 'USD'; 913 }, 914 auctionConfigMutator: (auctionConfig) => { 915 auctionConfig.componentAuctions[1].sellerCurrency = 'EUR'; 916 } 917 }); 918 }, 'Hybrid B&A auction --- sellerCurrency mismatch'); 919 920 subsetTest(promise_test, async test => { 921 await testHybridAuctionWithMutatedServerResponse( 922 test, /*expectBaWin=*/ true, { 923 auctionConfigMutator: (auctionConfig) => { 924 auctionConfig.componentAuctions[1].sellerCurrency = 'EUR'; 925 } 926 }); 927 }, 'Hybrid B&A auction --- sellerCurrency config, no bidCurrency'); 928 929 subsetTest(promise_test, async test => { 930 await testHybridAuctionWithMutatedServerResponse( 931 test, /*expectBaWin=*/ false, { 932 responseMutator: (response) => { 933 response.bidCurrency = 'USD'; 934 }, 935 auctionConfigMutator: (auctionConfig) => { 936 auctionConfig.perBuyerCurrencies = {}; 937 auctionConfig.perBuyerCurrencies[window.location.origin] = 'EUR'; 938 } 939 }); 940 }, 'Hybrid B&A auction --- top perBuyerCurrencies mismatch'); 941 942 subsetTest(promise_test, async test => { 943 await testHybridAuctionWithMutatedServerResponse( 944 test, /*expectBaWin=*/ true, { 945 auctionConfigMutator: (auctionConfig) => { 946 auctionConfig.perBuyerCurrencies = {}; 947 auctionConfig.perBuyerCurrencies[window.location.origin] = 'EUR'; 948 } 949 }); 950 }, 'Hybrid B&A auction --- perBuyerCurrencies config, no bidCurrency'); 951 952 subsetTest(promise_test, async test => { 953 await testHybridAuctionWithMutatedServerResponse( 954 test, /*expectBaWin=*/ true, { 955 responseMutator: (response) => { 956 response.bidCurrency = 'USD'; 957 response.bid = 50; 958 response.adMetadata = '[1, "hello"]'; 959 }, 960 auctionConfigMutator: (auctionConfig, uuid) => { 961 let trackTopSeller = createSellerReportURL(uuid, 'top'); 962 auctionConfig.decisionLogicURL = createDecisionScriptURL(uuid, { 963 // Note: this will throw on the local bid as well as an incorrect 964 // server bid. 965 scoreAd: ` 966 let origin = '${window.location.origin}'; 967 if (!(adMetadata instanceof Array) || 968 adMetadata.length !== 2 || 969 adMetadata[0] !== 1 || 970 adMetadata[1] !== 'hello') { 971 throw 'bad adMetadata ' + JSON.stringify(adMetadata); 972 } 973 if (bid !== 50) 974 throw 'bad bid ' + bid; 975 if (browserSignals.bidCurrency !== 'USD') 976 throw 'bad currency ' + browserSignals.bidCurrency; 977 if (browserSignals.interestGroupOwner != origin) 978 throw 'bad IG owner ' + browserSignals.interestGroupOwner; 979 if (browserSignals.componentSeller != origin) { 980 throw 'bad component seller ' + 981 browserSignals.interestGroupOwner; 982 }` 983 }); 984 } 985 }); 986 }, 'Hybrid B&A auction --- bid info passed to top-level scoreAd'); 987 988 subsetTest(promise_test, async test => { 989 await testHybridAuctionWithMutatedServerResponse( 990 test, /*expectBaWin=*/ true, { 991 responseMutator: (response) => { 992 response.bidCurrency = 'USD'; 993 response.bid = 50; 994 response.buyerAndSellerReportingId = 'bsid2'; 995 }, 996 igMutator: (ig) => { 997 ig.ads[0].buyerAndSellerReportingId = 'bsid1'; 998 ig.ads[1].buyerAndSellerReportingId = 'bsid2'; 999 }, 1000 auctionConfigMutator: (auctionConfig, uuid) => { 1001 let trackTopSeller = createSellerReportURL(uuid, 'top'); 1002 auctionConfig.decisionLogicURL = createDecisionScriptURL(uuid, { 1003 reportResult: `sendReportTo("${trackTopSeller}&" + 1004 browserSignals.bid + '&' + 1005 browserSignals.buyerAndSellerReportingId)` 1006 }); 1007 }, 1008 expectUrlsMutator: (expectUrls, uuid) => { 1009 expectUrls.push(createSellerReportURL(uuid, 'top') + '&50&bsid2'); 1010 } 1011 }); 1012 }, 'Hybrid B&A auction --- bid info passed to top-level reporting'); 1013 1014 subsetTest(promise_test, async test => { 1015 await testHybridAuctionWithMutatedServerResponse( 1016 test, /*expectBaWin=*/ true, { 1017 igMutator: (ig, uuid) => { 1018 ig.ads[1].renderURL = 1019 createRenderURL(uuid, `window.fence.reportEvent({ 1020 eventType: 'click', 1021 eventData: 'click_body', 1022 destination: ['component-seller', 'buyer'] 1023 }); 1024 window.fence.reportEvent({ 1025 eventType: 'clack', 1026 eventData: 'clack_body', 1027 destination: ['direct-seller'] 1028 });`); 1029 }, 1030 responseMutator: (response, uuid) => { 1031 response.winReportingURLs = { 1032 'buyerReportingURLs': { 1033 'interactionReportingURLs': { 1034 'click': createBidderBeaconURL(uuid, 'i'), 1035 'clack': createBidderBeaconURL(uuid, 'a') 1036 } 1037 }, 1038 'componentSellerReportingURLs': { 1039 'interactionReportingURLs': { 1040 'click': createSellerBeaconURL(uuid, 'i'), 1041 'clack': createSellerBeaconURL(uuid, 'a') 1042 } 1043 } 1044 }; 1045 }, 1046 expectUrlsMutator: (expectUrls, uuid) => { 1047 // The script triggers seller and buyer 'click', and seller 'clack'. 1048 // No tracker for page itself. 1049 expectUrls.pop(); 1050 expectUrls.push( 1051 createBidderBeaconURL(uuid, 'i') + ', body: click_body', 1052 createSellerBeaconURL(uuid, 'i') + ', body: click_body', 1053 createSellerBeaconURL(uuid, 'a') + ', body: clack_body'); 1054 } 1055 }); 1056 }, 'Hybrid B&A auction --- beacon reporting'); 1057 1058 ///////////////////////////////////////////////////////////////////////////// 1059 // updateIfOlderThanMs tests 1060 // 1061 // NOTE: Due to the lack of mock time in wpt, these tests just exercise the code 1062 // paths and ensure that no crash occurs -- they don't otherwise verify 1063 // behavior. 1064 ///////////////////////////////////////////////////////////////////////////// 1065 1066 subsetTest(promise_test, async test => { 1067 await BA.testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { 1068 msg.updateGroups = 1069 {[window.location.origin]: [{index: 2048, updateIfOlderThanMs: 1000}]}; 1070 }); 1071 }, 'Basic B&A auction - updateIfOlderThanMs - invalid index'); 1072 1073 1074 subsetTest(promise_test, async test => { 1075 await BA.testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { 1076 msg.updateGroups = { 1077 [window.location.origin]: [ 1078 {index: 0, updateIfOlderThanMs: 1000}, 1079 {index: 1, updateIfOlderThanMs: 10000} 1080 ] 1081 }; 1082 }); 1083 }, 'Basic B&A auction - updateIfOlderThanMs'); 1084 1085 ///////////////////////////////////////////////////////////////////////////// 1086 // 1087 // K-anonymity support tests 1088 // 1089 ///////////////////////////////////////////////////////////////////////////// 1090 1091 // Runs responseMutator on a minimal correct server response, and expects 1092 // either success/failure based on expectWin. 1093 async function kAnonTestWithMutatedServerResponse( 1094 test, expectWin, responseMutator, igMutator = undefined) { 1095 const uuid = generateUuid(test); 1096 const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); 1097 const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); 1098 const adsArray = 1099 [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; 1100 let ig = { 1101 owner: window.location.origin, 1102 name: DEFAULT_INTEREST_GROUP_NAME, 1103 ads: adsArray, 1104 biddingLogicURL: createBiddingScriptURL({allowComponentAuction: true}) 1105 }; 1106 if (igMutator) { 1107 igMutator(ig, uuid); 1108 } 1109 1110 const encoder = new TextEncoder(); 1111 const adARenderKAnonKey = 1112 encoder.encode(`AdBid\n${ig.owner}/\n${ig.biddingLogicURL}\n${adA}`); 1113 const adBRenderKAnonKey = 1114 encoder.encode(`AdBid\n${ig.owner}/\n${ig.biddingLogicURL}\n${adB}`); 1115 const adARenderKAnonKeyHash = new Uint8Array( 1116 await window.crypto.subtle.digest('SHA-256', adARenderKAnonKey)); 1117 const adBRenderKAnonKeyHash = new Uint8Array( 1118 await window.crypto.subtle.digest('SHA-256', adBRenderKAnonKey)); 1119 1120 const adANameReportingIdKAnonKey = encoder.encode( 1121 `NameReport\n${ig.owner}/\n${ig.biddingLogicURL}\n${adA}\n${ig.name}`); 1122 const adBNameReportingIdKAnonKey = encoder.encode( 1123 `NameReport\n${ig.owner}/\n${ig.biddingLogicURL}\n${adB}\n${ig.name}`); 1124 const adANameReportingIdKAnonKeyHash = new Uint8Array( 1125 await window.crypto.subtle.digest('SHA-256', adANameReportingIdKAnonKey)); 1126 const adBNameReportingIdKAnonKeyHash = new Uint8Array( 1127 await window.crypto.subtle.digest('SHA-256', adBNameReportingIdKAnonKey)); 1128 1129 const adABuyerReportingIdKAnonKey = encoder.encode(`BuyerReportId\n${ 1130 ig.owner}/\n${ig.biddingLogicURL}\n${adA}\n${adA.buyerReportingId}`); 1131 const adBBuyerReportingIdKAnonKey = encoder.encode(`BuyerReportId\n${ 1132 ig.owner}/\n${ig.biddingLogicURL}\n${adB}\n${adB.buyerReportingId}`); 1133 const adABuyerReportingIdKAnonKeyHash = 1134 new Uint8Array(await window.crypto.subtle.digest( 1135 'SHA-256', adABuyerReportingIdKAnonKey)); 1136 const adBBuyerReportingIdKAnonKeyHash = 1137 new Uint8Array(await window.crypto.subtle.digest( 1138 'SHA-256', adBBuyerReportingIdKAnonKey)); 1139 1140 const adABASReportingIdKAnonKey = 1141 encoder.encode(`BuyerAndSellerReportId\n${ig.owner}/\n${ 1142 ig.biddingLogicURL}\n${adA}\n${adA.buyerAndSellerReportingId}`); 1143 const adBBASReportingIdKAnonKey = 1144 encoder.encode(`BuyerAndSellerReportId\n${ig.owner}/\n${ 1145 ig.biddingLogicURL}\n${adB}\n${adB.buyerAndSellerReportingId}`); 1146 const adABASReportingIdKAnonKeyHash = new Uint8Array( 1147 await window.crypto.subtle.digest('SHA-256', adABASReportingIdKAnonKey)); 1148 const adBBASReportingIdKAnonKeyHash = new Uint8Array( 1149 await window.crypto.subtle.digest('SHA-256', adBBASReportingIdKAnonKey)); 1150 1151 const hashes = { 1152 adARenderKAnonKeyHash: adARenderKAnonKeyHash, 1153 adBRenderKAnonKeyHash: adBRenderKAnonKeyHash, 1154 adANameReportingIdKAnonKeyHash: adANameReportingIdKAnonKeyHash, 1155 adBNameReportingIdKAnonKeyHash: adBNameReportingIdKAnonKeyHash, 1156 adABuyerReportingIdKAnonKeyHash: adABuyerReportingIdKAnonKeyHash, 1157 adBBuyerReportingIdKAnonKeyHash: adBBuyerReportingIdKAnonKeyHash, 1158 adABASReportingIdKAnonKeyHash: adABASReportingIdKAnonKeyHash, 1159 adBBASReportingIdKAnonKeyHash: adBBASReportingIdKAnonKeyHash 1160 }; 1161 1162 await joinInterestGroup(test, uuid, ig); 1163 1164 const result = await navigator.getInterestGroupAdAuctionData({ 1165 coordinatorOrigin: await BA.configureCoordinator(), 1166 seller: window.location.origin 1167 }); 1168 assert_true(result.requestId !== null); 1169 assert_true(result.request.length > 0); 1170 1171 let decoded = await BA.decodeInterestGroupData(result.request); 1172 1173 let serverResponseMsg = { 1174 'biddingGroups': {}, 1175 'adRenderURL': ig.ads[0].renderURL, 1176 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, 1177 'interestGroupOwner': window.location.origin, 1178 }; 1179 serverResponseMsg.biddingGroups[window.location.origin] = [0]; 1180 1181 await responseMutator(serverResponseMsg, ig, hashes, uuid); 1182 1183 let serverResponse = 1184 await BA.encodeServerResponse(serverResponseMsg, decoded); 1185 1186 let hashString = await BA.payloadHash(serverResponse); 1187 await BA.authorizeServerResponseHashes([hashString]); 1188 1189 let auctionResult = await navigator.runAdAuction({ 1190 'seller': window.location.origin, 1191 'interestGroupBuyers': [window.location.origin], 1192 'requestId': result.requestId, 1193 'serverResponse': serverResponse, 1194 'resolveToConfig': true, 1195 }); 1196 if (expectWin) { 1197 expectSuccess(auctionResult); 1198 return auctionResult; 1199 } else { 1200 expectNoWinner(auctionResult); 1201 } 1202 } 1203 1204 subsetTest(promise_test, async test => { 1205 await kAnonTestWithMutatedServerResponse( 1206 test, /*expectSuccess=*/ true, (msg, ig, hashes) => { 1207 msg.kAnonWinnerJoinCandidates = { 1208 adRenderURLHash: hashes.adARenderKAnonKeyHash, 1209 reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, 1210 }; 1211 }); 1212 }, 'Basic B&A auction - winner with candidates'); 1213 1214 subsetTest(promise_test, async test => { 1215 await kAnonTestWithMutatedServerResponse( 1216 test, /*expectSuccess=*/ false, (msg, ig, hashes) => { 1217 msg.kAnonWinnerJoinCandidates = { 1218 adRenderURLHash: new Uint8Array(), 1219 reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, 1220 }; 1221 }); 1222 }, 'Basic B&A auction - winner with bad render hash'); 1223 1224 subsetTest(promise_test, async test => { 1225 await kAnonTestWithMutatedServerResponse( 1226 test, /*expectSuccess=*/ false, (msg, ig, hashes) => { 1227 msg.kAnonWinnerJoinCandidates = { 1228 adRenderURLHash: hashes.adARenderKAnonKeyHash, 1229 reportingIdHash: new Uint8Array(), 1230 }; 1231 }); 1232 }, 'Basic B&A auction - winner with bad reporting hash'); 1233 1234 subsetTest(promise_test, async test => { 1235 await kAnonTestWithMutatedServerResponse( 1236 test, /*expectSuccess=*/ false, (msg, ig, hashes) => { 1237 delete msg.adRenderURL; 1238 delete msg.interestGroupName; 1239 delete msg.interestGroupOwner; 1240 msg.kAnonGhostWinners = [{ 1241 kAnonJoinCandidates: { 1242 // missing adRenderURLHash 1243 reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, 1244 }, 1245 interestGroupIndex: 0, 1246 owner: window.location.origin, 1247 }] 1248 }); 1249 }, 'Basic B&A auction - invalid ghost winner'); 1250 1251 subsetTest(promise_test, async test => { 1252 await kAnonTestWithMutatedServerResponse( 1253 test, /*expectSuccess=*/ false, (msg, ig, hashes) => { 1254 delete msg.adRenderURL; 1255 delete msg.interestGroupName; 1256 delete msg.interestGroupOwner; 1257 msg.kAnonGhostWinners = [{ 1258 kAnonJoinCandidates: { 1259 adRenderURLHash: hashes.adARenderKAnonKeyHash, 1260 reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, 1261 }, 1262 interestGroupIndex: 0, 1263 owner: window.location.origin, 1264 }] 1265 }); 1266 }, 'Basic B&A auction - only ghost winner'); 1267 1268 subsetTest(promise_test, async test => { 1269 await kAnonTestWithMutatedServerResponse( 1270 test, /*expectSuccess=*/ false, (msg, ig, hashes) => { 1271 delete msg.adRenderURL; 1272 delete msg.interestGroupName; 1273 delete msg.interestGroupOwner; 1274 msg.kAnonGhostWinners = [ 1275 { 1276 kAnonJoinCandidates: { 1277 adRenderURLHash: hashes.adARenderKAnonKeyHash, 1278 reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, 1279 }, 1280 interestGroupIndex: 0, 1281 owner: window.location.origin, 1282 }, 1283 { 1284 kAnonJoinCandidates: { 1285 adRenderURLHash: hashes.adBRenderKAnonKeyHash, 1286 reportingIdHash: hashes.adBNameReportingIdKAnonKeyHash, 1287 }, 1288 interestGroupIndex: 0, 1289 owner: window.location.origin, 1290 } 1291 ] 1292 }); 1293 }, 'Basic B&A auction - multiple ghost winners'); 1294 1295 subsetTest(promise_test, async test => { 1296 await kAnonTestWithMutatedServerResponse( 1297 test, /*expectSuccess=*/ false, (msg, ig, hashes) => { 1298 delete msg.adRenderURL; 1299 delete msg.interestGroupName; 1300 delete msg.interestGroupOwner; 1301 msg.kAnonGhostWinners = [ 1302 { 1303 kAnonJoinCandidates: { 1304 adRenderURLHash: hashes.adARenderKAnonKeyHash, 1305 reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, 1306 }, 1307 interestGroupIndex: 0, 1308 owner: window.location.origin, 1309 }, 1310 { 1311 kAnonJoinCandidates: { 1312 // missing adRenderURLHash 1313 reportingIdHash: hashes.adBNameReportingIdKAnonKeyHash, 1314 }, 1315 interestGroupIndex: 0, 1316 owner: window.location.origin, 1317 } 1318 ] 1319 }); 1320 }, 'Basic B&A auction - second ghost winner invalid'); 1321 1322 subsetTest(promise_test, async test => { 1323 await kAnonTestWithMutatedServerResponse( 1324 test, /*expectSuccess=*/ true, (msg, ig, hashes) => { 1325 msg.kAnonWinnerJoinCandidates = { 1326 adRenderURLHash: hashes.adARenderKAnonKeyHash, 1327 reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, 1328 }; 1329 msg.kAnonGhostWinners = [{ 1330 kAnonJoinCandidates: { 1331 adRenderURLHash: hashes.adBRenderKAnonKeyHash, 1332 reportingIdHash: hashes.adBNameReportingIdKAnonKeyHash, 1333 }, 1334 interestGroupIndex: 0, 1335 owner: window.location.origin, 1336 }]; 1337 }); 1338 }, 'Basic B&A auction - winner with ghost winner'); 1339 1340 subsetTest(promise_test, async test => { 1341 await kAnonTestWithMutatedServerResponse( 1342 test, /*expectSuccess=*/ true, (msg, ig, hashes) => { 1343 msg.kAnonWinnerJoinCandidates = { 1344 adRenderURLHash: hashes.adARenderKAnonKeyHash, 1345 reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, 1346 }; 1347 msg.kAnonGhostWinners = [{ 1348 kAnonJoinCandidates: { 1349 adRenderURLHash: hashes.adBRenderKAnonKeyHash, 1350 reportingIdHash: hashes.adBNameReportingIdKAnonKeyHash, 1351 }, 1352 interestGroupIndex: 0, 1353 owner: window.location.origin, 1354 ghostWinnerForTopLevelAuction: { 1355 // missing adRenderURL 1356 modifiedBid: 100, 1357 }, 1358 }]; 1359 }); 1360 }, 'Basic B&A auction - invalid GhostWinnerForTopLevelAuction'); 1361 1362 subsetTest(promise_test, async test => { 1363 await kAnonTestWithMutatedServerResponse( 1364 test, /*expectSuccess=*/ true, (msg, ig, hashes) => { 1365 msg.kAnonWinnerJoinCandidates = { 1366 adRenderURLHash: hashes.adARenderKAnonKeyHash, 1367 reportingIdHash: hashes.adANameReportingIdKAnonKeyHash, 1368 }; 1369 msg.kAnonGhostWinners = [{ 1370 kAnonJoinCandidates: { 1371 adRenderURLHash: hashes.adBRenderKAnonKeyHash, 1372 reportingIdHash: hashes.adBNameReportingIdKAnonKeyHash, 1373 }, 1374 interestGroupIndex: 0, 1375 owner: window.location.origin, 1376 ghostWinnerForTopLevelAuction: { 1377 adRenderURL: ig.ads[1].renderURL, 1378 modifiedBid: 100, 1379 }, 1380 }]; 1381 }); 1382 }, 'Basic B&A auction - winner with full ghost winner'); 1383 1384 // TODO(behamilton): Add Multi-seller k-anon tests. 1385 // TODO(behamilton): Add k-anon tests with different reporting IDs. 1386 1387 /* Some things that are not currently tested that probably should be; this is 1388 not exhaustive, merely to keep track of things that come to mind as tests are 1389 written: 1390 1391 - forDebugOnly --- it will be straightforward now, but will break. 1392 - Some of the parsing details that need to match the spec language exactly. 1393 */