blob: 51aba54395c6a961dd036ec131411a39cbf70431 [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.
#ifndef CHROME_BROWSER_ASH_FLOATING_SSO_FLOATING_SSO_SERVICE_H_
#define CHROME_BROWSER_ASH_FLOATING_SSO_FLOATING_SSO_SERVICE_H_
#include <memory>
#include "base/containers/flat_set.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ash/floating_sso/floating_sso_sync_bridge.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/sync/model/data_type_store.h"
#include "components/url_matcher/url_matcher.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_access_result.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
namespace syncer {
class DataTypeControllerDelegate;
} // namespace syncer
class PrefService;
namespace ash::floating_sso {
class FloatingSsoService : public KeyedService,
public network::mojom::CookieChangeListener,
public FloatingSsoSyncBridge::Observer {
public:
// Callback used to get a CookieManager.
using CookieManagerGetter =
base::RepeatingCallback<network::mojom::CookieManager*()>;
FloatingSsoService(PrefService* prefs,
std::unique_ptr<FloatingSsoSyncBridge> bridge,
CookieManagerGetter cookie_manager_getter);
FloatingSsoService(const FloatingSsoService&) = delete;
FloatingSsoService& operator=(const FloatingSsoService&) = delete;
~FloatingSsoService() override;
// KeyedService:
void Shutdown() override;
// network::mojom::CookieChangeListener:
void OnCookieChange(const net::CookieChangeInfo& change) override;
// FloatingSsoSyncBridge::Observer:
void OnCookiesAddedOrUpdatedRemotely(
const std::vector<net::CanonicalCookie>& cookies) override;
void OnCookiesRemovedRemotely(
const std::vector<net::CanonicalCookie>& cookies) override;
bool IsFloatingSsoEnabled();
// `callback` will be run once there are no cookie manager changes in
// progress. This can be called repeatedly but only the latest callback will
// be executed.
void RunWhenCookiesAreReady(base::OnceClosure callback);
// `callback` will be run once the bridge executes `MergeFullSyncData` method
// (which can only happen when Sync is being enabled for the first time on
// this client) and once conditions for `RunWhenCookiesAreReady` are also
// satisfied.
void RunWhenCookiesAreReadyOnFirstSync(base::OnceClosure callback);
base::WeakPtr<syncer::DataTypeControllerDelegate> GetControllerDelegate();
// Signal that this cookie shouldn't be overridden with remote
// entities on initial Sync cycle.
void MarkToNotOverride(const net::CanonicalCookie& cookie);
bool ShouldSyncCookiesForUrl(const GURL& url) const;
FloatingSsoSyncBridge* GetBridgeForTesting() { return bridge_.get(); }
bool IsBoundToCookieManagerForTesting() { return receiver_.is_bound(); }
private:
void RegisterPolicyListeners();
// Map the FloatingSsoDomainBlocklist and FloatingSsoDomainBlocklistExceptions
// policies to URL matchers.
void UpdateUrlMatchers();
// Check if the feature is enabled based on the corresponding enterprise
// policy. If yes, start observing cookies and uploading them to Sync, and
// apply cookies from Sync if needed. If not, stop all of the above.
void StartOrStop();
void MaybeStartListening();
void StopListening();
void BindToCookieManager();
void OnCookiesLoaded(const net::CookieList& cookies);
bool ShouldSyncCookie(const net::CanonicalCookie& cookie) const;
bool ShouldSyncSessionCookies() const;
void OnConnectionError();
bool IsDomainAllowed(const GURL& url) const;
void OnCookieSet(net::CookieAccessResult result);
void OnCookieDeleted(bool success);
void DecrementChangesCountAndMaybeNotify();
raw_ptr<PrefService> prefs_ = nullptr;
// TODO(crbug.com/378091718): investigated lifetime issues when using
// raw_ptr<network::mojom::CookieManager> instead of a callback here.
CookieManagerGetter cookie_manager_getter_;
std::unique_ptr<FloatingSsoSyncBridge> bridge_;
base::ScopedObservation<FloatingSsoSyncBridge,
FloatingSsoSyncBridge::Observer>
scoped_observation_{this};
std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
// We fetch the accumulated cookies the first time the service is started, as
// well when the service stops listening and resumes due to setting changes.
// We do not fetch accumulated cookies when the connection to the cookie
// manager is disrupted because we attempt to reconnect right away.
bool fetch_accumulated_cookies_ = true;
// Count of changes (additions or deletions of cookies) currently being
// performed by `cookie_manager_`.
// TODO(crbug.com/377471962): Add explicit tests for this counter and for
// `on_no_changes_in_progress_callback_`.
int changes_in_progress_count_ = 0;
base::OnceClosure on_no_changes_in_progress_callback_;
mojo::Receiver<network::mojom::CookieChangeListener> receiver_{this};
std::unique_ptr<url_matcher::URLMatcher> block_url_matcher_;
std::unique_ptr<url_matcher::URLMatcher> except_url_matcher_;
};
} // namespace ash::floating_sso
#endif // CHROME_BROWSER_ASH_FLOATING_SSO_FLOATING_SSO_SERVICE_H_