blob: 2fdca154f77a9bc6a6dc25dbb947735021424e4f [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 "chrome/browser/browsing_data/chrome_browsing_data_model_delegate.h"
#include <memory>
#include <variant>
#include "base/barrier_callback.h"
#include "base/functional/callback_helpers.h"
#include "base/functional/concurrent_callbacks.h"
#include "base/functional/concurrent_closures.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "chrome/browser/browsing_topics/browsing_topics_service_factory.h"
#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
#include "chrome/browser/webid/federated_identity_permission_context.h"
#include "chrome/browser/webid/federated_identity_permission_context_factory.h"
#include "components/browsing_topics/browsing_topics_service.h"
#include "components/content_settings/browser/page_specific_content_settings.h"
#include "components/media_device_salt/media_device_salt_service.h"
#include "components/permissions/permissions_client.h"
#include "components/supervised_user/core/common/features.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/storage_partition_config.h"
#include "url/origin.h"
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
#include "chrome/browser/web_applications/isolated_web_apps/remove_isolated_web_app_data.h"
#include "chrome/browser/web_applications/web_app_command_scheduler.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#endif
namespace {
#if !BUILDFLAG(IS_ANDROID)
std::vector<ChromeBrowsingDataModelDelegate::DelegateEntry>
IsolatedWebAppBrowsingDataToDelegateEntries(
base::flat_map<url::Origin, uint64_t> isolated_web_app_browsing_data) {
std::vector<ChromeBrowsingDataModelDelegate::DelegateEntry> entries;
for (auto const& [origin, size] : isolated_web_app_browsing_data) {
entries.emplace_back(
origin,
static_cast<BrowsingDataModel::StorageType>(
ChromeBrowsingDataModelDelegate::StorageType::kIsolatedWebApp),
size);
}
return entries;
}
#endif // !BUILDFLAG(IS_ANDROID)
std::vector<ChromeBrowsingDataModelDelegate::DelegateEntry>
FlattenDelegateEntries(
std::vector<std::vector<ChromeBrowsingDataModelDelegate::DelegateEntry>>
entries) {
std::vector<ChromeBrowsingDataModelDelegate::DelegateEntry> flattened_entries;
for (const auto& vec : entries) {
flattened_entries.insert(flattened_entries.end(), vec.begin(), vec.end());
}
return flattened_entries;
}
} // namespace
// static
std::unique_ptr<ChromeBrowsingDataModelDelegate>
ChromeBrowsingDataModelDelegate::CreateForProfile(Profile* profile) {
return base::WrapUnique(new ChromeBrowsingDataModelDelegate(
profile, profile->GetDefaultStoragePartition()));
}
// static
std::unique_ptr<ChromeBrowsingDataModelDelegate>
ChromeBrowsingDataModelDelegate::CreateForStoragePartition(
Profile* profile,
content::StoragePartition* storage_partition) {
return base::WrapUnique(
new ChromeBrowsingDataModelDelegate(profile, storage_partition));
}
// static
void ChromeBrowsingDataModelDelegate::BrowsingDataAccessed(
content::RenderFrameHost* rfh,
const BrowsingDataModel::DataKey& data_key,
StorageType storage_type,
bool blocked) {
content_settings::PageSpecificContentSettings::BrowsingDataAccessed(
rfh, data_key, static_cast<BrowsingDataModel::StorageType>(storage_type),
blocked);
}
ChromeBrowsingDataModelDelegate::ChromeBrowsingDataModelDelegate(
Profile* profile,
content::StoragePartition* storage_partition)
: profile_(profile), storage_partition_(storage_partition) {}
ChromeBrowsingDataModelDelegate::~ChromeBrowsingDataModelDelegate() = default;
void ChromeBrowsingDataModelDelegate::GetAllDataKeys(
base::OnceCallback<void(std::vector<DelegateEntry>)> callback) {
base::ConcurrentCallbacks<std::vector<DelegateEntry>> concurrent;
GetAllFederatedIdentityDataKeys(concurrent.CreateCallback(), {});
#if !BUILDFLAG(IS_ANDROID)
auto* web_app_provider = web_app::WebAppProvider::GetForWebApps(profile_);
if (web_app_provider && storage_partition_->GetConfig().is_default()) {
web_app_provider->scheduler().GetIsolatedWebAppBrowsingData(
base::BindOnce(&IsolatedWebAppBrowsingDataToDelegateEntries)
.Then(concurrent.CreateCallback()));
}
#endif // !BUILDFLAG(IS_ANDROID)
GetAllMediaDeviceSaltDataKeys(concurrent.CreateCallback(), {});
// TODO(crbug.com/40205603): Implement data retrieval for remaining data
// types.
std::move(concurrent)
.Done(base::BindOnce(&FlattenDelegateEntries).Then(std::move(callback)));
}
void ChromeBrowsingDataModelDelegate::RemoveDataKey(
const BrowsingDataModel::DataKey& data_key,
BrowsingDataModel::StorageTypeSet storage_types,
base::OnceClosure callback) {
base::ConcurrentClosures concurrent;
if (storage_types.Has(
static_cast<BrowsingDataModel::StorageType>(StorageType::kTopics))) {
// Topics can be deleted but not queried from disk as the creating origins
// are hashed before being saved.
const url::Origin* origin = std::get_if<url::Origin>(&data_key);
auto* browsing_topics_service =
browsing_topics::BrowsingTopicsServiceFactory::GetForProfile(profile_);
browsing_topics_service->ClearTopicsDataForOrigin(*origin);
}
if (storage_types.Has(static_cast<BrowsingDataModel::StorageType>(
StorageType::kMediaDeviceSalt))) {
if (const blink::StorageKey* storage_key =
std::get_if<blink::StorageKey>(&data_key)) {
RemoveMediaDeviceSalt(*storage_key, concurrent.CreateClosure());
}
}
if (storage_types.Has(static_cast<BrowsingDataModel::StorageType>(
StorageType::kFederatedIdentity))) {
if (const webid::FederatedIdentityDataModel::DataKey*
federated_identity_data_key =
std::get_if<webid::FederatedIdentityDataModel::DataKey>(
&data_key)) {
RemoveFederatedIdentityData(*federated_identity_data_key,
concurrent.CreateClosure());
}
}
#if !BUILDFLAG(IS_ANDROID)
if (storage_types.Has(static_cast<BrowsingDataModel::StorageType>(
StorageType::kIsolatedWebApp))) {
CHECK(std::holds_alternative<url::Origin>(data_key));
const url::Origin& origin = *std::get_if<url::Origin>(&data_key);
web_app::RemoveIsolatedWebAppBrowsingData(profile_, origin,
concurrent.CreateClosure());
}
#endif // !BUILDFLAG(IS_ANDROID)
std::move(concurrent).Done(std::move(callback));
}
std::optional<BrowsingDataModel::DataOwner>
ChromeBrowsingDataModelDelegate::GetDataOwner(
const BrowsingDataModel::DataKey& data_key,
BrowsingDataModel::StorageType storage_type) const {
switch (static_cast<StorageType>(storage_type)) {
case StorageType::kIsolatedWebApp:
CHECK(std::holds_alternative<url::Origin>(data_key))
<< "Unsupported IWA DataKey type: " << data_key.index();
return std::get<url::Origin>(data_key);
case StorageType::kTopics:
CHECK(std::holds_alternative<url::Origin>(data_key))
<< "Unsupported Topics DataKey type: " << data_key.index();
return std::get<url::Origin>(data_key).host();
case StorageType::kMediaDeviceSalt:
CHECK(std::holds_alternative<blink::StorageKey>(data_key))
<< "Unsupported MediaDeviceSalt DataKey type: " << data_key.index();
return std::get<blink::StorageKey>(data_key).origin().host();
case StorageType::kFederatedIdentity:
CHECK(std::holds_alternative<webid::FederatedIdentityDataModel::DataKey>(
data_key))
<< "Unsupported FederatedIdentity DataKey type: " << data_key.index();
return std::get<webid::FederatedIdentityDataModel::DataKey>(data_key)
.relying_party_embedder()
.host();
default:
return std::nullopt;
}
}
std::optional<bool> ChromeBrowsingDataModelDelegate::IsStorageTypeCookieLike(
BrowsingDataModel::StorageType storage_type) const {
// Values below the first delegate type are handled in the model itself.
if (static_cast<int>(storage_type) <
static_cast<int>(StorageType::kFirstType)) {
return std::nullopt;
}
switch (
static_cast<ChromeBrowsingDataModelDelegate::StorageType>(storage_type)) {
case StorageType::kTopics:
case StorageType::kIsolatedWebApp:
case StorageType::kMediaDeviceSalt:
return false;
default:
NOTREACHED();
}
}
std::optional<bool>
ChromeBrowsingDataModelDelegate::IsBlockedByThirdPartyCookieBlocking(
const BrowsingDataModel::DataKey& data_key,
BrowsingDataModel::StorageType storage_type) const {
// TODO(crbug.com/40066162): Implement `GetThirdPartyPartitioningSite()` for
// delegate-specific data keys.
return IsStorageTypeCookieLike(storage_type);
}
bool ChromeBrowsingDataModelDelegate::IsCookieDeletionDisabled(
const GURL& url) {
CHECK(profile_);
if (profile_->IsChild()) {
auto* client = permissions::PermissionsClient::Get();
return client->IsCookieDeletionDisabled(profile_, url);
}
return false;
}
base::WeakPtr<BrowsingDataModel::Delegate>
ChromeBrowsingDataModelDelegate::AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void ChromeBrowsingDataModelDelegate::GetAllMediaDeviceSaltDataKeys(
base::OnceCallback<void(std::vector<DelegateEntry>)> callback,
std::vector<DelegateEntry> entries) {
if (auto* service =
MediaDeviceSaltServiceFactory::GetInstance()->GetForBrowserContext(
profile_)) {
service->GetAllStorageKeys(base::BindOnce(
&ChromeBrowsingDataModelDelegate::GotAllMediaDeviceSaltDataKeys,
weak_ptr_factory_.GetWeakPtr(), std::move(callback),
std::move(entries)));
} else {
std::move(callback).Run(std::move(entries));
}
}
void ChromeBrowsingDataModelDelegate::GotAllMediaDeviceSaltDataKeys(
base::OnceCallback<void(std::vector<DelegateEntry>)> callback,
std::vector<DelegateEntry> entries,
std::vector<blink::StorageKey> storage_keys) {
static constexpr uint64_t kMediaDeviceSaltEntrySize = 100;
for (const auto& key : storage_keys) {
entries.emplace_back(key,
static_cast<BrowsingDataModel::StorageType>(
StorageType::kMediaDeviceSalt),
kMediaDeviceSaltEntrySize);
}
std::move(callback).Run(std::move(entries));
}
void ChromeBrowsingDataModelDelegate::RemoveMediaDeviceSalt(
const blink::StorageKey& storage_key,
base::OnceClosure callback) {
media_device_salt::MediaDeviceSaltService* service =
MediaDeviceSaltServiceFactory::GetInstance()->GetForBrowserContext(
profile_);
if (service) {
service->DeleteSalt(storage_key, std::move(callback));
} else {
std::move(callback).Run();
}
}
void ChromeBrowsingDataModelDelegate::GetAllFederatedIdentityDataKeys(
base::OnceCallback<void(std::vector<DelegateEntry>)> callback,
std::vector<DelegateEntry> entries) {
if (auto* context =
FederatedIdentityPermissionContextFactory::GetForProfile(profile_)) {
context->GetAllDataKeys(base::BindOnce(
&ChromeBrowsingDataModelDelegate::GotAllFederatedIdentityDataKeys,
weak_ptr_factory_.GetWeakPtr(), std::move(callback),
std::move(entries)));
} else {
std::move(callback).Run(std::move(entries));
}
}
void ChromeBrowsingDataModelDelegate::GotAllFederatedIdentityDataKeys(
base::OnceCallback<void(std::vector<DelegateEntry>)> callback,
std::vector<DelegateEntry> entries,
std::vector<webid::FederatedIdentityDataModel::DataKey> data_keys) {
static constexpr uint64_t kFederatedIdentityDataEntrySize = 100;
for (const auto& key : data_keys) {
entries.emplace_back(key,
static_cast<BrowsingDataModel::StorageType>(
StorageType::kFederatedIdentity),
kFederatedIdentityDataEntrySize);
}
std::move(callback).Run(std::move(entries));
}
void ChromeBrowsingDataModelDelegate::RemoveFederatedIdentityData(
const webid::FederatedIdentityDataModel::DataKey& data_key,
base::OnceClosure callback) {
if (auto* context =
FederatedIdentityPermissionContextFactory::GetForProfile(profile_)) {
context->RemoveFederatedIdentityDataByDataKey(data_key,
std::move(callback));
} else {
std::move(callback).Run();
}
}