blob: 49fa03dc0e2515b078f39ace63e17e98eb67e673 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/device_bound_session_manager.h"
#include "base/barrier_callback.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/functional/callback_helpers.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/cookies/canonical_cookie.h"
#include "net/device_bound_sessions/session_params.h"
#include "net/device_bound_sessions/session_service.h"
#include "services/network/cookie_manager.h"
#include "services/network/public/mojom/clear_data_filter.mojom.h"
namespace network {
// static
std::unique_ptr<DeviceBoundSessionManager> DeviceBoundSessionManager::Create(
net::device_bound_sessions::SessionService* service,
CookieManager* cookie_manager) {
if (!service) {
return nullptr;
}
return base::WrapUnique(
new DeviceBoundSessionManager(service, cookie_manager));
}
DeviceBoundSessionManager::DeviceBoundSessionManager(
net::device_bound_sessions::SessionService* service,
CookieManager* cookie_manager)
: service_(service), cookie_manager_(cookie_manager) {}
DeviceBoundSessionManager::~DeviceBoundSessionManager() = default;
void DeviceBoundSessionManager::AddReceiver(
mojo::PendingReceiver<mojom::DeviceBoundSessionManager> receiver) {
receivers_.Add(this, std::move(receiver));
}
void DeviceBoundSessionManager::GetAllSessions(
DeviceBoundSessionManager::GetAllSessionsCallback callback) {
service_->GetAllSessionsAsync(std::move(callback));
}
void DeviceBoundSessionManager::DeleteSession(
net::device_bound_sessions::DeletionReason reason,
const net::device_bound_sessions::SessionKey& session_key) {
service_->DeleteSessionAndNotify(
reason,
{session_key.site,
net::device_bound_sessions::Session::Id(session_key.id)},
base::NullCallback());
}
void DeviceBoundSessionManager::DeleteAllSessions(
net::device_bound_sessions::DeletionReason reason,
std::optional<base::Time> created_after_time,
std::optional<base::Time> created_before_time,
network::mojom::ClearDataFilterPtr filter,
base::OnceClosure completion_callback) {
base::RepeatingCallback<bool(const url::Origin&, const net::SchemefulSite&)>
origin_and_site_matcher;
if (filter) {
origin_and_site_matcher = base::BindRepeating(
// TODO(crbug.com/384437667): Consolidate ClearDataFilter matching logic
[](const mojom::ClearDataFilter& filter, const url::Origin& origin,
const net::SchemefulSite& site) {
bool is_match = base::Contains(filter.origins, origin);
if (!is_match && !filter.domains.empty()) {
const std::string etld1_for_origin =
net::registry_controlled_domains::GetDomainAndRegistry(
site.GetURL(), net::registry_controlled_domains::
INCLUDE_PRIVATE_REGISTRIES);
is_match = base::Contains(filter.domains, etld1_for_origin);
}
switch (filter.type) {
case mojom::ClearDataFilter::Type::KEEP_MATCHES:
return !is_match;
case mojom::ClearDataFilter::Type::DELETE_MATCHES:
return is_match;
}
},
*filter);
}
service_->DeleteAllSessions(reason, created_after_time, created_before_time,
origin_and_site_matcher,
std::move(completion_callback));
}
DeviceBoundSessionManager::ObserverRegistration::ObserverRegistration() =
default;
DeviceBoundSessionManager::ObserverRegistration::~ObserverRegistration() =
default;
void DeviceBoundSessionManager::AddObserver(
const GURL& url,
mojo::PendingRemote<network::mojom::DeviceBoundSessionAccessObserver>
observer) {
auto registration = std::make_unique<ObserverRegistration>();
registration->remote.Bind(std::move(observer));
registration->remote.set_disconnect_handler(
base::BindOnce(&DeviceBoundSessionManager::RemoveObserver,
// base::Unretained is safe because `this` owns
// `registration`, which owns the callback.
base::Unretained(this), registration.get()));
registration->subscription = service_->AddObserver(
url,
base::BindRepeating(&network::mojom::DeviceBoundSessionAccessObserver::
OnDeviceBoundSessionAccessed,
base::Unretained(registration->remote.get())));
observer_registrations_.push_back(std::move(registration));
}
void DeviceBoundSessionManager::CreateBoundSessions(
std::vector<net::device_bound_sessions::SessionParams> params,
const std::vector<uint8_t>& wrapped_key,
const std::vector<net::CanonicalCookie>& cookies_to_set,
const net::CookieOptions& cookie_options,
CreateBoundSessionsCallback callback) {
auto barrier_callback = base::BarrierCallback<
net::device_bound_sessions::SessionError::ErrorType>(
params.size(),
base::BindOnce(&DeviceBoundSessionManager::OnCreateBoundSessionsAdded,
weak_factory_.GetWeakPtr(), cookies_to_set, cookie_options,
std::move(callback)));
for (net::device_bound_sessions::SessionParams& param : params) {
GURL fetcher_url = param.fetcher_url;
service_->AddSession(net::SchemefulSite(fetcher_url), std::move(param),
wrapped_key, barrier_callback);
}
}
void DeviceBoundSessionManager::OnCreateBoundSessionsAdded(
const std::vector<net::CanonicalCookie>& cookies_to_set,
const net::CookieOptions& cookie_options,
CreateBoundSessionsCallback callback,
std::vector<net::device_bound_sessions::SessionError::ErrorType>
session_results) {
if (cookies_to_set.empty()) {
std::move(callback).Run(std::move(session_results),
std::vector<net::CookieInclusionStatus>());
return;
}
auto final_callback = base::BindOnce(
[](CreateBoundSessionsCallback callback,
std::vector<net::device_bound_sessions::SessionError::ErrorType>
create_session_results,
std::vector<net::CookieAccessResult> results) {
std::vector<net::CookieInclusionStatus> cookie_results;
cookie_results.reserve(results.size());
for (auto& result : results) {
cookie_results.push_back(std::move(result.status));
}
std::move(callback).Run(std::move(create_session_results),
std::move(cookie_results));
},
std::move(callback), std::move(session_results));
auto barrier_callback = base::BarrierCallback<net::CookieAccessResult>(
cookies_to_set.size(), std::move(final_callback));
for (const auto& cookie : cookies_to_set) {
cookie_manager_->SetCanonicalCookie(
cookie, net::cookie_util::SimulatedCookieSource(cookie, "https"),
cookie_options, barrier_callback);
}
}
void DeviceBoundSessionManager::RemoveObserver(
DeviceBoundSessionManager::ObserverRegistration* registration) {
std::erase_if(observer_registrations_, base::MatchesUniquePtr(registration));
}
} // namespace network