0

Reland "Reland "Modify B&A key fetcher code to retain the full key ID""

This is a reland of commit 9f44fe6906

Original change's description:
> Reland "Modify B&A key fetcher code to retain the full key ID"
>
> This is a reland of commit 5624b16cc2
>
> Original change's description:
> > Modify B&A key fetcher code to retain the full key ID
> >
> > Changes the B&A key fetcher code so that it stores the full key
> > identifier instead of the first two bytes parsed as a hexadecimal
> > number. This will be needed to support features like Private Model
> > Training that include the full key ID as part of the message.
> >
> > This CL also does some refactoring in order to support per-adtech
> > keys/origin scoped keys as described in
> > https://github.com/WICG/turtledove/issues/1334.
> >
> > NO_IFTTT=Just moving the enums.
> >
> > Bug: 390160246
> > Change-Id: I62ded0175dbbc559363685ada995c91ef2d9d2dc
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6265963
> > Reviewed-by: Orr Bernstein <orrb@google.com>
> > Commit-Queue: Russ Hamilton <behamilton@google.com>
> > Auto-Submit: Russ Hamilton <behamilton@google.com>
> > Cr-Commit-Position: refs/heads/main@{#1423990}
>
> Bug: 390160246
> Change-Id: I968311418baf9b487654f294f065f893a5b217ac
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6299239
> Commit-Queue: Russ Hamilton <behamilton@google.com>
> Reviewed-by: Orr Bernstein <orrb@google.com>
> Cr-Commit-Position: refs/heads/main@{#1424577}

Bug: 390160246
Change-Id: I9f885c1fd667e094dd2cdf17eb21237fda1057e3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6297865
Reviewed-by: Orr Bernstein <orrb@google.com>
Commit-Queue: Russ Hamilton <behamilton@google.com>
Cr-Commit-Position: refs/heads/main@{#1424802}
This commit is contained in:
Russ Hamilton
2025-02-25 14:22:19 -08:00
committed by Chromium LUCI CQ
parent a5b2d3103e
commit 61333e40ef
27 changed files with 548 additions and 408 deletions

@ -1251,6 +1251,7 @@ source_set("browser") {
"interest_group/interest_group_real_time_report_util.h",
"interest_group/interest_group_storage.cc",
"interest_group/interest_group_storage.h",
"interest_group/interest_group_storage_metric_types.h",
"interest_group/interest_group_update.cc",
"interest_group/interest_group_update.h",
"interest_group/interest_group_update_manager.cc",

@ -24,6 +24,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/not_fatal_until.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
@ -786,11 +787,12 @@ std::optional<std::string> AdAuctionServiceImpl::GetCookieDeprecationLabel() {
}
void AdAuctionServiceImpl::GetBiddingAndAuctionServerKey(
const url::Origin& scope_origin,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(
base::expected<BiddingAndAuctionServerKey, std::string>)> callback) {
GetInterestGroupManager().GetBiddingAndAuctionServerKey(
std::move(coordinator), std::move(callback));
scope_origin, coordinator, std::move(callback));
}
AdAuctionServiceImpl::AdAuctionServiceImpl(
@ -1179,7 +1181,7 @@ void AdAuctionServiceImpl::LoadAuctionDataAndKeyForNextQueuedRequest() {
// GetBiddingAndAuctionServerKey can call its callback synchronously, and
// during the last loop iteration the callback may invalidate `state`.
GetInterestGroupManager().GetBiddingAndAuctionServerKey(
coordinator,
seller, coordinator,
base::BindOnce(
&AdAuctionServiceImpl::OnGotOneBiddingAndAuctionServerKey,
weak_ptr_factory_.GetWeakPtr(), state.request_id, seller));
@ -1246,8 +1248,12 @@ void AdAuctionServiceImpl::OnGotAuctionDataAndKey(
return;
}
uint32_t key_id = 0;
bool success =
base::HexStringToUInt(std::string_view(ba_key.id).substr(0, 2), &key_id);
DCHECK(success);
auto maybe_key_config = quiche::ObliviousHttpHeaderKeyConfig::Create(
ba_key.id, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
key_id, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
EVP_HPKE_AES_256_GCM);
CHECK(maybe_key_config.ok()) << maybe_key_config.status();

@ -110,6 +110,7 @@ class CONTENT_EXPORT AdAuctionServiceImpl final
network::mojom::ClientSecurityStatePtr GetClientSecurityState() override;
std::optional<std::string> GetCookieDeprecationLabel() override;
void GetBiddingAndAuctionServerKey(
const url::Origin& scope_origin,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(base::expected<BiddingAndAuctionServerKey,
std::string>)> callback) override;

@ -723,7 +723,8 @@ class AuctionProcessManagerTest
TrustedSignalsCacheImpl trusted_signals_cache_{
/*url_loader_factory=*/nullptr,
base::BindRepeating(
[](const std::optional<url::Origin>& coordinator,
[](const url::Origin& scope_origin,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(base::expected<BiddingAndAuctionServerKey,
std::string>)> callback) {
std::move(callback).Run(

@ -1829,12 +1829,13 @@ class MockTrustedSignalsCacheImpl : public TrustedSignalsCacheImpl {
CHECK(coordinator_key_callback_);
std::move(coordinator_key_callback_)
.Run(BiddingAndAuctionServerKey{"key whose value does not matter",
/*id=*/42});
/*id=*/"42"});
}
private:
// Expects only to see requests for `kCoordinatorOrigin`.
void GetCoordinatorKeyCallback(
const url::Origin& scope_origin,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(
base::expected<BiddingAndAuctionServerKey, std::string>)> callback) {
@ -2898,6 +2899,7 @@ class AuctionRunnerTest : public RenderViewHostTestHarness,
return std::nullopt;
}
void GetBiddingAndAuctionServerKey(
const url::Origin& scope_origin,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(base::expected<BiddingAndAuctionServerKey,
std::string>)> callback) override {

@ -29,6 +29,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/not_fatal_until.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/interest_group/auction_metrics_recorder.h"
#include "content/browser/interest_group/auction_process_manager.h"
@ -312,6 +313,7 @@ AuctionWorkletManager::WorkletOwner::WorkletOwner(
if (!base::FeatureList::IsEnabled(features::kFledgeUseKVv2SignalsCache)) {
waiting_on_trusted_signals_kvv2_public_key_ = true;
worklet_manager->delegate()->GetBiddingAndAuctionServerKey(
url::Origin::Create(worklet_info_.signals_url.value_or(GURL())),
std::move(worklet_info_.trusted_signals_coordinator),
base::BindOnce(&AuctionWorkletManager::WorkletOwner::
OnTrustedSignalsKVv2KeyFetched,
@ -524,9 +526,13 @@ void AuctionWorkletManager::WorkletOwner::OnTrustedSignalsKVv2KeyFetched(
// more debugging information rather than just pass a nullptr to bidder/seller
// worklet.
if (key_or_error.has_value()) {
uint32_t key_id = 0;
bool success = base::HexStringToUInt(
std::string_view(key_or_error->id).substr(0, 2), &key_id);
DCHECK(success);
trusted_signals_kvv2_public_key_ =
auction_worklet::mojom::TrustedSignalsPublicKey::New(key_or_error->key,
key_or_error->id);
key_id);
}
LoadWorkletIfReady(number_of_bidder_threads);

@ -117,6 +117,7 @@ class CONTENT_EXPORT AuctionWorkletManager {
virtual std::optional<std::string> GetCookieDeprecationLabel() = 0;
virtual void GetBiddingAndAuctionServerKey(
const url::Origin& scope_origin,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(base::expected<BiddingAndAuctionServerKey,
std::string>)> callback) = 0;

@ -120,8 +120,10 @@ bool PublicKeyEvaluateHelper(
const auction_worklet::mojom::TrustedSignalsPublicKey* public_key,
base::expected<BiddingAndAuctionServerKey, std::string> expected_key) {
if (expected_key.has_value() && public_key) {
return expected_key->id == public_key->id &&
expected_key->key == public_key->key;
uint32_t key_id = 0;
EXPECT_TRUE(base::HexStringToUInt(
std::string_view(expected_key->id).substr(0, 2), &key_id));
return key_id == public_key->id && expected_key->key == public_key->key;
} else if (!expected_key.has_value() && !public_key) {
return true;
} else {
@ -952,6 +954,7 @@ class AuctionWorkletManagerTest : public RenderViewHostTestHarness,
return std::nullopt;
}
void GetBiddingAndAuctionServerKey(
const url::Origin& scope_origin,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(base::expected<BiddingAndAuctionServerKey,
std::string>)> callback) override {
@ -3252,6 +3255,7 @@ class AuctionWorkletManagerKVv2Test : public AuctionWorkletManagerTest {
~AuctionWorkletManagerKVv2Test() override { DCHECK(!fetch_key_callback_); }
void GetBiddingAndAuctionServerKey(
const url::Origin& scope_origin,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(base::expected<BiddingAndAuctionServerKey,
std::string>)> callback) override {
@ -3275,13 +3279,13 @@ class AuctionWorkletManagerKVv2Test : public AuctionWorkletManagerTest {
bool synchronous_fetch_ = true;
base::expected<BiddingAndAuctionServerKey, std::string> key_{
BiddingAndAuctionServerKey("public-key", /*id=*/0)};
BiddingAndAuctionServerKey("public-key", /*id=*/"00")};
};
TEST_F(AuctionWorkletManagerKVv2Test,
SingleBidderWorkletSyncFetchedKeyBeforeProcessAssigned) {
std::vector<base::expected<BiddingAndAuctionServerKey, std::string>>
expected_keys = {BiddingAndAuctionServerKey("public-key", /*id=*/0),
expected_keys = {BiddingAndAuctionServerKey("public-key", /*id=*/"00"),
base::unexpected("Failed to fetch public key.")};
for (const auto& key : expected_keys) {
@ -3312,7 +3316,7 @@ TEST_F(AuctionWorkletManagerKVv2Test,
TEST_F(AuctionWorkletManagerKVv2Test,
SingleBidderWorkletAsyncFetchedKeyBeforeProcessAssigned) {
std::vector<base::expected<BiddingAndAuctionServerKey, std::string>>
expected_keys = {BiddingAndAuctionServerKey("public-key", /*id=*/0),
expected_keys = {BiddingAndAuctionServerKey("public-key", /*id=*/"00"),
base::unexpected("Failed to fetch public key.")};
auction_process_manager_->DeferOnLaunchedForHandles();
synchronous_fetch_ = false;
@ -3347,7 +3351,7 @@ TEST_F(AuctionWorkletManagerKVv2Test,
TEST_F(AuctionWorkletManagerKVv2Test,
SingleBidderWorkletAsyncFetchedKeyAfterProcessAssigned) {
std::vector<base::expected<BiddingAndAuctionServerKey, std::string>>
expected_keys = {BiddingAndAuctionServerKey("public-key", /*id=*/0),
expected_keys = {BiddingAndAuctionServerKey("public-key", /*id=*/"00"),
base::unexpected("Failed to fetch public key.")};
auction_process_manager_->DeferOnLaunchedForHandles();
synchronous_fetch_ = false;
@ -3581,7 +3585,7 @@ TEST_F(AuctionWorkletManagerKVv2Test, BidderWorkletWithoutCoordinator) {
TEST_F(AuctionWorkletManagerKVv2Test,
SingleSellerWorkletSyncFetchedKeyBeforeProcessAssigned) {
std::vector<base::expected<BiddingAndAuctionServerKey, std::string>>
expected_keys = {BiddingAndAuctionServerKey("public-key", /*id=*/0),
expected_keys = {BiddingAndAuctionServerKey("public-key", /*id=*/"00"),
base::unexpected("Failed to fetch public key.")};
for (const auto& key : expected_keys) {
@ -3613,7 +3617,7 @@ TEST_F(AuctionWorkletManagerKVv2Test,
TEST_F(AuctionWorkletManagerKVv2Test,
SingleSellerWorkletAsyncFetchedKeyBeforeProcessAssigned) {
std::vector<base::expected<BiddingAndAuctionServerKey, std::string>>
expected_keys = {BiddingAndAuctionServerKey("public-key", /*id=*/0),
expected_keys = {BiddingAndAuctionServerKey("public-key", /*id=*/"00"),
base::unexpected("Failed to fetch public key.")};
auction_process_manager_->DeferOnLaunchedForHandles();
synchronous_fetch_ = false;
@ -3649,7 +3653,7 @@ TEST_F(AuctionWorkletManagerKVv2Test,
TEST_F(AuctionWorkletManagerKVv2Test,
SingleSellerWorkletAsyncFetchedKeyAfterProcessAssigned) {
std::vector<base::expected<BiddingAndAuctionServerKey, std::string>>
expected_keys = {BiddingAndAuctionServerKey("public-key", /*id=*/0),
expected_keys = {BiddingAndAuctionServerKey("public-key", /*id=*/"00"),
base::unexpected("Failed to fetch public key.")};
auction_process_manager_->DeferOnLaunchedForHandles();
synchronous_fetch_ = false;

@ -11,6 +11,8 @@
#include "base/rand_util.h"
#include "content/browser/interest_group/interest_group_features.h"
#include "content/browser/interest_group/interest_group_manager_impl.h"
#include "content/browser/interest_group/interest_group_storage.pb.h"
#include "content/browser/interest_group/interest_group_storage_metric_types.h"
#include "net/base/isolation_info.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
@ -74,8 +76,134 @@ const struct {
{kBiddingAndAuctionAWSCoordinatorOrigin,
kBiddingAndAuctionAWSCoordinatorKeyURL},
};
std::vector<BiddingAndAuctionServerKey> ParseKeysList(
const base::Value::List* keys_list) {
std::vector<BiddingAndAuctionServerKey> keys;
for (const auto& entry : *keys_list) {
BiddingAndAuctionServerKey key;
const base::Value::Dict* key_dict = entry.GetIfDict();
if (!key_dict) {
continue;
}
const std::string* key_value = key_dict->FindString("key");
if (!key_value) {
continue;
}
if (!base::Base64Decode(*key_value, &key.key)) {
continue;
}
const std::string* id_value = key_dict->FindString("id");
// Previous versions depend on the first two characters being hex digits.
if (!id_value || id_value->size() < 2 ||
!base::IsHexDigit((*id_value)[0]) ||
!base::IsHexDigit((*id_value)[1])) {
continue;
}
key.id = *id_value;
keys.push_back(std::move(key));
}
return keys;
}
} // namespace
BiddingAndAuctionKeySet::BiddingAndAuctionKeySet(
std::vector<BiddingAndAuctionServerKey> keys)
: keys_(std::move(keys)) {}
BiddingAndAuctionKeySet::~BiddingAndAuctionKeySet() = default;
BiddingAndAuctionKeySet::BiddingAndAuctionKeySet(
BiddingAndAuctionKeySet&& keyset) = default;
BiddingAndAuctionKeySet& BiddingAndAuctionKeySet::operator=(
BiddingAndAuctionKeySet&& keyset) = default;
bool BiddingAndAuctionKeySet::HasKeys() const {
if (!keys_.empty()) {
return true;
}
return false;
}
std::optional<BiddingAndAuctionServerKey> BiddingAndAuctionKeySet::GetRandomKey(
const url::Origin& scoped_origin) const {
if (!keys_.empty()) {
return keys_[base::RandInt(0, keys_.size() - 1)];
}
return std::nullopt;
}
std::string BiddingAndAuctionKeySet::AsBinaryProto() const {
BiddingAndAuctionServerKeysProtos keys_protos;
for (const auto& key : keys_) {
BiddingAndAuctionServerKeysProtos_BiddingAndAuctionServerKeyProto*
key_proto = keys_protos.add_keys();
uint32_t key_id = 0;
DCHECK(
base::HexStringToUInt(std::string_view(key.id).substr(0, 2), &key_id));
key_proto->set_key(key.key);
key_proto->set_id(key_id);
key_proto->set_id_str(key.id);
}
std::string key_protos_str;
if (!keys_protos.SerializeToString(&key_protos_str)) {
base::UmaHistogramEnumeration(
"Storage.InterestGroup.ProtoSerializationResult."
"BiddingAndAuctionServerKeyProtos",
InterestGroupStorageProtoSerializationResult::kFailed);
return "";
}
base::UmaHistogramEnumeration(
"Storage.InterestGroup.ProtoSerializationResult."
"BiddingAndAuctionServerKeyProtos",
InterestGroupStorageProtoSerializationResult::kSucceeded);
return key_protos_str;
}
/*static*/ std::optional<BiddingAndAuctionKeySet>
BiddingAndAuctionKeySet::FromBinaryProto(std::string key_blob) {
BiddingAndAuctionServerKeysProtos keys_protos;
bool success = keys_protos.ParseFromString(key_blob);
if (!success) {
base::UmaHistogramEnumeration(
"Storage.InterestGroup.ProtoDeserializationResult."
"BiddingAndAuctionServerKeyProtos",
InterestGroupStorageProtoDeserializationResult::kFailed);
return std::nullopt;
}
base::UmaHistogramEnumeration(
"Storage.InterestGroup.ProtoDeserializationResult."
"BiddingAndAuctionServerKeyProtos",
InterestGroupStorageProtoDeserializationResult::kSucceeded);
std::vector<BiddingAndAuctionServerKey> keys;
keys.reserve(keys_protos.keys_size());
for (auto& key_proto : *keys_protos.mutable_keys()) {
if (key_proto.id_str().empty()) {
std::string id_str;
base::AppendHexEncodedByte((key_proto.id() >> 4) & 0x0F, id_str);
base::AppendHexEncodedByte(key_proto.id() & 0x0F, id_str);
keys.emplace_back(std::move(*key_proto.mutable_key()), id_str);
} else {
keys.emplace_back(std::move(*key_proto.mutable_key()),
std::move(*key_proto.mutable_id_str()));
}
}
return BiddingAndAuctionKeySet(std::move(keys));
}
BiddingAndAuctionServerKeyFetcher::CallbackQueueItem::CallbackQueueItem(
BiddingAndAuctionServerKeyFetcherCallback callback,
url::Origin scope_origin)
: callback(std::move(callback)), scope_origin(std::move(scope_origin)) {}
BiddingAndAuctionServerKeyFetcher::CallbackQueueItem::~CallbackQueueItem() =
default;
BiddingAndAuctionServerKeyFetcher::CallbackQueueItem::CallbackQueueItem(
CallbackQueueItem&& item) = default;
BiddingAndAuctionServerKeyFetcher::CallbackQueueItem&
BiddingAndAuctionServerKeyFetcher::CallbackQueueItem::operator=(
CallbackQueueItem&& item) = default;
BiddingAndAuctionServerKeyFetcher::PerCoordinatorFetcherState::
PerCoordinatorFetcherState() = default;
BiddingAndAuctionServerKeyFetcher::PerCoordinatorFetcherState::
@ -95,6 +223,7 @@ BiddingAndAuctionServerKeyFetcher::BiddingAndAuctionServerKeyFetcher(
DCHECK_EQ(coordinator.scheme(), url::kHttpsScheme);
PerCoordinatorFetcherState state;
state.key_url = GURL(key_config.key_url);
state.version = 1;
if (!state.key_url.is_valid()) {
continue;
}
@ -119,6 +248,7 @@ BiddingAndAuctionServerKeyFetcher::BiddingAndAuctionServerKeyFetcher(
PerCoordinatorFetcherState state;
state.key_url = GURL(kv.second.GetString());
state.version = 1;
if (!state.key_url.is_valid()) {
fetcher_state_map_.erase(coordinator);
continue;
@ -132,6 +262,7 @@ BiddingAndAuctionServerKeyFetcher::BiddingAndAuctionServerKeyFetcher(
if (key_url.is_valid()) {
PerCoordinatorFetcherState state;
state.key_url = std::move(key_url);
state.version = 1;
fetcher_state_map_.insert_or_assign(default_gcp_coordinator_,
std::move(state));
}
@ -148,13 +279,15 @@ void BiddingAndAuctionServerKeyFetcher::MaybePrefetchKeys() {
}
did_prefetch_keys_ = true;
for (auto& [coordinator, state] : fetcher_state_map_) {
if (state.keys.size() == 0 || state.expiration < base::Time::Now()) {
FetchKeys(coordinator, state, base::DoNothing());
if (!state.keyset || !state.keyset->HasKeys() ||
state.expiration < base::Time::Now()) {
FetchKeys(url::Origin(), coordinator, state, base::DoNothing());
}
}
}
void BiddingAndAuctionServerKeyFetcher::GetOrFetchKey(
const url::Origin& scope_origin,
const std::optional<url::Origin>& maybe_coordinator,
BiddingAndAuctionServerKeyFetcherCallback callback) {
const url::Origin& coordinator = maybe_coordinator.has_value()
@ -174,31 +307,40 @@ void BiddingAndAuctionServerKeyFetcher::GetOrFetchKey(
}
// If we have keys and they haven't expired just call the callback now.
if (state.keys.size() > 0 && state.expiration > base::Time::Now()) {
if (state.keyset && state.keyset->HasKeys() &&
state.expiration > base::Time::Now()) {
std::optional<BiddingAndAuctionServerKey> key =
state.keyset->GetRandomKey(scope_origin);
if (!key) {
std::move(callback).Run(
base::unexpected<std::string>("No key for adtech origin"));
return;
}
// Use a random key from the set to limit the server's ability to identify
// us based on the key we use.
base::UmaHistogramBoolean("Ads.InterestGroup.ServerAuction.KeyFetch.Cached",
true);
std::move(callback).Run(
state.keys[base::RandInt(0, state.keys.size() - 1)]);
std::move(callback).Run(std::move(*key));
return;
}
base::UmaHistogramBoolean("Ads.InterestGroup.ServerAuction.KeyFetch.Cached",
false);
FetchKeys(coordinator, state, std::move(callback));
FetchKeys(scope_origin, coordinator, state, std::move(callback));
}
void BiddingAndAuctionServerKeyFetcher::FetchKeys(
const url::Origin& scope_origin,
const url::Origin& coordinator,
PerCoordinatorFetcherState& state,
BiddingAndAuctionServerKeyFetcherCallback callback) {
state.fetch_start = base::TimeTicks::Now();
state.queue.push_back(std::move(callback));
state.queue.emplace_back(std::move(callback), scope_origin);
if (state.queue.size() > 1) {
return;
}
state.keys.clear();
state.keyset.reset();
if (base::FeatureList::IsEnabled(features::kFledgeStoreBandAKeysInDB)) {
manager_->GetBiddingAndAuctionServerKeys(
@ -213,19 +355,26 @@ void BiddingAndAuctionServerKeyFetcher::FetchKeys(
void BiddingAndAuctionServerKeyFetcher::OnFetchKeysFromDatabaseComplete(
const url::Origin& coordinator,
std::pair<base::Time, std::vector<BiddingAndAuctionServerKey>>
expiration_and_keys) {
if (expiration_and_keys.second.empty() ||
expiration_and_keys.first < base::Time::Now()) {
std::pair<base::Time, std::string> expiration_and_keys) {
if (expiration_and_keys.first < base::Time::Now()) {
base::UmaHistogramBoolean(
"Ads.InterestGroup.ServerAuction.KeyFetch.DBCached", false);
FetchKeysFromNetwork(coordinator);
} else {
base::UmaHistogramBoolean(
"Ads.InterestGroup.ServerAuction.KeyFetch.DBCached", true);
CacheKeysAndRunAllCallbacks(coordinator, expiration_and_keys.second,
expiration_and_keys.first);
return;
}
std::optional<BiddingAndAuctionKeySet> keyset =
BiddingAndAuctionKeySet::FromBinaryProto(expiration_and_keys.second);
if (!keyset) {
base::UmaHistogramBoolean(
"Ads.InterestGroup.ServerAuction.KeyFetch.DBCached", false);
FetchKeysFromNetwork(coordinator);
return;
}
base::UmaHistogramBoolean("Ads.InterestGroup.ServerAuction.KeyFetch.DBCached",
true);
CacheKeysAndRunAllCallbacks(coordinator, std::move(*keyset),
expiration_and_keys.first);
}
void BiddingAndAuctionServerKeyFetcher::FetchKeysFromNetwork(
@ -267,6 +416,7 @@ void BiddingAndAuctionServerKeyFetcher::OnFetchKeysFromNetworkComplete(
base::TimeTicks::Now() - state.network_fetch_start);
base::UmaHistogramBoolean(
"Ads.InterestGroup.ServerAuction.KeyFetch.NetworkCached", was_cached);
DCHECK_EQ(1u, state.version);
data_decoder::DataDecoder::ParseJsonIsolated(
*response,
base::BindOnce(&BiddingAndAuctionServerKeyFetcher::OnParsedKeys,
@ -287,56 +437,34 @@ void BiddingAndAuctionServerKeyFetcher::OnParsedKeys(
return;
}
const base::Value::List* key_values = response_dict->FindList("keys");
if (!key_values) {
const base::Value::List* keys_list = response_dict->FindList("keys");
if (!keys_list) {
FailAllCallbacks(coordinator);
return;
}
std::vector<BiddingAndAuctionServerKey> keys;
for (const auto& entry : *key_values) {
BiddingAndAuctionServerKey key;
const base::Value::Dict* key_dict = entry.GetIfDict();
if (!key_dict) {
continue;
}
const std::string* key_value = key_dict->FindString("key");
if (!key_value) {
continue;
}
if (!base::Base64Decode(*key_value, &key.key)) {
continue;
}
const std::string* id_value = key_dict->FindString("id");
unsigned int key_id;
if (!id_value || id_value->size() == 0 ||
!base::HexStringToUInt(id_value->substr(0, 2), &key_id) ||
key_id > 0xFF) {
continue;
}
key.id = key_id;
keys.push_back(std::move(key));
}
std::vector<BiddingAndAuctionServerKey> keys = ParseKeysList(keys_list);
if (keys.size() == 0) {
FailAllCallbacks(coordinator);
return;
}
BiddingAndAuctionKeySet keyset(std::move(keys));
base::Time expiration = base::Time::Now() + kKeyRequestInterval;
CacheKeysAndRunAllCallbacks(coordinator, keys, expiration);
if (base::FeatureList::IsEnabled(features::kFledgeStoreBandAKeysInDB)) {
manager_->SetBiddingAndAuctionServerKeys(coordinator, std::move(keys),
expiration);
manager_->SetBiddingAndAuctionServerKeys(
coordinator, keyset.AsBinaryProto(), expiration);
}
CacheKeysAndRunAllCallbacks(coordinator, std::move(keyset), expiration);
}
void BiddingAndAuctionServerKeyFetcher::CacheKeysAndRunAllCallbacks(
const url::Origin& coordinator,
const std::vector<BiddingAndAuctionServerKey>& keys,
BiddingAndAuctionKeySet keyset,
base::Time expiration) {
PerCoordinatorFetcherState& state = fetcher_state_map_.at(coordinator);
state.keys = keys;
state.keyset = std::move(keyset);
state.expiration = expiration;
while (!state.queue.empty()) {
@ -347,8 +475,15 @@ void BiddingAndAuctionServerKeyFetcher::CacheKeysAndRunAllCallbacks(
// empty queue.
// Use a random key from the set to limit the server's ability to identify
// us based on the key we use.
std::move(state.queue.front())
.Run(state.keys[base::RandInt(0, state.keys.size() - 1)]);
std::optional<BiddingAndAuctionServerKey> key =
state.keyset->GetRandomKey(state.queue.front().scope_origin);
if (!key) {
std::move(state.queue.front().callback)
.Run(base::unexpected<std::string>("No key for adtech origin"));
} else {
std::move(state.queue.front().callback).Run(std::move(*key));
}
state.queue.pop_front();
}
}
@ -362,7 +497,7 @@ void BiddingAndAuctionServerKeyFetcher::FailAllCallbacks(
// request. If we removed the current request first then enqueued the
// request, that would start another thread of execution since there was an
// empty queue.
std::move(state.queue.front())
std::move(state.queue.front().callback)
.Run(base::unexpected<std::string>("Key fetch failed"));
state.queue.pop_front();
}

@ -10,6 +10,7 @@
#include <vector>
#include "base/containers/circular_deque.h"
#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/types/expected.h"
@ -41,7 +42,38 @@ inline constexpr char kBiddingAndAuctionAWSCoordinatorKeyURL[] =
struct BiddingAndAuctionServerKey {
std::string key; // bytes containing the key.
uint8_t id; // key id corresponding to this key.
std::string id; // key id corresponding to this key.
};
// This class abstracts the set of keys. This makes code accessing the keys more
// generic to ease the transition as we consider alternative key scopes.
// See https://github.com/WICG/turtledove/issues/1334 for details.
class CONTENT_EXPORT BiddingAndAuctionKeySet {
public:
explicit BiddingAndAuctionKeySet(
std::vector<BiddingAndAuctionServerKey> keys);
~BiddingAndAuctionKeySet();
BiddingAndAuctionKeySet(BiddingAndAuctionKeySet&& keyset);
BiddingAndAuctionKeySet& operator=(BiddingAndAuctionKeySet&& keyset);
// Returns true if we have any keys in this Keyset.
bool HasKeys() const;
// Returns a random key from the set of keys for this coordinator. If keys are
// scoped by origin, the provided `scoped_origin` is used to select the the
// keyset to select from.
std::optional<BiddingAndAuctionServerKey> GetRandomKey(
const url::Origin& scoped_origin) const;
// Convert Keyset to binary Protobuf for storage.
std::string AsBinaryProto() const;
// Create a Keyset from binary Protobuf.
static std::optional<BiddingAndAuctionKeySet> FromBinaryProto(
std::string key_blob);
private:
std::vector<BiddingAndAuctionServerKey> keys_;
};
// BiddingAndAuctionServerKeyFetcher manages fetching and caching of the public
@ -72,10 +104,23 @@ class CONTENT_EXPORT BiddingAndAuctionServerKeyFetcher {
// GetOrFetchKey provides a key in the callback if necessary. If the key is
// immediately available then the callback may be called synchronously.
void GetOrFetchKey(const std::optional<url::Origin>& maybe_coordinator,
void GetOrFetchKey(const url::Origin& scope_origin,
const std::optional<url::Origin>& maybe_coordinator,
BiddingAndAuctionServerKeyFetcherCallback callback);
private:
struct CallbackQueueItem {
CallbackQueueItem(BiddingAndAuctionServerKeyFetcherCallback callback,
url::Origin scope_origin);
~CallbackQueueItem();
CallbackQueueItem(CallbackQueueItem&& item);
CallbackQueueItem& operator=(CallbackQueueItem&& item);
BiddingAndAuctionServerKeyFetcherCallback callback;
url::Origin scope_origin;
};
struct PerCoordinatorFetcherState {
PerCoordinatorFetcherState();
~PerCoordinatorFetcherState();
@ -84,13 +129,14 @@ class CONTENT_EXPORT BiddingAndAuctionServerKeyFetcher {
PerCoordinatorFetcherState& operator=(PerCoordinatorFetcherState&& state);
GURL key_url;
uint8_t version;
// queue_ contains callbacks waiting for a key to be fetched over the
// network.
base::circular_deque<BiddingAndAuctionServerKeyFetcherCallback> queue;
base::circular_deque<CallbackQueueItem> queue;
// keys_ contains a list of keys received from the server (if any).
std::vector<BiddingAndAuctionServerKey> keys;
std::optional<BiddingAndAuctionKeySet> keyset;
// expiration_ contains the expiration time for any keys that are cached by
// this object.
@ -108,13 +154,13 @@ class CONTENT_EXPORT BiddingAndAuctionServerKeyFetcher {
// Fetch keys for a particular coordinator, first checking if the key is
// in the database.
void FetchKeys(const url::Origin& coordinator,
void FetchKeys(const url::Origin& scope_origin,
const url::Origin& coordinator,
PerCoordinatorFetcherState& state,
BiddingAndAuctionServerKeyFetcherCallback callback);
void OnFetchKeysFromDatabaseComplete(
const url::Origin& coordinator,
std::pair<base::Time, std::vector<BiddingAndAuctionServerKey>> keys);
void OnFetchKeysFromDatabaseComplete(const url::Origin& coordinator,
std::pair<base::Time, std::string> keys);
void FetchKeysFromNetwork(const url::Origin& coordinator);
@ -129,10 +175,9 @@ class CONTENT_EXPORT BiddingAndAuctionServerKeyFetcher {
void OnParsedKeys(url::Origin coordinator,
data_decoder::DataDecoder::ValueOrError result);
void CacheKeysAndRunAllCallbacks(
const url::Origin& coordinator,
const std::vector<BiddingAndAuctionServerKey>& keys,
base::Time expiration);
void CacheKeysAndRunAllCallbacks(const url::Origin& coordinator,
BiddingAndAuctionKeySet keyset,
base::Time expiration);
void FailAllCallbacks(url::Origin coordinator);

@ -28,6 +28,7 @@ namespace content {
namespace {
const char kTestAdtech[] = "https://adtech.test/";
const char kOtherDefaultGCPKeyURL[] = "https://example.com/other_keys";
class BiddingAndAuctionServerKeyFetcherTest : public testing::Test {
@ -43,33 +44,26 @@ class BiddingAndAuctionServerKeyFetcherTest : public testing::Test {
&url_loader_factory_);
}
url::Origin CoordinatorOrigin() {
return url::Origin::Create(
GURL(kDefaultBiddingAndAuctionGCPCoordinatorOrigin));
}
protected:
std::pair<base::Time, std::vector<BiddingAndAuctionServerKey>>
GetDBStoredKeysWithExpiration(const url::Origin& coordinator) {
std::pair<base::Time, std::vector<BiddingAndAuctionServerKey>>
expiration_and_keys;
std::pair<base::Time, std::string> GetDBStoredKeysWithExpiration(
const url::Origin& coordinator) {
std::pair<base::Time, std::string> expiration_and_keys;
base::RunLoop run_loop;
manager_->GetBiddingAndAuctionServerKeys(
coordinator,
base::BindLambdaForTesting(
[&](std::pair<base::Time, std::vector<BiddingAndAuctionServerKey>>
stored_keys) {
expiration_and_keys = std::move(stored_keys);
run_loop.Quit();
}));
coordinator, base::BindLambdaForTesting(
[&](std::pair<base::Time, std::string> stored_keys) {
expiration_and_keys = std::move(stored_keys);
run_loop.Quit();
}));
run_loop.Run();
return expiration_and_keys;
}
void SetDBStoredKeys(const url::Origin& coordinator,
std::vector<BiddingAndAuctionServerKey> keys,
std::string serialized_keys,
base::Time expiration) {
manager_->SetBiddingAndAuctionServerKeys(coordinator, keys, expiration);
manager_->SetBiddingAndAuctionServerKeys(coordinator, serialized_keys,
expiration);
}
content::BiddingAndAuctionServerKeyFetcher CreateFetcher() {
@ -77,6 +71,10 @@ class BiddingAndAuctionServerKeyFetcherTest : public testing::Test {
shared_url_loader_factory_);
}
const url::Origin kTestAdtechOrigin = url::Origin::Create(GURL(kTestAdtech));
const url::Origin kCoordinatorOrigin =
url::Origin::Create(GURL(kDefaultBiddingAndAuctionGCPCoordinatorOrigin));
network::TestURLLoaderFactory url_loader_factory_;
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
base::test::TaskEnvironment task_environment_{
@ -91,7 +89,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, UnknownCoordinator) {
base::RunLoop run_loop;
fetcher.GetOrFetchKey(
url::Origin(),
kTestAdtechOrigin, url::Origin(),
base::BindLambdaForTesting([&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
EXPECT_FALSE(maybe_key.has_value());
@ -111,7 +109,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, NoURL) {
base::RunLoop run_loop;
fetcher.GetOrFetchKey(
CoordinatorOrigin(),
kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting([&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
EXPECT_FALSE(maybe_key.has_value());
@ -151,7 +149,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, BadResponses) {
// AddResponse overwrites the previous response.
url_loader_factory_.AddResponse(kBiddingAndAuctionGCPCoordinatorKeyURL,
response);
fetcher.GetOrFetchKey(CoordinatorOrigin(),
fetcher.GetOrFetchKey(kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -169,14 +167,14 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, FailsAll) {
int completed = 0;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(
CoordinatorOrigin(),
kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting([&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
EXPECT_FALSE(maybe_key.has_value());
completed++;
}));
fetcher.GetOrFetchKey(
CoordinatorOrigin(),
kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting([&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
EXPECT_FALSE(maybe_key.has_value());
@ -196,12 +194,12 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, RequestDuringFailure) {
int completed = 0;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(
CoordinatorOrigin(),
kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting([&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
EXPECT_FALSE(maybe_key.has_value());
completed++;
fetcher.GetOrFetchKey(CoordinatorOrigin(),
fetcher.GetOrFetchKey(kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -229,7 +227,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, GoodResponse) {
content::BiddingAndAuctionServerKey key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(
CoordinatorOrigin(),
kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting([&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
EXPECT_TRUE(maybe_key.has_value());
@ -237,7 +235,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, GoodResponse) {
run_loop.Quit();
}));
run_loop.Run();
EXPECT_EQ(0x12, key.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", key.id);
EXPECT_EQ(std::string(32, '\0'), key.key);
EXPECT_EQ(1u, url_loader_factory_.total_requests());
}
@ -252,12 +250,12 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, RequestDuringSuccess) {
int completed = 0;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(
CoordinatorOrigin(),
kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting([&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
EXPECT_TRUE(maybe_key.has_value());
completed++;
fetcher.GetOrFetchKey(CoordinatorOrigin(),
fetcher.GetOrFetchKey(kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -282,7 +280,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, CachesValue) {
{
content::BiddingAndAuctionServerKey key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(CoordinatorOrigin(),
fetcher.GetOrFetchKey(kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -291,7 +289,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, CachesValue) {
run_loop.Quit();
}));
run_loop.Run();
EXPECT_EQ(0x12, key.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", key.id);
EXPECT_EQ(std::string(32, '\0'), key.key);
EXPECT_EQ(1u, url_loader_factory_.total_requests());
}
@ -299,7 +297,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, CachesValue) {
{
content::BiddingAndAuctionServerKey key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(CoordinatorOrigin(),
fetcher.GetOrFetchKey(kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -308,7 +306,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, CachesValue) {
run_loop.Quit();
}));
run_loop.Run();
EXPECT_EQ(0x12, key.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", key.id);
EXPECT_EQ(std::string(32, '\0'), key.key);
// The response was cached so there was still only 1 request.
EXPECT_EQ(1u, url_loader_factory_.total_requests());
@ -327,16 +325,18 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, ReadsValuesCachedInDBIfEnabled) {
content::BiddingAndAuctionServerKeyFetcher fetcher = CreateFetcher();
std::vector<BiddingAndAuctionServerKey> keys;
BiddingAndAuctionServerKey key;
key.id = 1;
key.id = "12345678-9abc-def0-1234-56789abcdef0";
key.key = "a";
keys.push_back(key);
SetDBStoredKeys(CoordinatorOrigin(), keys, base::Time::Now() + base::Days(2));
BiddingAndAuctionKeySet keyset(std::move(keys));
SetDBStoredKeys(kCoordinatorOrigin, keyset.AsBinaryProto(),
base::Time::Now() + base::Days(2));
task_environment_.RunUntilIdle();
{
content::BiddingAndAuctionServerKey returned_key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(CoordinatorOrigin(),
fetcher.GetOrFetchKey(kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -360,7 +360,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, ReadsValuesCachedInDBIfEnabled) {
// This should make a new request to the network now.
content::BiddingAndAuctionServerKey returned_key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(CoordinatorOrigin(),
fetcher.GetOrFetchKey(kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -371,7 +371,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, ReadsValuesCachedInDBIfEnabled) {
task_environment_.RunUntilIdle();
run_loop.Run();
EXPECT_EQ(1u, url_loader_factory_.total_requests());
EXPECT_EQ(0x12, returned_key.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", returned_key.id);
EXPECT_EQ(std::string(32, '\0'), returned_key.key);
}
}
@ -391,7 +391,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, WritesValuesToDBIfEnabled) {
content::BiddingAndAuctionServerKey key;
{
base::RunLoop run_loop;
fetcher.GetOrFetchKey(CoordinatorOrigin(),
fetcher.GetOrFetchKey(kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -400,19 +400,17 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, WritesValuesToDBIfEnabled) {
run_loop.Quit();
}));
run_loop.Run();
EXPECT_EQ(0x12, key.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", key.id);
EXPECT_EQ(std::string(32, '\0'), key.key);
EXPECT_EQ(1u, url_loader_factory_.total_requests());
}
task_environment_.RunUntilIdle();
std::pair<base::Time, std::vector<content::BiddingAndAuctionServerKey>>
expiration_and_stored_keys =
GetDBStoredKeysWithExpiration(CoordinatorOrigin());
std::pair<base::Time, std::string> expiration_and_stored_keys =
GetDBStoredKeysWithExpiration(kCoordinatorOrigin);
EXPECT_EQ(base::Time::Now() + base::Days(7),
expiration_and_stored_keys.first);
ASSERT_EQ(1u, expiration_and_stored_keys.second.size());
EXPECT_EQ(expiration_and_stored_keys.second[0].key, key.key);
EXPECT_EQ(expiration_and_stored_keys.second[0].id, key.id);
BiddingAndAuctionKeySet keyset({key});
EXPECT_EQ(expiration_and_stored_keys.second, keyset.AsBinaryProto());
}
TEST_F(BiddingAndAuctionServerKeyFetcherTest,
@ -431,7 +429,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest,
net::HTTP_NOT_FOUND);
bool completed = false;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(coordinator,
fetcher.GetOrFetchKey(kTestAdtechOrigin, coordinator,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -453,7 +451,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest,
}]})");
content::BiddingAndAuctionServerKey key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(coordinator,
fetcher.GetOrFetchKey(kTestAdtechOrigin, coordinator,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -462,7 +460,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest,
run_loop.Quit();
}));
run_loop.Run();
EXPECT_EQ(0x12, key.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", key.id);
EXPECT_EQ(std::string(32, '\0'), key.key);
}
}
@ -494,7 +492,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, MaybePrefetchKeysCachesValue) {
{
content::BiddingAndAuctionServerKey key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(coordinator,
fetcher.GetOrFetchKey(kTestAdtechOrigin, coordinator,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -510,7 +508,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, MaybePrefetchKeysCachesValue) {
"id": "23456789-abcd-ef01-2345-6789abcdef01"
}]})"));
run_loop.Run();
EXPECT_EQ(0x12, key.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", key.id);
EXPECT_EQ(std::string(32, '\0'), key.key);
}
@ -545,7 +543,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest,
{
content::BiddingAndAuctionServerKey key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(coordinator,
fetcher.GetOrFetchKey(kTestAdtechOrigin, coordinator,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -555,7 +553,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest,
}));
run_loop.Run();
EXPECT_EQ(0x12, key.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", key.id);
EXPECT_EQ(std::string(32, '\0'), key.key);
EXPECT_EQ(1u, url_loader_factory_.total_requests());
}
@ -593,14 +591,14 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, CoalescesRequests) {
{
content::BiddingAndAuctionServerKey key1, key2;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(CoordinatorOrigin(),
fetcher.GetOrFetchKey(kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
EXPECT_TRUE(maybe_key.has_value());
key1 = *maybe_key;
}));
fetcher.GetOrFetchKey(CoordinatorOrigin(),
fetcher.GetOrFetchKey(kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -609,10 +607,10 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, CoalescesRequests) {
run_loop.Quit();
}));
run_loop.Run();
EXPECT_EQ(0x12, key1.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", key1.id);
EXPECT_EQ(std::string(32, '\0'), key1.key);
EXPECT_EQ(0x12, key2.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", key2.id);
EXPECT_EQ(std::string(32, '\0'), key2.key);
EXPECT_EQ(1u, url_loader_factory_.total_requests());
@ -633,7 +631,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, ChoosesRandomKey) {
{
content::BiddingAndAuctionServerKey key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(CoordinatorOrigin(),
fetcher.GetOrFetchKey(kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -644,11 +642,11 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, ChoosesRandomKey) {
run_loop.Run();
}
std::set<uint8_t> ids;
std::set<std::string> ids;
while (ids.size() < 2) {
content::BiddingAndAuctionServerKey key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(CoordinatorOrigin(),
fetcher.GetOrFetchKey(kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting(
[&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
@ -659,7 +657,9 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, ChoosesRandomKey) {
run_loop.Run();
ids.insert(key.id);
}
EXPECT_THAT(ids, testing::ElementsAre(0x12, 0x23));
EXPECT_THAT(ids,
testing::ElementsAre("12345678-9abc-def0-1234-56789abcdef0",
"23456789-abcd-ef01-2345-6789abcdef01"));
}
TEST_F(BiddingAndAuctionServerKeyFetcherTest, OverridesConfig) {
@ -680,7 +680,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, OverridesConfig) {
content::BiddingAndAuctionServerKey key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(
CoordinatorOrigin(),
kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting([&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
EXPECT_TRUE(maybe_key.has_value());
@ -688,7 +688,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, OverridesConfig) {
run_loop.Quit();
}));
run_loop.Run();
EXPECT_EQ(0x12, key.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", key.id);
EXPECT_EQ(std::string(32, '\0'), key.key);
EXPECT_EQ(1u, url_loader_factory_.total_requests());
}
@ -711,7 +711,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, NoConfigOnlyURL) {
content::BiddingAndAuctionServerKey key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(
CoordinatorOrigin(),
kTestAdtechOrigin, kCoordinatorOrigin,
base::BindLambdaForTesting([&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
EXPECT_TRUE(maybe_key.has_value());
@ -719,7 +719,7 @@ TEST_F(BiddingAndAuctionServerKeyFetcherTest, NoConfigOnlyURL) {
run_loop.Quit();
}));
run_loop.Run();
EXPECT_EQ(0x12, key.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", key.id);
EXPECT_EQ(std::string(32, '\0'), key.key);
EXPECT_EQ(1u, url_loader_factory_.total_requests());
}
@ -768,7 +768,7 @@ TEST_P(BiddingAndAuctionServerKeyFetcherCoordinatorTest, GoodResponse) {
content::BiddingAndAuctionServerKey key;
base::RunLoop run_loop;
fetcher.GetOrFetchKey(
GetCoordinator(),
kTestAdtechOrigin, GetCoordinator(),
base::BindLambdaForTesting([&](base::expected<BiddingAndAuctionServerKey,
std::string> maybe_key) {
EXPECT_TRUE(maybe_key.has_value());
@ -776,7 +776,7 @@ TEST_P(BiddingAndAuctionServerKeyFetcherCoordinatorTest, GoodResponse) {
run_loop.Quit();
}));
run_loop.Run();
EXPECT_EQ(0x12, key.id);
EXPECT_EQ("12345678-9abc-def0-1234-56789abcdef0", key.id);
EXPECT_EQ(std::string(32, '\0'), key.key);
EXPECT_EQ(1u, url_loader_factory_.total_requests());
}

@ -438,6 +438,7 @@ class InterestGroupAuctionReporterTest
return std::nullopt;
}
void GetBiddingAndAuctionServerKey(
const url::Origin& scope_origin,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(base::expected<BiddingAndAuctionServerKey,
std::string>)> callback) override {

@ -27367,12 +27367,12 @@ class InterestGroupTrustedSignalsKVv2BrowserTest
0xf1, 0x85, 0xd9, 0xd8, 0x91, 0xc7, 0x4d, 0xcf, 0x1e, 0xb9, 0x1a,
0x7d, 0x50, 0xa5, 0x8b, 0x01, 0x68, 0x3e, 0x60, 0x05, 0x2d,
};
BiddingAndAuctionKeySet keyset({BiddingAndAuctionServerKey{
std::string(reinterpret_cast<const char*>(kTestPublicKey),
sizeof(kTestPublicKey)),
kKeyIdStr}});
manager_->SetBiddingAndAuctionServerKeys(
kCoordinatorOrigin,
{BiddingAndAuctionServerKey{
std::string(reinterpret_cast<const char*>(kTestPublicKey),
sizeof(kTestPublicKey)),
kKeyId}},
kCoordinatorOrigin, keyset.AsBinaryProto(),
/*expiration=*/base::Time::Now() + base::Days(1));
}
@ -27590,6 +27590,7 @@ class InterestGroupTrustedSignalsKVv2BrowserTest
}
static constexpr int kKeyId = 170;
static constexpr char kKeyIdStr[] = "AA";
base::test::ScopedFeatureList feature_list_;
const url::Origin kCoordinatorOrigin = url::Origin::Create(

@ -529,17 +529,15 @@ void InterestGroupCachingStorage::UpdateInterestGroupPriorityOverrides(
void InterestGroupCachingStorage::SetBiddingAndAuctionServerKeys(
const url::Origin& coordinator,
const std::vector<BiddingAndAuctionServerKey>& keys,
std::string serialized_keys,
base::Time expiration) {
interest_group_storage_
.AsyncCall(&InterestGroupStorage::SetBiddingAndAuctionServerKeys)
.WithArgs(coordinator, keys, expiration);
.WithArgs(coordinator, std::move(serialized_keys), expiration);
}
void InterestGroupCachingStorage::GetBiddingAndAuctionServerKeys(
const url::Origin& coordinator,
base::OnceCallback<
void(std::pair<base::Time, std::vector<BiddingAndAuctionServerKey>>)>
callback) {
base::OnceCallback<void(std::pair<base::Time, std::string>)> callback) {
interest_group_storage_
.AsyncCall(&InterestGroupStorage::GetBiddingAndAuctionServerKeys)
.WithArgs(coordinator)

@ -310,17 +310,14 @@ class CONTENT_EXPORT InterestGroupCachingStorage {
// Update B&A keys for a coordinator. This function will overwrite any
// existing keys for the coordinator.
void SetBiddingAndAuctionServerKeys(
const url::Origin& coordinator,
const std::vector<BiddingAndAuctionServerKey>& keys,
base::Time expiration);
void SetBiddingAndAuctionServerKeys(const url::Origin& coordinator,
std::string serialized_keys,
base::Time expiration);
// Load stored B&A server keys for a coordinator along with the keys'
// expiration.
void GetBiddingAndAuctionServerKeys(
const url::Origin& coordinator,
base::OnceCallback<
void(std::pair<base::Time, std::vector<BiddingAndAuctionServerKey>>)>
callback);
base::OnceCallback<void(std::pair<base::Time, std::string>)> callback);
void GetLastMaintenanceTimeForTesting(
base::RepeatingCallback<void(base::Time)> callback) const;

@ -756,16 +756,14 @@ void InterestGroupManagerImpl::UpdateInterestGroupPriorityOverrides(
void InterestGroupManagerImpl::SetBiddingAndAuctionServerKeys(
const url::Origin& coordinator,
const std::vector<BiddingAndAuctionServerKey>& keys,
std::string serialized_keys,
base::Time expiration) {
caching_storage_.SetBiddingAndAuctionServerKeys(coordinator, keys,
expiration);
caching_storage_.SetBiddingAndAuctionServerKeys(
coordinator, std::move(serialized_keys), expiration);
}
void InterestGroupManagerImpl::GetBiddingAndAuctionServerKeys(
const url::Origin& coordinator,
base::OnceCallback<
void(std::pair<base::Time, std::vector<BiddingAndAuctionServerKey>>)>
callback) {
base::OnceCallback<void(std::pair<base::Time, std::string>)> callback) {
caching_storage_.GetBiddingAndAuctionServerKeys(coordinator,
std::move(callback));
}
@ -921,10 +919,11 @@ void InterestGroupManagerImpl::OnAdAuctionDataLoadComplete(
}
void InterestGroupManagerImpl::GetBiddingAndAuctionServerKey(
const url::Origin& seller,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(
base::expected<BiddingAndAuctionServerKey, std::string>)> callback) {
ba_key_fetcher_.GetOrFetchKey(coordinator, std::move(callback));
ba_key_fetcher_.GetOrFetchKey(seller, coordinator, std::move(callback));
}
void InterestGroupManagerImpl::OnJoinInterestGroupPermissionsChecked(

@ -385,18 +385,15 @@ class CONTENT_EXPORT InterestGroupManagerImpl : public InterestGroupManager {
// Update B&A keys for a coordinator. This function will overwrite any
// existing keys for the coordinator.
void SetBiddingAndAuctionServerKeys(
const url::Origin& coordinator,
const std::vector<BiddingAndAuctionServerKey>& keys,
base::Time expiration);
void SetBiddingAndAuctionServerKeys(const url::Origin& coordinator,
std::string serialized_keys,
base::Time expiration);
// Load stored B&A server keys for a coordinator along with the keys'
// expiration.
void GetBiddingAndAuctionServerKeys(
const url::Origin& coordinator,
base::OnceCallback<
void(std::pair<base::Time, std::vector<BiddingAndAuctionServerKey>>)>
callback);
base::OnceCallback<void(std::pair<base::Time, std::string>)> callback);
// Clears the InterestGroupPermissionsChecker's cache of the results of
// .well-known fetches.
@ -513,6 +510,7 @@ class CONTENT_EXPORT InterestGroupManagerImpl : public InterestGroupManager {
// called synchronously if the key is already available or the coordinator is
// not recognized.
void GetBiddingAndAuctionServerKey(
const url::Origin& seller,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(
base::expected<BiddingAndAuctionServerKey, std::string>)> callback);

@ -40,6 +40,7 @@
#include "content/browser/interest_group/interest_group_features.h"
#include "content/browser/interest_group/interest_group_k_anonymity_manager.h"
#include "content/browser/interest_group/interest_group_storage.pb.h"
#include "content/browser/interest_group/interest_group_storage_metric_types.h"
#include "content/browser/interest_group/interest_group_update.h"
#include "content/browser/interest_group/storage_interest_group.h"
#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h"
@ -69,104 +70,6 @@ using blink::mojom::BiddingBrowserSignalsPtr;
using blink::mojom::PreviousWinPtr;
using SellerCapabilitiesType = blink::SellerCapabilitiesType;
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(AdProtoDecompressionOutcome)
enum class AdProtoDecompressionOutcome {
kSuccess = 0,
kFailure = 1,
kMaxValue = kFailure,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:AdProtoDecompressionOutcome)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(InterestGroupStorageInitializationResult)
enum class InterestGroupStorageInitializationResult {
kSuccessAlreadyCurrent = 0,
kSuccessUpgraded = 1,
kSuccessCreateSchema = 2,
kSuccessCreateSchemaAfterIncompatibleRaze = 3,
kSuccessCreateSchemaAfterNoMetaTableRaze = 4,
kFailedCreateInMemory = 5,
kFailedCreateDirectory = 6,
kFailedCreateFile = 7,
kFailedToRazeIncompatible = 8,
kFailedToRazeNoMetaTable = 9,
kFailedMetaTableInit = 10,
kFailedCreateSchema = 11,
kFailedCreateSchemaAfterIncompatibleRaze = 12,
kFailedCreateSchemaAfterNoMetaTableRaze = 13,
kFailedUpgradeDB = 14,
kMaxValue = kFailedUpgradeDB,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:InterestGroupStorageInitializationResult)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(InterestGroupStorageJSONDeserializationResult)
enum class InterestGroupStorageJSONDeserializationResult {
kSucceeded = 0,
kFailed = 1,
kMaxValue = kFailed,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:InterestGroupStorageJSONDeserializationResult)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(InterestGroupStorageJSONSerializationResult)
enum class InterestGroupStorageJSONSerializationResult {
kSucceeded = 0,
kFailed = 1,
kMaxValue = kFailed,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:InterestGroupStorageJSONSerializationResult)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(InterestGroupStorageProtoDeserializationResult)
enum class InterestGroupStorageProtoDeserializationResult {
kSucceeded = 0,
kFailed = 1,
kMaxValue = kFailed,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:InterestGroupStorageProtoDeserializationResult)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(InterestGroupStorageProtoSerializationResult)
enum class InterestGroupStorageProtoSerializationResult {
kSucceeded = 0,
kFailed = 1,
kMaxValue = kFailed,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:InterestGroupStorageProtoSerializationResult)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(InterestGroupStorageVacuumResult)
enum class InterestGroupStorageVacuumResult {
kSucceeded = 0,
kFailed = 1,
kMaxValue = kFailed,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:InterestGroupStorageVacuumResult)
const base::FilePath::CharType kDatabasePath[] =
FILE_PATH_LITERAL("InterestGroups");
@ -5607,18 +5510,10 @@ bool ClearExpiredBiddingAndAuctionKeys(sql::Database& db, base::Time now) {
return clear_expired_keys.Run();
}
bool DoSetBiddingAndAuctionServerKeys(
sql::Database& db,
const url::Origin& coordinator,
const std::vector<BiddingAndAuctionServerKey>& keys,
base::Time expiration) {
BiddingAndAuctionServerKeyProtos key_protos;
for (const BiddingAndAuctionServerKey& key : keys) {
BiddingAndAuctionServerKeyProtos_BiddingAndAuctionServerKeyProto*
key_proto = key_protos.add_keys();
key_proto->set_key(key.key);
key_proto->set_id(key.id);
}
bool DoSetBiddingAndAuctionServerKeys(sql::Database& db,
const url::Origin& coordinator,
std::string serialized_keys,
base::Time expiration) {
sql::Statement insert_keys_statement(db.GetCachedStatement(
SQL_FROM_HERE,
"INSERT OR REPLACE INTO "
@ -5627,27 +5522,15 @@ bool DoSetBiddingAndAuctionServerKeys(
insert_keys_statement.Reset(true);
insert_keys_statement.BindString(0, Serialize(coordinator));
std::string key_protos_str;
if (key_protos.SerializeToString(&key_protos_str)) {
base::UmaHistogramEnumeration(
"Storage.InterestGroup.ProtoSerializationResult."
"BiddingAndAuctionServerKeyProtos",
InterestGroupStorageProtoSerializationResult::kSucceeded);
} else {
base::UmaHistogramEnumeration(
"Storage.InterestGroup.ProtoSerializationResult."
"BiddingAndAuctionServerKeyProtos",
InterestGroupStorageProtoSerializationResult::kFailed);
// TODO(crbug.com/355010821): Consider bubbling out the failure.
}
insert_keys_statement.BindBlob(1, key_protos_str);
insert_keys_statement.BindBlob(1, serialized_keys);
insert_keys_statement.BindTime(2, expiration);
return insert_keys_statement.Run();
}
std::pair<base::Time, std::vector<BiddingAndAuctionServerKey>>
DoGetBiddingAndAuctionServerKeys(sql::Database& db,
const url::Origin& coordinator) {
std::pair<base::Time, std::string> DoGetBiddingAndAuctionServerKeys(
sql::Database& db,
const url::Origin& coordinator) {
sql::Statement keys_statement(
db.GetCachedStatement(SQL_FROM_HERE,
"SELECT expiration, keys "
@ -5666,30 +5549,7 @@ DoGetBiddingAndAuctionServerKeys(sql::Database& db,
if (keys_statement.Step()) {
base::Time expiration = keys_statement.ColumnTime(0);
std::string key_blob = keys_statement.ColumnString(1);
BiddingAndAuctionServerKeyProtos key_protos;
bool success = key_protos.ParseFromString(key_blob);
if (success) {
base::UmaHistogramEnumeration(
"Storage.InterestGroup.ProtoDeserializationResult."
"BiddingAndAuctionServerKeyProtos",
InterestGroupStorageProtoDeserializationResult::kSucceeded);
} else {
base::UmaHistogramEnumeration(
"Storage.InterestGroup.ProtoDeserializationResult."
"BiddingAndAuctionServerKeyProtos",
InterestGroupStorageProtoDeserializationResult::kFailed);
// TODO(crbug.com/355010821): Consider bubbling out the failure.
}
if (not success || key_protos.keys().empty()) {
return {base::Time::Min(), {}};
}
std::vector<BiddingAndAuctionServerKey> keys;
keys.reserve(key_protos.keys_size());
for (auto& key_proto : *key_protos.mutable_keys()) {
keys.emplace_back(std::move(*key_proto.mutable_key()), key_proto.id());
}
return {expiration, keys};
return {expiration, key_blob};
}
return {base::Time::Min(), {}};
}
@ -6481,16 +6341,17 @@ InterestGroupStorage::GetAllInterestGroupsUnfilteredForTesting() {
void InterestGroupStorage::SetBiddingAndAuctionServerKeys(
const url::Origin& coordinator,
const std::vector<BiddingAndAuctionServerKey>& keys,
std::string serialized_keys,
base::Time expiration) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!EnsureDBInitialized()) {
return;
}
DoSetBiddingAndAuctionServerKeys(*db_, coordinator, keys, expiration);
DoSetBiddingAndAuctionServerKeys(*db_, coordinator,
std::move(serialized_keys), expiration);
}
std::pair<base::Time, std::vector<BiddingAndAuctionServerKey>>
std::pair<base::Time, std::string>
InterestGroupStorage::GetBiddingAndAuctionServerKeys(
const url::Origin& coordinator) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

@ -32,8 +32,6 @@ struct InterestGroup;
}
namespace content {
struct BiddingAndAuctionServerKey;
// InterestGroupStorage controls access to the Interest Group Database. All
// public functions perform operations on the database and may block. This
// implementation is not thread-safe so all functions should be called from
@ -208,15 +206,13 @@ class CONTENT_EXPORT InterestGroupStorage {
// Update B&A keys for a coordinator. This function will overwrite any
// existing keys for the coordinator.
void SetBiddingAndAuctionServerKeys(
const url::Origin& coordinator,
const std::vector<BiddingAndAuctionServerKey>& keys,
base::Time expiration);
void SetBiddingAndAuctionServerKeys(const url::Origin& coordinator,
std::string serialized_keys,
base::Time expiration);
// Load stored B&A server keys for a coordinator along with the keys'
// expiration.
std::pair<base::Time, std::vector<BiddingAndAuctionServerKey>>
GetBiddingAndAuctionServerKeys(const url::Origin& coordinator);
std::pair<base::Time, std::string> GetBiddingAndAuctionServerKeys(
const url::Origin& coordinator);
// Returns various resource limits, as configured by feature params.
static size_t MaxOwnerRegularInterestGroups();

@ -23,11 +23,17 @@ message AdProtos {
repeated AdProto ads = 1;
}
message BiddingAndAuctionServerKeyProtos {
message BiddingAndAuctionServerKeysProtos {
message BiddingAndAuctionServerKeyProto {
bytes key = 1;
int32 id = 2;
optional int32 id = 2 [deprecated = true];
string id_str = 3;
}
message BiddingAndAuctionServerKeyProtos {
repeated BiddingAndAuctionServerKeyProto keys = 1;
}
// Global keys
repeated BiddingAndAuctionServerKeyProto keys = 1;
}

@ -0,0 +1,110 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_STORAGE_METRIC_TYPES_H_
#define CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_STORAGE_METRIC_TYPES_H_
namespace content {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(AdProtoDecompressionOutcome)
enum class AdProtoDecompressionOutcome {
kSuccess = 0,
kFailure = 1,
kMaxValue = kFailure,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:AdProtoDecompressionOutcome)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(InterestGroupStorageInitializationResult)
enum class InterestGroupStorageInitializationResult {
kSuccessAlreadyCurrent = 0,
kSuccessUpgraded = 1,
kSuccessCreateSchema = 2,
kSuccessCreateSchemaAfterIncompatibleRaze = 3,
kSuccessCreateSchemaAfterNoMetaTableRaze = 4,
kFailedCreateInMemory = 5,
kFailedCreateDirectory = 6,
kFailedCreateFile = 7,
kFailedToRazeIncompatible = 8,
kFailedToRazeNoMetaTable = 9,
kFailedMetaTableInit = 10,
kFailedCreateSchema = 11,
kFailedCreateSchemaAfterIncompatibleRaze = 12,
kFailedCreateSchemaAfterNoMetaTableRaze = 13,
kFailedUpgradeDB = 14,
kMaxValue = kFailedUpgradeDB,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:InterestGroupStorageInitializationResult)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(InterestGroupStorageJSONDeserializationResult)
enum class InterestGroupStorageJSONDeserializationResult {
kSucceeded = 0,
kFailed = 1,
kMaxValue = kFailed,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:InterestGroupStorageJSONDeserializationResult)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(InterestGroupStorageJSONSerializationResult)
enum class InterestGroupStorageJSONSerializationResult {
kSucceeded = 0,
kFailed = 1,
kMaxValue = kFailed,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:InterestGroupStorageJSONSerializationResult)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(InterestGroupStorageProtoDeserializationResult)
enum class InterestGroupStorageProtoDeserializationResult {
kSucceeded = 0,
kFailed = 1,
kMaxValue = kFailed,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:InterestGroupStorageProtoDeserializationResult)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(InterestGroupStorageProtoSerializationResult)
enum class InterestGroupStorageProtoSerializationResult {
kSucceeded = 0,
kFailed = 1,
kMaxValue = kFailed,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:InterestGroupStorageProtoSerializationResult)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(InterestGroupStorageVacuumResult)
enum class InterestGroupStorageVacuumResult {
kSucceeded = 0,
kFailed = 1,
kMaxValue = kFailed,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/storage/enums.xml:InterestGroupStorageVacuumResult)
} // namespace content
#endif // CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_STORAGE_METRIC_TYPES_H_

@ -4173,7 +4173,7 @@ TEST_F(InterestGroupStorageTest, SetGetBiddingAndAuctionKeys) {
url::Origin::Create(GURL("https://b.example.com"));
std::unique_ptr<InterestGroupStorage> storage = CreateStorage();
// No keys should be returned before any values are set.
std::vector<BiddingAndAuctionServerKey> a_loaded_keys, b_loaded_keys;
std::string a_loaded_keys, b_loaded_keys;
base::Time a_expiration, b_expiration;
std::tie(a_expiration, a_loaded_keys) =
storage->GetBiddingAndAuctionServerKeys(origin_a);
@ -4183,44 +4183,32 @@ TEST_F(InterestGroupStorageTest, SetGetBiddingAndAuctionKeys) {
EXPECT_TRUE(b_loaded_keys.empty());
// The set values should be returned.
std::vector<BiddingAndAuctionServerKey> a_keys{{"1", 1}, {"2", 2}};
std::string a_keys = "A keys in binary proto";
base::Time expiration = base::Time::Now() + base::Seconds(5);
storage->SetBiddingAndAuctionServerKeys(origin_a, a_keys, expiration);
std::tie(a_expiration, a_loaded_keys) =
storage->GetBiddingAndAuctionServerKeys(origin_a);
std::tie(b_expiration, b_loaded_keys) =
storage->GetBiddingAndAuctionServerKeys(origin_b);
EXPECT_EQ(a_loaded_keys.size(), 2u);
EXPECT_NE(a_loaded_keys[0].id, a_loaded_keys[1].id);
for (const BiddingAndAuctionServerKey& key : a_loaded_keys) {
EXPECT_TRUE((key.id == 1 && key.key == "1") ||
(key.id == 2 && key.key == "2"));
}
EXPECT_EQ(a_loaded_keys, a_keys);
EXPECT_TRUE(b_loaded_keys.empty());
EXPECT_EQ(expiration, a_expiration);
// Setting values for a different origin shouldn't affect the previously
// set values.
std::vector<BiddingAndAuctionServerKey> b_keys{{"3", 3}};
std::string b_keys = "B keys in binary proto";
storage->SetBiddingAndAuctionServerKeys(origin_b, b_keys, expiration);
std::tie(a_expiration, a_loaded_keys) =
storage->GetBiddingAndAuctionServerKeys(origin_a);
std::tie(b_expiration, b_loaded_keys) =
storage->GetBiddingAndAuctionServerKeys(origin_b);
EXPECT_EQ(a_loaded_keys.size(), 2u);
EXPECT_NE(a_loaded_keys[0].id, a_loaded_keys[1].id);
for (const BiddingAndAuctionServerKey& key : a_loaded_keys) {
EXPECT_TRUE((key.id == 1 && key.key == "1") ||
(key.id == 2 && key.key == "2"));
}
EXPECT_EQ(b_loaded_keys.size(), 1u);
EXPECT_EQ("3", b_loaded_keys[0].key);
EXPECT_EQ(3, b_loaded_keys[0].id);
EXPECT_EQ(a_loaded_keys, a_keys);
EXPECT_EQ(b_loaded_keys, b_keys);
EXPECT_EQ(expiration, a_expiration);
EXPECT_EQ(expiration, b_expiration);
// Resetting the keys should overwrite the previous keys.
a_keys = {{"1", 1}};
a_keys = "New A keys in binary proto";
task_environment().FastForwardBy(base::Seconds(2));
expiration = base::Time::Now() + base::Days(7);
storage->SetBiddingAndAuctionServerKeys(origin_a, a_keys, expiration);
@ -4228,12 +4216,8 @@ TEST_F(InterestGroupStorageTest, SetGetBiddingAndAuctionKeys) {
storage->GetBiddingAndAuctionServerKeys(origin_a);
std::tie(b_expiration, b_loaded_keys) =
storage->GetBiddingAndAuctionServerKeys(origin_b);
EXPECT_EQ(a_loaded_keys.size(), 1u);
EXPECT_EQ("1", a_loaded_keys[0].key);
EXPECT_EQ(1, a_loaded_keys[0].id);
EXPECT_EQ(b_loaded_keys.size(), 1u);
EXPECT_EQ("3", b_loaded_keys[0].key);
EXPECT_EQ(3, b_loaded_keys[0].id);
EXPECT_EQ(a_loaded_keys, a_keys);
EXPECT_EQ(b_loaded_keys, b_keys);
EXPECT_EQ(expiration, a_expiration);
EXPECT_NE(expiration, b_expiration);
@ -4243,9 +4227,7 @@ TEST_F(InterestGroupStorageTest, SetGetBiddingAndAuctionKeys) {
storage->GetBiddingAndAuctionServerKeys(origin_a);
std::tie(b_expiration, b_loaded_keys) =
storage->GetBiddingAndAuctionServerKeys(origin_b);
EXPECT_EQ(a_loaded_keys.size(), 1u);
EXPECT_EQ("1", a_loaded_keys[0].key);
EXPECT_EQ(1, a_loaded_keys[0].id);
EXPECT_EQ(a_loaded_keys, a_keys);
EXPECT_TRUE(b_loaded_keys.empty());
EXPECT_EQ(expiration, a_expiration);
@ -4257,28 +4239,10 @@ TEST_F(InterestGroupStorageTest, SetGetBiddingAndAuctionKeys) {
storage->GetBiddingAndAuctionServerKeys(origin_a);
std::tie(b_expiration, b_loaded_keys) =
storage->GetBiddingAndAuctionServerKeys(origin_b);
EXPECT_EQ(a_loaded_keys.size(), 1u);
EXPECT_EQ("1", a_loaded_keys[0].key);
EXPECT_EQ(1, a_loaded_keys[0].id);
EXPECT_EQ(a_loaded_keys, a_keys);
EXPECT_EQ(expiration, a_expiration);
EXPECT_TRUE(b_loaded_keys.empty());
}
TEST_F(InterestGroupStorageTest, SetGetBiddingAndAuctionKeysNonUtf8) {
const url::Origin origin = url::Origin::Create(GURL("https://b.example.com"));
std::unique_ptr<InterestGroupStorage> storage = CreateStorage();
std::string key(32, 0x00);
std::vector<BiddingAndAuctionServerKey> keys{{key, 2}};
storage->SetBiddingAndAuctionServerKeys(origin, keys,
base::Time::Now() + base::Days(1));
std::vector<BiddingAndAuctionServerKey> loaded_keys;
base::Time expiration;
std::tie(expiration, loaded_keys) =
storage->GetBiddingAndAuctionServerKeys(origin);
EXPECT_EQ(loaded_keys.size(), 1u);
EXPECT_EQ(loaded_keys[0].key, key);
EXPECT_EQ(loaded_keys[0].id, 2);
}
} // namespace
} // namespace content

@ -1116,7 +1116,7 @@ void TrustedSignalsCacheImpl::GetCoordinatorKey(FetchMap::iterator fetch_it) {
// request body, or the information needed to create it, while waiting for the
// key to be received.
get_coordinator_key_callback_.Run(
fetch_it->first.coordinator,
fetch_it->first.script_origin(), fetch_it->first.coordinator,
base::BindOnce(&TrustedSignalsCacheImpl::OnCoordinatorKeyReceived,
fetch_it->second.weak_ptr_factory.GetWeakPtr(), fetch_it));
}

@ -105,6 +105,7 @@ class CONTENT_EXPORT TrustedSignalsCacheImpl
// The `callback` parameter may be invoked synchronously or asynchronously,
// and may fail.
using GetCoordinatorKeyCallback = base::RepeatingCallback<void(
const url::Origin& scope_origin,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(
base::expected<BiddingAndAuctionServerKey, std::string>)> callback)>;

@ -295,13 +295,14 @@ class TestTrustedSignalsCache : public TrustedSignalsCacheImpl {
// Callback to handle coordinator key requests by the base
// TrustedSignalsCacheImpl class.
void GetCoordinatorKey(
const url::Origin& scope_origin,
const std::optional<url::Origin>& coordinator,
base::OnceCallback<void(
base::expected<BiddingAndAuctionServerKey, std::string>)> callback) {
switch (get_coordinator_key_mode_) {
case GetCoordinatorKeyMode::kSync:
std::move(callback).Run(BiddingAndAuctionServerKey{
/*key=*/coordinator->Serialize(), /*id=*/1});
/*key=*/coordinator->Serialize(), /*id=*/"01"});
break;
case GetCoordinatorKeyMode::kAsync:
// This should be safe, as the base class guards this callback with a
@ -310,7 +311,7 @@ class TestTrustedSignalsCache : public TrustedSignalsCacheImpl {
FROM_HERE,
base::BindOnce(std::move(callback),
BiddingAndAuctionServerKey{
/*key=*/coordinator->Serialize(), /*id=*/1}));
/*key=*/coordinator->Serialize(), /*id=*/"01"}));
break;
case GetCoordinatorKeyMode::kSyncFail:
std::move(callback).Run(base::unexpected(std::string(kKeyFetchFailed)));
@ -1565,7 +1566,7 @@ TYPED_TEST(TrustedSignalsCacheTest, HandleDestroyedWithoutStartingFetch) {
if (test_case != TestCase::kCancelBeforeCoordinatorKeyCallback) {
callback = this->trusted_signals_cache_->WaitForCoordinatorKeyCallback();
if (test_case == TestCase::kCancelAfterCoordinatorKeyCallback) {
std::move(callback).Run(BiddingAndAuctionServerKey{"key", /*id=*/1});
std::move(callback).Run(BiddingAndAuctionServerKey{"key", /*id=*/"01"});
}
}
@ -1587,7 +1588,7 @@ TYPED_TEST(TrustedSignalsCacheTest, HandleDestroyedWithoutStartingFetch) {
if (test_case ==
TestCase::kCancelDuringCoordinatorKeyCallbackAndInvokeCallback) {
// Invoking the GetCoordinatorKeyCallback late should not crash.
std::move(callback).Run(BiddingAndAuctionServerKey{"key", /*id=*/1});
std::move(callback).Run(BiddingAndAuctionServerKey{"key", /*id=*/"01"});
}
}
}
@ -3300,7 +3301,7 @@ TYPED_TEST(TrustedSignalsCacheTest, CancelledDuringGetCoordinatorKey) {
this->trusted_signals_cache_->WaitForCoordinatorKeyCallback();
handle.reset();
if (invoke_callback) {
std::move(callback).Run(BiddingAndAuctionServerKey{"key", /*id=*/1});
std::move(callback).Run(BiddingAndAuctionServerKey{"key", /*id=*/"01"});
}
// Let any pending async callbacks complete.
@ -3349,9 +3350,9 @@ TYPED_TEST(TrustedSignalsCacheTest,
// Invoke both callbacks, with the usual key (the serialized
// coordinator).
std::move(callback1).Run(BiddingAndAuctionServerKey{
/*key=*/params1.coordinator.Serialize(), /*id=*/1});
/*key=*/params1.coordinator.Serialize(), /*id=*/"01"});
std::move(callback2).Run(BiddingAndAuctionServerKey{
/*key=*/params2.coordinator.Serialize(), /*id=*/1});
/*key=*/params2.coordinator.Serialize(), /*id=*/"01"});
auto fetches = this->WaitForSignalsFetches(2);
@ -3386,7 +3387,7 @@ TYPED_TEST(TrustedSignalsCacheTest,
EXPECT_NE(handle1->compression_group_token(),
handle2->compression_group_token());
std::move(callback1).Run(BiddingAndAuctionServerKey{
/*key=*/params1.coordinator.Serialize(), /*id=*/1});
/*key=*/params1.coordinator.Serialize(), /*id=*/"01"});
auto fetch = this->WaitForSignalsFetch();
@ -3419,7 +3420,7 @@ TYPED_TEST(TrustedSignalsCacheTest,
handle2->compression_group_token());
EXPECT_NE(partition_id1, partition_id2);
std::move(callback1).Run(BiddingAndAuctionServerKey{
/*key=*/params1.coordinator.Serialize(), /*id=*/1});
/*key=*/params1.coordinator.Serialize(), /*id=*/"01"});
auto fetch = this->WaitForSignalsFetch();
@ -3447,7 +3448,7 @@ TYPED_TEST(TrustedSignalsCacheTest,
handle2->compression_group_token());
EXPECT_EQ(partition_id1, partition_id2);
std::move(callback1).Run(BiddingAndAuctionServerKey{
/*key=*/params1.coordinator.Serialize(), /*id=*/1});
/*key=*/params1.coordinator.Serialize(), /*id=*/"01"});
auto fetch = this->WaitForSignalsFetch();
@ -3481,7 +3482,7 @@ TYPED_TEST(TrustedSignalsCacheTest,
auto callback = this->trusted_signals_cache_->WaitForCoordinatorKeyCallback();
std::move(callback).Run(BiddingAndAuctionServerKey{
/*key=*/this->kCoordinator.Serialize(), /*id=*/1});
/*key=*/this->kCoordinator.Serialize(), /*id=*/"01"});
// No fetch should have been started yet.
EXPECT_EQ(this->trusted_signals_cache_->num_pending_fetches(), 0u);

@ -22,6 +22,7 @@
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/notimplemented.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "base/types/expected.h"
@ -352,10 +353,13 @@ void TrustedSignalsFetcher::EncryptRequestBodyAndStart(
trusted_signals_url_ = trusted_signals_url;
callback_ = std::move(callback);
uint32_t key_id = 0;
DCHECK(base::HexStringToUInt(
std::string_view(bidding_and_auction_key.id).substr(0, 2), &key_id));
// Add encryption for request body.
auto maybe_key_config = quiche::ObliviousHttpHeaderKeyConfig::Create(
bidding_and_auction_key.id, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
key_id, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
EVP_HPKE_AES_256_GCM);
CHECK(maybe_key_config.ok());
auto maybe_ciphertext_request_body =

@ -88,6 +88,7 @@ const uint8_t kTestPublicKey[] = {
};
const uint8_t kKeyId = 3;
const char kKeyIdStr[] = "03";
// Helper to create a CompressionGroupResult given all field values.
// `compression_group_data` is a string that will be CBOR encoded to form the
@ -280,7 +281,7 @@ class TrustedSignalsFetcherTest : public testing::Test {
BiddingAndAuctionServerKey{
std::string(reinterpret_cast<const char*>(kTestPublicKey),
sizeof(kTestPublicKey)),
kKeyId},
kKeyIdStr},
compression_groups,
base::BindLambdaForTesting(
[&](TrustedSignalsFetcher::SignalsFetchResult result) {
@ -311,7 +312,7 @@ class TrustedSignalsFetcherTest : public testing::Test {
BiddingAndAuctionServerKey{
std::string(reinterpret_cast<const char*>(kTestPublicKey),
sizeof(kTestPublicKey)),
kKeyId},
kKeyIdStr},
compression_groups,
base::BindLambdaForTesting(
[&](TrustedSignalsFetcher::SignalsFetchResult result) {
@ -2374,7 +2375,7 @@ TEST_F(TrustedSignalsFetcherTest, BiddingSignalsIsolationInfo) {
BiddingAndAuctionServerKey{
std::string(reinterpret_cast<const char*>(kTestPublicKey),
sizeof(kTestPublicKey)),
kKeyId},
kKeyIdStr},
CreateBasicBiddingSignalsRequest(),
base::BindLambdaForTesting(
[](TrustedSignalsFetcher::SignalsFetchResult result) {
@ -2411,7 +2412,7 @@ TEST_F(TrustedSignalsFetcherTest, ScoringSignalsIsolationInfo) {
BiddingAndAuctionServerKey{
std::string(reinterpret_cast<const char*>(kTestPublicKey),
sizeof(kTestPublicKey)),
kKeyId},
kKeyIdStr},
CreateBasicScoringSignalsRequest(),
base::BindLambdaForTesting(
[](TrustedSignalsFetcher::SignalsFetchResult result) {
@ -2469,7 +2470,7 @@ TEST_F(TrustedSignalsFetcherTest, ScoringSignalsClientSecurityState) {
BiddingAndAuctionServerKey{
std::string(reinterpret_cast<const char*>(kTestPublicKey),
sizeof(kTestPublicKey)),
kKeyId},
kKeyIdStr},
CreateBasicScoringSignalsRequest(),
base::BindLambdaForTesting(
[](TrustedSignalsFetcher::SignalsFetchResult result) {
@ -2560,7 +2561,7 @@ TEST(TrustedSignalsFetcherTimeoutTest, BiddingSignalsTimeout) {
BiddingAndAuctionServerKey{
std::string(reinterpret_cast<const char*>(kTestPublicKey),
sizeof(kTestPublicKey)),
kKeyId},
kKeyIdStr},
bidding_signals_request,
base::BindLambdaForTesting(
[&](TrustedSignalsFetcher::SignalsFetchResult result) {