chromium/chrome/browser/ash/floating_sso/floating_sso_service.h

// 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/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 "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:
  FloatingSsoService(PrefService* prefs,
                     std::unique_ptr<FloatingSsoSyncBridge> bridge,
                     network::mojom::CookieManager* cookie_manager);
  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;

  base::WeakPtr<syncer::DataTypeControllerDelegate> GetControllerDelegate();

  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();

  bool IsFloatingSsoEnabled();
  void MaybeStartListening();
  void StopListening();
  void BindToCookieManager();
  void OnCookiesLoaded(const net::CookieList& cookies);
  bool ShouldSyncCookie(const net::CanonicalCookie& cookie) const;
  void OnConnectionError();
  bool IsDomainAllowed(const net::CanonicalCookie& cookie) const;
  bool IsFloatingWorkspaceEnabled() const;

  raw_ptr<PrefService> prefs_ = nullptr;
  const raw_ptr<network::mojom::CookieManager> cookie_manager_;
  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;

  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_