blob: 8332fb88d5d224f5b4d4548b55f93a465adae967 [file] [log] [blame]
// Copyright 2022 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/fenced_frame/fenced_frame_config.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/uuid.h"
#include "content/browser/fenced_frame/fenced_frame_reporter.h"
#include "services/network/public/cpp/attribution_reporting_runtime_features.h"
#include "third_party/blink/public/common/interest_group/ad_auction_constants.h"
namespace content {
const char kUrnUuidPrefix[] = "urn:uuid:";
GURL GenerateUrnUuid() {
return GURL(kUrnUuidPrefix +
base::Uuid::GenerateRandomV4().AsLowercaseString());
}
namespace {
std::vector<std::pair<GURL, FencedFrameConfig>>
GenerateURNConfigVectorForConfigs(
const std::vector<FencedFrameConfig>& nested_configs) {
std::vector<std::pair<GURL, FencedFrameConfig>> nested_urn_config_pairs;
DCHECK_LE(nested_configs.size(), blink::kMaxAdAuctionAdComponents);
for (const FencedFrameConfig& config : nested_configs) {
// Give each config its own urn:uuid. This ensures that if the same config
// is loaded into multiple fenced frames, they will not share the same
// urn:uuid across processes.
GURL urn_uuid = GenerateUrnUuid();
auto config_with_urn = config;
config_with_urn.urn_uuid_ = urn_uuid;
nested_urn_config_pairs.emplace_back(urn_uuid, config_with_urn);
}
// Pad `component_ads_` to contain exactly kMaxAdAuctionAdComponents ads, to
// avoid leaking any data to the fenced frame the component ads array is
// exposed to.
while (nested_urn_config_pairs.size() < blink::kMaxAdAuctionAdComponents) {
GURL urn_uuid = GenerateUrnUuid();
nested_urn_config_pairs.emplace_back(
urn_uuid, FencedFrameConfig(urn_uuid, GURL(url::kAboutBlankURL)));
}
return nested_urn_config_pairs;
}
template <typename Property>
void RedactProperty(
const absl::optional<FencedFrameProperty<Property>>& property,
FencedFrameEntity entity,
absl::optional<blink::FencedFrame::RedactedFencedFrameProperty<Property>>&
out) {
if (property.has_value()) {
out = blink::FencedFrame::RedactedFencedFrameProperty(
property->GetValueForEntity(entity));
}
}
} // namespace
FencedFrameConfig::FencedFrameConfig() = default;
FencedFrameConfig::FencedFrameConfig(const GURL& mapped_url)
: mapped_url_(absl::in_place,
mapped_url,
VisibilityToEmbedder::kOpaque,
VisibilityToContent::kTransparent),
mode_(DeprecatedFencedFrameMode::kOpaqueAds) {}
FencedFrameConfig::FencedFrameConfig(
const GURL& mapped_url,
const gfx::Size& content_size,
scoped_refptr<FencedFrameReporter> fenced_frame_reporter,
bool is_ad_component)
: mapped_url_(absl::in_place,
mapped_url,
VisibilityToEmbedder::kOpaque,
VisibilityToContent::kTransparent),
content_size_(absl::in_place,
content_size,
VisibilityToEmbedder::kTransparent,
VisibilityToContent::kTransparent),
deprecated_should_freeze_initial_size_(absl::in_place,
false,
VisibilityToEmbedder::kTransparent,
VisibilityToContent::kOpaque),
fenced_frame_reporter_(fenced_frame_reporter),
is_ad_component_(is_ad_component) {}
FencedFrameConfig::FencedFrameConfig(const GURL& urn_uuid,
const GURL& mapped_url)
: urn_uuid_(urn_uuid),
mapped_url_(absl::in_place,
mapped_url,
VisibilityToEmbedder::kOpaque,
VisibilityToContent::kTransparent),
mode_(DeprecatedFencedFrameMode::kOpaqueAds) {}
FencedFrameConfig::FencedFrameConfig(
const GURL& mapped_url,
scoped_refptr<FencedFrameReporter> fenced_frame_reporter,
bool is_ad_component)
: FencedFrameConfig(mapped_url) {
fenced_frame_reporter_ = fenced_frame_reporter;
is_ad_component_ = is_ad_component;
}
FencedFrameConfig::FencedFrameConfig(
const GURL& urn_uuid,
const GURL& mapped_url,
const SharedStorageBudgetMetadata& shared_storage_budget_metadata,
scoped_refptr<FencedFrameReporter> fenced_frame_reporter)
: urn_uuid_(urn_uuid),
mapped_url_(absl::in_place,
mapped_url,
VisibilityToEmbedder::kOpaque,
VisibilityToContent::kTransparent),
deprecated_should_freeze_initial_size_(absl::in_place,
false,
VisibilityToEmbedder::kTransparent,
VisibilityToContent::kOpaque),
shared_storage_budget_metadata_(absl::in_place,
shared_storage_budget_metadata,
VisibilityToEmbedder::kOpaque,
VisibilityToContent::kOpaque),
fenced_frame_reporter_(std::move(fenced_frame_reporter)),
mode_(DeprecatedFencedFrameMode::kOpaqueAds) {}
FencedFrameConfig::FencedFrameConfig(const FencedFrameConfig&) = default;
FencedFrameConfig::FencedFrameConfig(FencedFrameConfig&&) = default;
FencedFrameConfig::~FencedFrameConfig() = default;
FencedFrameConfig& FencedFrameConfig::operator=(const FencedFrameConfig&) =
default;
FencedFrameConfig& FencedFrameConfig::operator=(FencedFrameConfig&&) = default;
blink::FencedFrame::RedactedFencedFrameConfig FencedFrameConfig::RedactFor(
FencedFrameEntity entity) const {
blink::FencedFrame::RedactedFencedFrameConfig redacted_config;
if (urn_uuid_.has_value()) {
redacted_config.urn_uuid_ = urn_uuid_;
}
RedactProperty(mapped_url_, entity, redacted_config.mapped_url_);
RedactProperty(container_size_, entity, redacted_config.container_size_);
RedactProperty(content_size_, entity, redacted_config.content_size_);
RedactProperty(deprecated_should_freeze_initial_size_, entity,
redacted_config.deprecated_should_freeze_initial_size_);
RedactProperty(ad_auction_data_, entity, redacted_config.ad_auction_data_);
if (nested_configs_.has_value()) {
absl::optional<std::vector<FencedFrameConfig>>
partially_redacted_nested_configs =
nested_configs_->GetValueForEntity(entity);
if (partially_redacted_nested_configs.has_value()) {
redacted_config.nested_configs_.emplace(
std::vector<blink::FencedFrame::RedactedFencedFrameConfig>());
for (const FencedFrameConfig& nested_config :
partially_redacted_nested_configs.value()) {
redacted_config.nested_configs_->potentially_opaque_value->emplace_back(
nested_config.RedactFor(FencedFrameEntity::kEmbedder));
}
} else {
redacted_config.nested_configs_.emplace(absl::nullopt);
}
}
RedactProperty(shared_storage_budget_metadata_, entity,
redacted_config.shared_storage_budget_metadata_);
// The mode never needs to be redacted, because it is a function of which API
// was called to generate the config, rather than any cross-site data.
redacted_config.mode_ = mode_;
redacted_config.effective_enabled_permissions_ =
effective_enabled_permissions;
return redacted_config;
}
FencedFrameProperties::FencedFrameProperties()
: ad_auction_data_(absl::nullopt),
nested_urn_config_pairs_(absl::nullopt),
shared_storage_budget_metadata_(absl::nullopt),
embedder_shared_storage_context_(absl::nullopt),
partition_nonce_(absl::in_place,
base::UnguessableToken::Create(),
VisibilityToEmbedder::kOpaque,
VisibilityToContent::kOpaque) {}
FencedFrameProperties::FencedFrameProperties(const FencedFrameConfig& config)
: mapped_url_(config.mapped_url_),
container_size_(config.container_size_),
content_size_(config.content_size_),
deprecated_should_freeze_initial_size_(
config.deprecated_should_freeze_initial_size_),
ad_auction_data_(config.ad_auction_data_),
on_navigate_callback_(config.on_navigate_callback_),
nested_urn_config_pairs_(absl::nullopt),
shared_storage_budget_metadata_(absl::nullopt),
embedder_shared_storage_context_(absl::nullopt),
fenced_frame_reporter_(config.fenced_frame_reporter_),
partition_nonce_(absl::in_place,
base::UnguessableToken::Create(),
VisibilityToEmbedder::kOpaque,
VisibilityToContent::kOpaque),
mode_(config.mode_),
is_ad_component_(config.is_ad_component_),
effective_enabled_permissions(config.effective_enabled_permissions) {
if (config.shared_storage_budget_metadata_) {
shared_storage_budget_metadata_.emplace(
&config.shared_storage_budget_metadata_->GetValueIgnoringVisibility(),
config.shared_storage_budget_metadata_->visibility_to_embedder_,
config.shared_storage_budget_metadata_->visibility_to_content_);
}
if (config.nested_configs_) {
nested_urn_config_pairs_.emplace(
GenerateURNConfigVectorForConfigs(
config.nested_configs_->GetValueIgnoringVisibility()),
config.nested_configs_->visibility_to_embedder_,
config.nested_configs_->visibility_to_content_);
}
}
FencedFrameProperties::FencedFrameProperties(const FencedFrameProperties&) =
default;
FencedFrameProperties::FencedFrameProperties(FencedFrameProperties&&) = default;
FencedFrameProperties::~FencedFrameProperties() = default;
FencedFrameProperties& FencedFrameProperties::operator=(
const FencedFrameProperties&) = default;
FencedFrameProperties& FencedFrameProperties::operator=(
FencedFrameProperties&&) = default;
blink::FencedFrame::RedactedFencedFrameProperties
FencedFrameProperties::RedactFor(FencedFrameEntity entity) const {
blink::FencedFrame::RedactedFencedFrameProperties redacted_properties;
RedactProperty(mapped_url_, entity, redacted_properties.mapped_url_);
RedactProperty(container_size_, entity, redacted_properties.container_size_);
RedactProperty(content_size_, entity, redacted_properties.content_size_);
RedactProperty(deprecated_should_freeze_initial_size_, entity,
redacted_properties.deprecated_should_freeze_initial_size_);
RedactProperty(ad_auction_data_, entity,
redacted_properties.ad_auction_data_);
if (nested_urn_config_pairs_.has_value()) {
absl::optional<std::vector<std::pair<GURL, FencedFrameConfig>>>
partially_redacted_nested_urn_config_pairs =
nested_urn_config_pairs_->GetValueForEntity(entity);
if (partially_redacted_nested_urn_config_pairs.has_value()) {
redacted_properties.nested_urn_config_pairs_.emplace(
std::vector<std::pair<
GURL, blink::FencedFrame::RedactedFencedFrameConfig>>());
for (const std::pair<GURL, FencedFrameConfig>& nested_urn_config_pair :
*partially_redacted_nested_urn_config_pairs) {
redacted_properties.nested_urn_config_pairs_->potentially_opaque_value
->emplace_back(nested_urn_config_pair.first,
nested_urn_config_pair.second.RedactFor(
FencedFrameEntity::kEmbedder));
}
} else {
redacted_properties.nested_urn_config_pairs_.emplace(absl::nullopt);
}
}
if (shared_storage_budget_metadata_.has_value()) {
absl::optional<raw_ptr<const SharedStorageBudgetMetadata>>
potentially_opaque_ptr =
shared_storage_budget_metadata_->GetValueForEntity(entity);
if (potentially_opaque_ptr.has_value()) {
redacted_properties.shared_storage_budget_metadata_ =
blink::FencedFrame::RedactedFencedFrameProperty(
absl::make_optional(*potentially_opaque_ptr.value()));
} else {
redacted_properties.shared_storage_budget_metadata_.emplace(
absl::nullopt);
}
}
if ((fenced_frame_reporter_ || is_ad_component_) &&
entity != FencedFrameEntity::kCrossOriginContent) {
// An ad component should use its parent's fenced frame reporter. Even
// though it does not have a reporter in its `FencedFrameProperties`, this
// flag is still marked as true. Content that is cross-origin to the
// config's mapped url will not get access to its parent's reporter.
redacted_properties.has_fenced_frame_reporting_ = true;
}
// The mode never needs to be redacted, because it is a function of which API
// was called to generate the config, rather than any cross-site data.
redacted_properties.mode_ = mode_;
redacted_properties.effective_enabled_permissions_ =
effective_enabled_permissions;
return redacted_properties;
}
void FencedFrameProperties::UpdateMappedURL(GURL url) {
CHECK(mapped_url_.has_value());
mapped_url_->value_ = url;
}
void FencedFrameProperties::UpdateAutomaticBeaconData(
const std::string& event_data,
const std::vector<blink::FencedFrame::ReportingDestination>& destinations,
network::AttributionReportingRuntimeFeatures
attribution_reporting_runtime_features) {
// For an ad component, the event data from its automatic beacon is ignored.
automatic_beacon_info_.emplace(is_ad_component_ ? std::string{} : event_data,
destinations,
attribution_reporting_runtime_features);
}
} // namespace content