blob: e9de6ad338ac544569876a0d5244ecc43a515f95 [file] [log] [blame]
// Copyright 2019 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/browsing_data/same_site_data_remover_impl.h"
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/barrier_closure.h"
#include "base/bind.h"
#include "base/callback.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browsing_data_filter_builder.h"
#include "content/public/browser/same_site_data_remover.h"
#include "content/public/browser/storage_partition.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_constants.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_util.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "url/origin.h"
namespace content {
namespace {
const uint32_t kStoragePartitionRemovalMask =
content::StoragePartition::REMOVE_DATA_MASK_ALL &
~content::StoragePartition::REMOVE_DATA_MASK_COOKIES;
void OnGetAllCookiesWithAccessSemantics(
base::OnceClosure closure,
network::mojom::CookieManager* cookie_manager,
std::set<std::string>* same_site_none_domains,
const std::vector<net::CanonicalCookie>& cookies,
const std::vector<net::CookieAccessSemantics>& access_semantics_list) {
DCHECK(cookies.size() == access_semantics_list.size());
base::RepeatingClosure barrier =
base::BarrierClosure(cookies.size(), std::move(closure));
for (size_t i = 0; i < cookies.size(); ++i) {
const net::CanonicalCookie& cookie = cookies[i];
// Partitioned cookies are only available in a single top-level site (or
// that site's First-Party Set). Since partitioned cookies cannot be used as
// a cross-site tracking mechanism, we exclude them from this type of
// clearing.
if (!cookie.IsPartitioned() &&
cookie.IsEffectivelySameSiteNone(access_semantics_list[i])) {
same_site_none_domains->emplace(cookie.Domain());
cookie_manager->DeleteCanonicalCookie(
cookie, base::BindOnce([](const base::RepeatingClosure& callback,
bool success) { callback.Run(); },
barrier));
} else {
barrier.Run();
}
}
}
std::unique_ptr<BrowsingDataFilterBuilder> CreateBrowsingDataFilterBuilder(
const std::set<std::string>& same_site_none_domains) {
std::unique_ptr<BrowsingDataFilterBuilder> filter_builder =
BrowsingDataFilterBuilder::Create(
BrowsingDataFilterBuilder::Mode::kDelete);
for (const std::string& domain : same_site_none_domains) {
std::string host_domain = net::cookie_util::CookieDomainAsHost(domain);
std::string registrable_domain = GetDomainAndRegistry(
host_domain,
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
filter_builder->AddRegisterableDomain(
registrable_domain.empty() ? host_domain : registrable_domain);
}
return filter_builder;
}
} // namespace
SameSiteDataRemoverImpl::SameSiteDataRemoverImpl(
BrowserContext* browser_context)
: browser_context_(browser_context),
storage_partition_(browser_context_->GetDefaultStoragePartition()) {
DCHECK(browser_context_);
}
SameSiteDataRemoverImpl::~SameSiteDataRemoverImpl() {}
const std::set<std::string>&
SameSiteDataRemoverImpl::GetDeletedDomainsForTesting() {
return same_site_none_domains_;
}
void SameSiteDataRemoverImpl::OverrideStoragePartitionForTesting(
StoragePartition* storage_partition) {
storage_partition_ = storage_partition;
}
void SameSiteDataRemoverImpl::DeleteSameSiteNoneCookies(
base::OnceClosure closure) {
same_site_none_domains_.clear();
auto* cookie_manager =
storage_partition_->GetCookieManagerForBrowserProcess();
cookie_manager->GetAllCookiesWithAccessSemantics(
base::BindOnce(&OnGetAllCookiesWithAccessSemantics, std::move(closure),
cookie_manager, &same_site_none_domains_));
}
void SameSiteDataRemoverImpl::ClearStoragePartitionData(
base::OnceClosure closure) {
// TODO(crbug.com/987177): Figure out how to handle protected storage.
std::unique_ptr<BrowsingDataFilterBuilder> filter_builder =
CreateBrowsingDataFilterBuilder(same_site_none_domains_);
storage_partition_->ClearData(
kStoragePartitionRemovalMask,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, filter_builder.get(),
StoragePartition::StorageKeyPolicyMatcherFunction(), nullptr, false,
base::Time(), base::Time::Max(), std::move(closure));
}
void SameSiteDataRemoverImpl::ClearStoragePartitionForOrigins(
base::OnceClosure closure,
std::set<url::Origin> origins) {
// TODO(crbug.com/987177): Figure out how to handle protected storage.
std::unique_ptr<BrowsingDataFilterBuilder> filter_builder =
BrowsingDataFilterBuilder::Create(
BrowsingDataFilterBuilder::Mode::kDelete);
for (const url::Origin& origin : origins) {
filter_builder->AddOrigin(origin);
}
storage_partition_->ClearData(
kStoragePartitionRemovalMask,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, filter_builder.get(),
StoragePartition::StorageKeyPolicyMatcherFunction(), nullptr, false,
base::Time(), base::Time::Max(), std::move(closure));
}
// Defines the ClearSameSiteNoneData function declared in same_site_remover.h.
// Clears cookies and associated data available in third-party contexts.
void ClearSameSiteNoneData(base::OnceClosure closure, BrowserContext* context) {
auto same_site_remover = std::make_unique<SameSiteDataRemoverImpl>(context);
SameSiteDataRemoverImpl* remover = same_site_remover.get();
remover->DeleteSameSiteNoneCookies(
base::BindOnce(&SameSiteDataRemoverImpl::ClearStoragePartitionData,
std::move(same_site_remover), std::move(closure)));
}
void ClearSameSiteNoneCookiesAndStorageForOrigins(
base::OnceClosure closure,
BrowserContext* context,
std::set<url::Origin> origins) {
auto same_site_remover = std::make_unique<SameSiteDataRemoverImpl>(context);
SameSiteDataRemoverImpl* remover = same_site_remover.get();
remover->DeleteSameSiteNoneCookies(base::BindOnce(
&SameSiteDataRemoverImpl::ClearStoragePartitionForOrigins,
std::move(same_site_remover), std::move(closure), std::move(origins)));
}
} // namespace content