blob: 5d9d3bb77358a6f5c29e21bb36445eb669fddf9f [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/interest_group/bidding_and_auction_response.h"
#include "services/network/public/cpp/is_potentially_trustworthy.h"
namespace content {
namespace {
const size_t kFramingHeaderSize = 5; // bytes
const uint8_t kExpectedHeaderVersionInfo = 0x02;
} // namespace
absl::optional<base::span<const uint8_t>>
ExtractCompressedBiddingAndAuctionResponse(
base::span<const uint8_t> decrypted_data) {
if (decrypted_data.size() < kFramingHeaderSize) {
// Response is too short
return absl::nullopt;
}
if (decrypted_data[0] != kExpectedHeaderVersionInfo) {
// Bad version and compression information
return absl::nullopt;
}
size_t response_length = (decrypted_data[1] << 24) |
(decrypted_data[2] << 16) |
(decrypted_data[3] << 8) | (decrypted_data[4] << 0);
if (decrypted_data.size() < kFramingHeaderSize + response_length) {
// Incomplete Data.
return absl::nullopt;
}
return decrypted_data.subspan(kFramingHeaderSize, response_length);
}
BiddingAndAuctionResponse::BiddingAndAuctionResponse(
BiddingAndAuctionResponse&&) = default;
BiddingAndAuctionResponse& BiddingAndAuctionResponse::operator=(
BiddingAndAuctionResponse&&) = default;
BiddingAndAuctionResponse::BiddingAndAuctionResponse() = default;
BiddingAndAuctionResponse::~BiddingAndAuctionResponse() = default;
// static
absl::optional<BiddingAndAuctionResponse> BiddingAndAuctionResponse::TryParse(
base::Value input,
const base::flat_map<url::Origin, std::vector<std::string>>& group_names) {
BiddingAndAuctionResponse output;
base::Value::Dict* input_dict = input.GetIfDict();
if (!input_dict) {
return absl::nullopt;
}
base::Value::Dict* error_struct = input_dict->FindDict("error");
if (error_struct) {
std::string* message = error_struct->FindString("message");
if (message) {
output.error = *message;
}
}
absl::optional<bool> maybe_is_chaff = input_dict->FindBool("isChaff");
if (maybe_is_chaff && maybe_is_chaff.value()) {
output.is_chaff = true;
// TODO(behamilton): Fail auction - auction failed on the server.
return std::move(output);
}
output.is_chaff = false;
std::string* maybe_render_url = input_dict->FindString("adRenderURL");
if (!maybe_render_url) {
return absl::nullopt;
}
output.ad_render_url = GURL(*maybe_render_url);
if (!output.ad_render_url.is_valid() ||
!network::IsUrlPotentiallyTrustworthy(output.ad_render_url)) {
return absl::nullopt;
}
base::Value* components_value = input_dict->Find("components");
if (components_value) {
base::Value::List* components = components_value->GetIfList();
if (!components) {
return absl::nullopt;
}
for (const base::Value& component_val : *components) {
const std::string* component_str = component_val.GetIfString();
if (!component_str) {
return absl::nullopt;
}
GURL component(*component_str);
if (!component.is_valid() ||
!network::IsUrlPotentiallyTrustworthy(component)) {
return absl::nullopt;
}
output.ad_components.emplace_back(std::move(component));
}
}
std::string* maybe_name = input_dict->FindString("interestGroupName");
if (!maybe_name) {
return absl::nullopt;
}
output.interest_group_name = *maybe_name;
std::string* maybe_owner = input_dict->FindString("interestGroupOwner");
if (!maybe_owner) {
return absl::nullopt;
}
output.interest_group_owner = url::Origin::Create(GURL(*maybe_owner));
if (!network::IsOriginPotentiallyTrustworthy(output.interest_group_owner)) {
return absl::nullopt;
}
base::Value::Dict* bidding_groups = input_dict->FindDict("biddingGroups");
if (!bidding_groups) {
return absl::nullopt;
}
for (const auto owner_groups : *bidding_groups) {
url::Origin owner = url::Origin::Create(GURL(owner_groups.first));
if (!network::IsOriginPotentiallyTrustworthy(owner)) {
return absl::nullopt;
}
auto it = group_names.find(owner);
if (it == group_names.end()) {
return absl::nullopt;
}
const std::vector<std::string>& names = it->second;
const base::Value::List* groups = owner_groups.second.GetIfList();
if (!groups) {
return absl::nullopt;
}
for (const auto& group : *groups) {
absl::optional<int> maybe_group_idx = group.GetIfInt();
if (!maybe_group_idx) {
return absl::nullopt;
}
if (*maybe_group_idx < 0 ||
static_cast<size_t>(*maybe_group_idx) >= names.size()) {
return absl::nullopt;
}
output.bidding_groups.emplace_back(owner, names[*maybe_group_idx]);
}
}
output.score = input_dict->FindDouble("score");
output.bid = input_dict->FindDouble("bid");
base::Value::Dict* win_reporting_urls =
input_dict->FindDict("winReportingURLs");
if (win_reporting_urls) {
base::Value::Dict* buyer_reporting =
win_reporting_urls->FindDict("buyerReportingURLs");
if (buyer_reporting) {
output.buyer_reporting = ReportingURLs::TryParse(buyer_reporting);
}
base::Value::Dict* seller_reporting =
win_reporting_urls->FindDict("topLevelSellerReportingURLs");
if (seller_reporting) {
output.seller_reporting = ReportingURLs::TryParse(seller_reporting);
}
}
return std::move(output);
}
BiddingAndAuctionResponse::ReportingURLs::ReportingURLs() = default;
BiddingAndAuctionResponse::ReportingURLs::~ReportingURLs() = default;
BiddingAndAuctionResponse::ReportingURLs::ReportingURLs(ReportingURLs&&) =
default;
BiddingAndAuctionResponse::ReportingURLs&
BiddingAndAuctionResponse::ReportingURLs::operator=(ReportingURLs&&) = default;
// static
absl::optional<BiddingAndAuctionResponse::ReportingURLs>
BiddingAndAuctionResponse::ReportingURLs::TryParse(
base::Value::Dict* input_dict) {
ReportingURLs output;
std::string* maybe_reporting_url = input_dict->FindString("reportingURL");
if (maybe_reporting_url) {
GURL reporting_url(*maybe_reporting_url);
if (reporting_url.is_valid() &&
network::IsUrlPotentiallyTrustworthy(reporting_url)) {
output.reporting_url = std::move(reporting_url);
}
}
base::Value::Dict* interaction_reporting =
input_dict->FindDict("interactionReportingURLs");
if (interaction_reporting) {
std::vector<std::pair<std::string, GURL>> beacon_urls;
for (const auto interaction : *interaction_reporting) {
std::string* maybe_url = interaction.second.GetIfString();
if (!maybe_url) {
continue;
}
GURL beacon_url(*maybe_url);
if (!beacon_url.is_valid() ||
!network::IsUrlPotentiallyTrustworthy(beacon_url)) {
continue;
}
beacon_urls.emplace_back(interaction.first, std::move(beacon_url));
}
output.beacon_urls =
base::flat_map<std::string, GURL>(std::move(beacon_urls));
}
return std::move(output);
}
} // namespace content