Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
// META: script=/common/utils.js
// META: script=resources/fledge-util.sub.js
// META: script=/common/subset-tests.js
// META: timeout=long
// META: variant=?1-last
"use strict;"
// This file contains tests for additional bids and negative targeting.
//
// TODO:
// - test that an additional bid with some correct signatures can be negative
// targeted for those negative interest groups whose signatures match.
// - test that additional bids can be fetched using an iframe navigation.
// - test that additional bids are not fetched using an iframe navigation for
// which the `adAuctionHeaders=true` attribute is not specified.
// - test that additional bids are not fetched using a Fetch request for which
// `adAuctionHeaders: true` is not specified.
// - test that an additional bid with an incorrect seller and / or top-level
// seller is not used included in an auction.
// - lots of tests for different types of malformed additional bids, e.g.
// missing fields, malformed signature, invalid currency code,
// missing joining origin for multiple negative interest groups, etc.
// - test that correctly formatted additional bids are included in an auction
// when fetched alongside malformed additional bid headers by a Fetch
// request (both invalid headers and invalid additional bids)
// - test that an additional bid is rejected if its from a buyer who is not
// allowed to participate in the auction.
// - test that an additional bid is rejected if its currency doesn't match the
// buyer's associated per-buyer currency from the auction config.
// - test that correctly formatted additional bids are included in an auction
// when fetched alongside malformed additional bid headers by an iframe
// navigation (both invalid headers and invalid additional bids).
// - test that reportWin is not used for reporting an additional bid win.
// - test that additional bids can *not* be fetched from iframe subresource
// requests.
// - test that an auction nonce can only be used once, and a second auction
// trying to reuse an auction immediately fails.
// - test that an auction nonce must be created in the same window/tab as the
// call to runAdAuction.
// - test reportAdditionalBidWin with each of no metadata, null metadata, and
// an object metadata.
// - test that an auction running in one tab can't see an additional bid loaded
// in a new tab.
// - test that two auctions running with different nonces only get the
// additional bids fetched with their auction nonce.
// - test that two auctions running with different nonces only get the
// additional bids fetched with their auction nonce, when both additional
// bids are retrieved with one fetch.
// - test that a multiseller auction with two component auctions can direct
// additional bids to the correct component auctions.
// - test that two auctions running with different nonces only get the
// additional bids fetched with their auction nonce.
// - test that two auctions running with different nonces only get the
// additional bids fetched with their auction nonce, when both additional
// bids are retrieved with one fetch.
// - test that an additional bid can compete against an interest group bid and
// lose.
// - test that an additional bid can compete against an interest group bid and
// win.
// - test that a malformed additional bid causes that one additional bid to be
// ignored, but the rest of the auction (and other additional bids, even
// from the same fetch) continue on.
// - test (in join-leave-ad-interest-group.https.window.js) that an IG that
// provides `additionalBidKey` fails if the key fails to decode, or if
// that IG also provides `ads`, or if it provides `updateURL`.
// - test that an IG update cannot cause a regular interest group (one that
// does not provide `additionalBidKey`) to become a negative interest
// group (one that does provide `additionalBidKey`).
// - test (in auction-config-passed-to-worklets.https.window.js) that a
// multi-seller auction fails if the top-level auction provides
// a value for `additionalBids`.
// - test (in auction-config-passed-to-worklets.https.window.js) that an auction
// fails if it provides `additionalBids` but not `auctionNonce`, or if it
// provides `additionalBids` but not `interestGroupBuyers`.
// The auction is run with the seller being the same as the document origin.
// The request to fetch additional bids must be issued to the seller's origin
// for ad auction headers interception to associate it with this auction.
const SINGLE_SELLER_AUCTION_SELLER = window.location.origin;
const ADDITIONAL_BID_SECRET_KEY = 'nWGxne/9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A=';
const ADDITIONAL_BID_PUBLIC_KEY = '11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=';
// Single-seller auction with a single buyer who places a single additional
// bid. As the only bid, this wins.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const buyer = OTHER_ORIGIN1;
const additionalBid = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer, 'horses', 1.99);
await runAdditionalBidTest(
test, uuid, [buyer], auctionNonce,
additionalBidHelper.fetchAdditionalBids(seller, [additionalBid]),
/*highestScoringOtherBid=*/0,
/*winningAdditionalBidId=*/'horses');
}, 'single valid additional bid');
// Single-seller auction with a two buyers competing with additional bids.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const buyer1 = OTHER_ORIGIN1;
const additionalBid1 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer1, 'horses', 1.99);
const buyer2 = OTHER_ORIGIN2;
const additionalBid2 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer2, 'planes', 2.99);
await runAdditionalBidTest(
test, uuid, [buyer1, buyer2], auctionNonce,
additionalBidHelper.fetchAdditionalBids(
seller, [additionalBid1, additionalBid2]),
/*highestScoringOtherBid=*/1.99,
/*winningAdditionalBidId=*/'planes');
}, 'two valid additional bids');
// Same as the test above, except that this uses two Fetch requests instead of
// one to retrieve the additional bids.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const buyer1 = OTHER_ORIGIN1;
const additionalBid1 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer1, 'horses', 1.99);
const buyer2 = OTHER_ORIGIN2;
const additionalBid2 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer2, 'planes', 2.99);
await runAdditionalBidTest(
test, uuid, [buyer1, buyer2], auctionNonce,
Promise.all([
additionalBidHelper.fetchAdditionalBids(seller, [additionalBid1]),
additionalBidHelper.fetchAdditionalBids(seller, [additionalBid2])
]),
/*highestScoringOtherBid=*/1.99,
/*winningAdditionalBidId=*/'planes');
}, 'two valid additional bids from two distinct Fetch requests');
// Single-seller auction with a single buyer who places a single additional
// bid with the wrong auctionNonce in the bid, causing the bid to fail.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const auctionNonceInBid = crypto.randomUUID();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const buyer = OTHER_ORIGIN1;
const additionalBid = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer, 'horses', 1.99);
additionalBidHelper.setBidAuctionNonceOverride(
additionalBid, auctionNonceInBid);
await runAdditionalBidTestNoWinner(
test, uuid, [buyer], auctionNonce,
additionalBidHelper.fetchAdditionalBids(seller, [additionalBid]),
/*highestScoringOtherBid=*/0);
}, 'single valid additional bid with wrong auctionNonce in bid');
// Single-seller auction with a single buyer who places a single additional
// bid with no auctionNonce in the bid, causing the bid to fail.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const buyer = OTHER_ORIGIN1;
const additionalBid = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer, 'horses', 1.99);
additionalBidHelper.removeAuctionNonceFromBid(additionalBid);
await runAdditionalBidTestNoWinner(
test, uuid, [buyer], auctionNonce,
additionalBidHelper.fetchAdditionalBids(seller, [additionalBid]),
/*highestScoringOtherBid=*/0);
}, 'single valid additional bid with no auctionNonce in bid');
// Single-seller auction with a single buyer who places a single additional
// bid with auctionNonce and bidNonce in the bid (but no seller nonce), causing
// the bid to fail.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const sellerNonce = crypto.randomUUID();
const bidNonce =
await additionalBidHelper.computeBidNonce(auctionNonce, sellerNonce);
const seller = SINGLE_SELLER_AUCTION_SELLER;
const additionalBidOverrides = {
bidNonce: bidNonce,
};
const buyer = OTHER_ORIGIN1;
const additionalBid = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer, 'horses', 1.99,
/*additionalBidOverrides=*/ additionalBidOverrides);
await runAdditionalBidTestNoWinner(
test, uuid, [buyer], auctionNonce,
additionalBidHelper.fetchAdditionalBids(seller, [additionalBid]),
/*highestScoringOtherBid=*/0);
}, 'single valid additional bid with auctionNonce and bidNonce in bid (but no seller nonce)');
// Single-seller auction with a single buyer who places a single additional
// bid that uses seller nonce / bidNonce. As the only bid, this wins.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const sellerNonce = crypto.randomUUID();
const bidNonce =
await additionalBidHelper.computeBidNonce(auctionNonce, sellerNonce);
const seller = SINGLE_SELLER_AUCTION_SELLER;
const additionalBidOverrides = {
bidNonce: bidNonce,
};
const buyer = OTHER_ORIGIN1;
const additionalBid = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer, 'horses', 1.99,
/*additionalBidOverrides=*/ additionalBidOverrides);
additionalBidHelper.setSellerNonce(additionalBid, sellerNonce);
additionalBidHelper.removeAuctionNonceFromBid(additionalBid);
await runAdditionalBidTest(
test, uuid, [buyer], auctionNonce,
additionalBidHelper.fetchAdditionalBids(seller, [additionalBid]),
/*highestScoringOtherBid=*/0,
/*winningAdditionalBidId=*/'horses');
}, 'single valid additional bid with seller nonce');
// Single-seller auction with a single buyer who places a single additional bid
// that uses seller nonce, but no bidNonce. Since the bidNonce is missing, there
// is no winner.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const sellerNonce = crypto.randomUUID();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const buyer = OTHER_ORIGIN1;
const additionalBid = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer, 'horses', 1.99);
additionalBidHelper.setSellerNonce(additionalBid, sellerNonce);
await runAdditionalBidTestNoWinner(
test, uuid, [buyer], auctionNonce,
additionalBidHelper.fetchAdditionalBids(seller, [additionalBid]),
/*highestScoringOtherBid=*/0);
}, 'single additional bid with seller nonce with no bidNonce');
// Single-seller auction with a single buyer who places a single additional bid
// that uses seller nonce, but no bidNonce or auctionNonce. Since the bidNonce
// is missing, there is no winner.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const sellerNonce = crypto.randomUUID();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const buyer = OTHER_ORIGIN1;
const additionalBid = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer, 'horses', 1.99);
additionalBidHelper.setSellerNonce(additionalBid, sellerNonce);
additionalBidHelper.removeAuctionNonceFromBid(additionalBid);
await runAdditionalBidTestNoWinner(
test, uuid, [buyer], auctionNonce,
additionalBidHelper.fetchAdditionalBids(seller, [additionalBid]),
/*highestScoringOtherBid=*/0);
}, 'single additional bid with seller nonce with no bidNonce or auctionNonce');
// Single-seller auction with a single buyer who places a single additional
// bid that uses seller nonce / bidNonce. Since the bidNonce is invalid there is
// no winner.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const sellerNonce = crypto.randomUUID();
// Intentionally use the wrong bidNonce, base64(sha256("incorrect")).
const bidNonce = 'ID01Nr1irTOscLfqPU9eELbVLr0Mt1goQaBTrrtxhqM=';
const seller = SINGLE_SELLER_AUCTION_SELLER;
const additionalBidOverrides = {
bidNonce: bidNonce,
};
const buyer = OTHER_ORIGIN1;
const additionalBid = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer, 'horses', 1.99,
/*additionalBidOverrides=*/ additionalBidOverrides);
additionalBidHelper.setSellerNonce(additionalBid, sellerNonce);
additionalBidHelper.removeAuctionNonceFromBid(additionalBid);
await runAdditionalBidTestNoWinner(
test, uuid, [buyer], auctionNonce,
additionalBidHelper.fetchAdditionalBids(seller, [additionalBid]),
/*highestScoringOtherBid=*/0);
}, 'single invalid additional bid with seller nonce');
// Single-seller auction with a two buyers competing with additional bids, using
// seller nonce.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const sellerNonce1 = crypto.randomUUID();
const sellerNonce2 = crypto.randomUUID();
const bidNonce1 =
await additionalBidHelper.computeBidNonce(auctionNonce, sellerNonce1);
const bidNonce2 =
await additionalBidHelper.computeBidNonce(auctionNonce, sellerNonce2);
const seller = SINGLE_SELLER_AUCTION_SELLER;
const additionalBidOverrides1 = {
bidNonce: bidNonce1,
};
const additionalBidOverrides2 = {
bidNonce: bidNonce2,
};
const buyer1 = OTHER_ORIGIN1;
const additionalBid1 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer1, 'horses', 1.99,
/*additionalBidOverrides=*/ additionalBidOverrides1);
additionalBidHelper.setSellerNonce(additionalBid1, sellerNonce1);
additionalBidHelper.removeAuctionNonceFromBid(additionalBid1);
const buyer2 = OTHER_ORIGIN2;
const additionalBid2 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer2, 'planes', 2.99,
/*additionalBidOverrides=*/ additionalBidOverrides2);
additionalBidHelper.setSellerNonce(additionalBid2, sellerNonce2);
additionalBidHelper.removeAuctionNonceFromBid(additionalBid2);
await runAdditionalBidTest(
test, uuid, [buyer1, buyer2], auctionNonce,
additionalBidHelper.fetchAdditionalBids(
seller, [additionalBid1, additionalBid2]),
/*highestScoringOtherBid=*/1.99,
/*winningAdditionalBidId=*/'planes');
}, 'two valid additional bids using seller nonce');
// Single-seller auction with a single buyer who places a single additional
// bid that uses seller nonce / bidNonce, but also auctionNonce in the bid. As
// exactly one of bidNonce / auctionNonce is allowed in the bid, this fails.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const sellerNonce = crypto.randomUUID();
const bidNonce =
await additionalBidHelper.computeBidNonce(auctionNonce, sellerNonce);
const seller = SINGLE_SELLER_AUCTION_SELLER;
const additionalBidOverrides = {
bidNonce: bidNonce,
};
const buyer = OTHER_ORIGIN1;
const additionalBid = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer, 'horses', 1.99,
/*additionalBidOverrides=*/ additionalBidOverrides);
additionalBidHelper.setSellerNonce(additionalBid, sellerNonce);
// Don't remove the auctionNonce from the bid.
await runAdditionalBidTestNoWinner(
test, uuid, [buyer], auctionNonce,
additionalBidHelper.fetchAdditionalBids(seller, [additionalBid]),
/*highestScoringOtherBid=*/0);
}, 'single additional bid with seller nonce, but also with auctionNonce in bid');
// Single-seller auction with a single buyer who places a single additional
// bid with auctionNonce and bidNonce in the bid (with seller nonce), causing
// the bid to fail.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const sellerNonce = crypto.randomUUID();
const bidNonce =
await additionalBidHelper.computeBidNonce(auctionNonce, sellerNonce);
const seller = SINGLE_SELLER_AUCTION_SELLER;
const additionalBidOverrides = {
bidNonce: bidNonce,
};
const buyer = OTHER_ORIGIN1;
const additionalBid = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer, 'horses', 1.99,
/*additionalBidOverrides=*/ additionalBidOverrides);
additionalBidHelper.setSellerNonce(additionalBid, sellerNonce);
await runAdditionalBidTestNoWinner(
test, uuid, [buyer], auctionNonce,
additionalBidHelper.fetchAdditionalBids(seller, [additionalBid]),
/*highestScoringOtherBid=*/0);
}, 'single valid additional bid with auctionNonce and bidNonce in bid (with seller nonce)');
// Single-seller auction with a single additional bid. Because this additional
// bid is filtered by negative targeting, this auction has no winner.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const negativeInterestGroupName = 'already-owns-a-plane';
const buyer = OTHER_ORIGIN1;
const additionalBid = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer, 'planes', 2.99);
additionalBidHelper.addNegativeInterestGroup(
additionalBid, negativeInterestGroupName);
additionalBidHelper.signWithSecretKeys(
additionalBid, [ADDITIONAL_BID_SECRET_KEY]);
await joinNegativeInterestGroup(
test, buyer, negativeInterestGroupName, ADDITIONAL_BID_PUBLIC_KEY);
await runBasicFledgeTestExpectingNoWinner(
test, uuid,
{ interestGroupBuyers: [buyer],
auctionNonce: auctionNonce,
additionalBids: additionalBidHelper.fetchAdditionalBids(
seller, [additionalBid])});
}, 'one additional bid filtered by negative targeting, so auction has no ' +
'winner');
// Single-seller auction with a two buyers competing with additional bids.
// The higher of these has a negative interest group specified, and that
// negative interest group has been joined, so the lower bid wins.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const negativeInterestGroupName = 'already-owns-a-plane';
const buyer1 = OTHER_ORIGIN1;
const additionalBid1 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer1, 'horses', 1.99);
const buyer2 = OTHER_ORIGIN2;
const additionalBid2 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer2, 'planes', 2.99);
additionalBidHelper.addNegativeInterestGroup(
additionalBid2, negativeInterestGroupName);
additionalBidHelper.signWithSecretKeys(
additionalBid2, [ADDITIONAL_BID_SECRET_KEY]);
await joinNegativeInterestGroup(
test, buyer2, negativeInterestGroupName, ADDITIONAL_BID_PUBLIC_KEY);
await runAdditionalBidTest(
test, uuid, [buyer1, buyer2], auctionNonce,
additionalBidHelper.fetchAdditionalBids(
seller, [additionalBid1, additionalBid2]),
/*highestScoringOtherBid=*/0,
/*winningAdditionalBidId=*/'horses');
}, 'higher additional bid is filtered by negative targeting, so ' +
'lower additional bid win');
// Same as above, except that the bid is missing a signature, so that the
// negative targeting interest group is ignored, and the higher bid, which
// would have otherwise been filtered by negative targeting, wins.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const negativeInterestGroupName = 'already-owns-a-plane';
const buyer1 = OTHER_ORIGIN1;
const additionalBid1 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer1, 'horses', 1.99);
const buyer2 = OTHER_ORIGIN2;
const additionalBid2 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer2, 'planes', 2.99);
additionalBidHelper.addNegativeInterestGroup(
additionalBid2, negativeInterestGroupName);
await joinNegativeInterestGroup(
test, buyer2, negativeInterestGroupName, ADDITIONAL_BID_PUBLIC_KEY);
await runAdditionalBidTest(
test, uuid, [buyer1, buyer2], auctionNonce,
additionalBidHelper.fetchAdditionalBids(
seller, [additionalBid1, additionalBid2]),
/*highestScoringOtherBid=*/1.99,
/*winningAdditionalBidId=*/'planes');
}, 'higher additional bid is filtered by negative targeting, but it is ' +
'missing a signature, so it still wins');
// Same as above, except that the bid is signed incorrectly, so that the
// negative targeting interest group is ignored, and the higher bid, which
// would have otherwise been filtered by negative targeting, wins.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const negativeInterestGroupName = 'already-owns-a-plane';
const buyer1 = OTHER_ORIGIN1;
const additionalBid1 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer1, 'horses', 1.99);
const buyer2 = OTHER_ORIGIN2;
const additionalBid2 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer2, 'planes', 2.99);
additionalBidHelper.addNegativeInterestGroup(
additionalBid2, negativeInterestGroupName);
additionalBidHelper.incorrectlySignWithSecretKeys(
additionalBid2, [ADDITIONAL_BID_SECRET_KEY]);
await joinNegativeInterestGroup(
test, buyer2, negativeInterestGroupName, ADDITIONAL_BID_PUBLIC_KEY);
await runAdditionalBidTest(
test, uuid, [buyer1, buyer2], auctionNonce,
additionalBidHelper.fetchAdditionalBids(
seller, [additionalBid1, additionalBid2]),
/*highestScoringOtherBid=*/1.99,
/*winningAdditionalBidId=*/'planes');
}, 'higher additional bid is filtered by negative targeting, but it has an ' +
'invalid signature, so it still wins');
// A test of an additional bid with multiple negative interest groups.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const negativeInterestGroupName1 = 'already-owns-a-plane';
const negativeInterestGroupName2 = 'another-negative-interest-group';
const buyer1 = OTHER_ORIGIN1;
const additionalBid1 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer1, 'horses', 1.99);
const buyer2 = OTHER_ORIGIN2;
const additionalBid2 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer2, 'planes', 2.99);
additionalBidHelper.addNegativeInterestGroups(
additionalBid2, [negativeInterestGroupName1, negativeInterestGroupName2],
/*joiningOrigin=*/window.location.origin);
additionalBidHelper.signWithSecretKeys(
additionalBid2, [ADDITIONAL_BID_SECRET_KEY]);
await joinNegativeInterestGroup(
test, buyer2, negativeInterestGroupName1, ADDITIONAL_BID_PUBLIC_KEY);
await runAdditionalBidTest(
test, uuid, [buyer1, buyer2], auctionNonce,
additionalBidHelper.fetchAdditionalBids(
seller, [additionalBid1, additionalBid2]),
/*highestScoringOtherBid=*/0,
/*winningAdditionalBidId=*/'horses');
}, 'higher additional bid is filtered by negative targeting by two negative ' +
'interest groups, and since one is on the device, the lower bid wins');
// Same as above, but with a mismatched joining origin.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const negativeInterestGroupName1 = 'already-owns-a-plane';
const negativeInterestGroupName2 = 'another-negative-interest-group';
const buyer1 = OTHER_ORIGIN1;
const additionalBid1 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer1, 'horses', 1.99);
const buyer2 = OTHER_ORIGIN2;
const additionalBid2 = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer2, 'planes', 2.99);
additionalBidHelper.addNegativeInterestGroups(
additionalBid2, [negativeInterestGroupName1, negativeInterestGroupName2],
/*joiningOrigin=*/OTHER_ORIGIN1);
additionalBidHelper.signWithSecretKeys(
additionalBid2, [ADDITIONAL_BID_SECRET_KEY]);
await joinNegativeInterestGroup(
test, buyer2, negativeInterestGroupName1, ADDITIONAL_BID_PUBLIC_KEY);
await runAdditionalBidTest(
test, uuid, [buyer1, buyer2], auctionNonce,
additionalBidHelper.fetchAdditionalBids(
seller, [additionalBid1, additionalBid2]),
/*highestScoringOtherBid=*/1.99,
/*winningAdditionalBidId=*/'planes');
}, 'higher additional bid is filtered by negative targeting by two negative ' +
'interest groups, but because of a joining origin mismatch, it still wins');
// Ensure that trusted seller signals are retrieved for additional bids.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const auctionNonce = await navigator.createAuctionNonce();
const seller = SINGLE_SELLER_AUCTION_SELLER;
const buyer = OTHER_ORIGIN1;
const additionalBid = additionalBidHelper.createAdditionalBid(
uuid, auctionNonce, seller, buyer, 'horses', 1.99);
let renderURL = createRenderURL(uuid);
await runBasicFledgeTestExpectingWinner(
test, uuid,
{ interestGroupBuyers: [buyer],
auctionNonce: auctionNonce,
additionalBids: additionalBidHelper.fetchAdditionalBids(
seller, [additionalBid]),
decisionLogicURL: createDecisionScriptURL(
uuid,
{ scoreAd:
`if(!"${renderURL}" in trustedScoringSignals.renderURL) ` +
'throw "missing trusted signals";'}),
trustedScoringSignalsURL: TRUSTED_SCORING_SIGNALS_URL});
}, 'trusted seller signals retrieved for additional bids');