chromium/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.h

// Copyright 2018 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_POLICY_REMOTE_COMMANDS_CRD_CRD_ADMIN_SESSION_CONTROLLER_H_
#define CHROME_BROWSER_ASH_POLICY_REMOTE_COMMANDS_CRD_CRD_ADMIN_SESSION_CONTROLLER_H_

#include <memory>
#include <optional>
#include <string_view>
#include <vector>

#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/types/expected.h"
#include "chrome/browser/ash/policy/remote_commands/crd/crd_session_observer.h"
#include "chrome/browser/ash/policy/remote_commands/crd/remote_activity_notification_controller.h"
#include "chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "remoting/host/chromeos/chromeos_enterprise_params.h"
#include "remoting/host/chromeos/remote_support_host_ash.h"
#include "remoting/host/chromeos/session_id.h"
#include "remoting/host/mojom/remote_support.mojom-forward.h"

namespace ash::curtain {
class SecurityCurtainController;
}  // namespace ash::curtain

namespace policy {

// Controller that owns the admin initiated CRD session (if any).
//
// Will keep the session alive and active as long as this class lives.
// Deleting this class object will forcefully interrupt the active CRD session.
class CrdAdminSessionController : private StartCrdSessionJobDelegate,
                                  private CrdSessionObserver {
 public:
  // Proxy class to establish a connection with the Remoting service.
  // Overwritten in unittests to inject a test service.
  class RemotingServiceProxy {
   public:
    virtual ~RemotingServiceProxy() = default;

    using StartSessionCallback = base::OnceCallback<void(
        remoting::mojom::StartSupportSessionResponsePtr response)>;
    using SessionIdCallback =
        base::OnceCallback<void(std::optional<remoting::SessionId>)>;

    // Starts a new remote support session. `callback` is
    // called with the result.
    virtual void StartSession(
        remoting::mojom::SupportSessionParamsPtr params,
        const remoting::ChromeOsEnterpriseParams& enterprise_params,
        StartSessionCallback callback) = 0;

    // Checks if session information for a reconnectable session is stored,
    // and invokes `callback` with the id of the reconnectable session (or
    // std::nullopt if there is none).
    virtual void GetReconnectableSessionId(SessionIdCallback callback) = 0;

    // Starts a new remote support session, which will resume the reconnectable
    // session with the given `session_id`.
    virtual void ReconnectToSession(remoting::SessionId session_id,
                                    const std::string& oauth_access_token,
                                    StartSessionCallback callback) = 0;
  };

  CrdAdminSessionController();
  explicit CrdAdminSessionController(
      std::unique_ptr<RemotingServiceProxy> remoting_service);
  CrdAdminSessionController(const CrdAdminSessionController&) = delete;
  CrdAdminSessionController& operator=(const CrdAdminSessionController&) =
      delete;
  ~CrdAdminSessionController() override;

  static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);

  void Init(PrefService* local_state,
            ash::curtain::SecurityCurtainController& curtain_controller,
            base::OnceClosure done_callback = base::DoNothing());
  void Shutdown();

  StartCrdSessionJobDelegate& GetDelegate();

  void SetOAuthTokenForTesting(std::string_view token);
  void FailOAuthTokenFetchForTesting();

 private:
  class CrdHostSession;

  class SessionLauncher;
  class ReconnectedSessionLauncher;
  class NewSessionLauncher;

  // Checks if there is a reconnectable session, and if so this will reconnect
  // to it. A session is reconnectable when it was created with
  // `SessionParameters::allow_reconnections` set. `done_callback` is invoked
  // either when we conclude there is no reconnectable session, or when the
  // reconnectable session has been re-established.
  void TryToReconnect(base::OnceClosure done_callback);

  std::unique_ptr<CrdHostSession> CreateCrdHostSession();

  bool IsCurrentSessionCurtained() const;

  // `DeviceCommandStartCrdSessionJob::Delegate` implementation:
  bool HasActiveSession() const override;
  void TerminateSession() override;
  void StartCrdHostAndGetCode(
      const SessionParameters& parameters,
      AccessCodeCallback success_callback,
      ErrorCallback error_callback,
      SessionEndCallback session_finished_callback) override;

  // `CrdHostObserver` implementation:
  void OnHostStopped(ExtendedStartCrdSessionResultCode result,
                     const std::string& message) override;

  std::unique_ptr<RemotingServiceProxy> remoting_service_;
  std::unique_ptr<RemoteActivityNotificationController>
      notification_controller_;
  std::unique_ptr<CrdHostSession> active_session_;

  raw_ptr<ash::curtain::SecurityCurtainController> curtain_controller_ =
      nullptr;

  // During unittests the `DeviceOAuth2TokenService` will be null and the code
  // will instead use this OAuth token to restart a reconnectable session.
  std::optional<std::string> oauth_token_for_test_;
};

}  // namespace policy

#endif  // CHROME_BROWSER_ASH_POLICY_REMOTE_COMMANDS_CRD_CRD_ADMIN_SESSION_CONTROLLER_H_