chromium/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h

// Copyright 2020 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_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_CERTIFICATE_MANAGER_IMPL_H_
#define CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_CERTIFICATE_MANAGER_IMPL_H_

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

#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "base/timer/timer.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_encrypted_metadata_key.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.h"
#include "chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager.h"
#include "chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.h"
#include "chromeos/ash/components/nearby/common/client/nearby_http_result.h"
#include "chromeos/ash/services/nearby/public/mojom/nearby_share_settings.mojom.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "third_party/nearby/sharing/proto/rpc_resources.pb.h"

class NearbyShareClient;
class NearbyShareClientFactory;
class NearbyShareLocalDeviceDataManager;
class NearbyShareProfileInfoProvider;
class PrefService;

namespace device {
class BluetoothAdapter;
}  // namespace device

namespace leveldb_proto {
class ProtoDatabaseProvider;
}  // namespace leveldb_proto

namespace ash::nearby {
class NearbyScheduler;
}  // namespace ash::nearby

namespace nearby::sharing::proto {
class ListPublicCertificatesResponse;
}  // namespace nearby::sharing::proto

// An implementation of the NearbyShareCertificateManager that handles
//   1) creating, storing, and uploading local device certificates, as well as
//      removing expired/revoked local device certificates;
//   2) downloading, storing, and decrypting public certificates from trusted
//      contacts, as well as removing expired public certificates.
//
// This implementation destroys and recreates all private certificates if there
// are any changes to the user's contact list or allowlist, or if there are any
// changes to the local device data, such as the device name.
class NearbyShareCertificateManagerImpl
    : public NearbyShareCertificateManager,
      public NearbyShareContactManager::Observer,
      public NearbyShareLocalDeviceDataManager::Observer,
      public device::BluetoothAdapter::Observer {
 public:
  class Factory {
   public:
    static std::unique_ptr<NearbyShareCertificateManager> Create(
        NearbyShareLocalDeviceDataManager* local_device_data_manager,
        NearbyShareContactManager* contact_manager,
        NearbyShareProfileInfoProvider* profile_info_provider,
        PrefService* pref_service,
        leveldb_proto::ProtoDatabaseProvider* proto_database_provider,
        const base::FilePath& profile_path,
        NearbyShareClientFactory* client_factory,
        const base::Clock* clock = base::DefaultClock::GetInstance());
    static void SetFactoryForTesting(Factory* test_factory);

   protected:
    virtual ~Factory();
    virtual std::unique_ptr<NearbyShareCertificateManager> CreateInstance(
        NearbyShareLocalDeviceDataManager* local_device_data_manager,
        NearbyShareContactManager* contact_manager,
        NearbyShareProfileInfoProvider* profile_info_provider,
        PrefService* pref_service,
        leveldb_proto::ProtoDatabaseProvider* proto_database_provider,
        const base::FilePath& profile_path,
        NearbyShareClientFactory* client_factory,
        const base::Clock* clock) = 0;

   private:
    static Factory* test_factory_;
  };

  ~NearbyShareCertificateManagerImpl() override;

 private:
  NearbyShareCertificateManagerImpl(
      NearbyShareLocalDeviceDataManager* local_device_data_manager,
      NearbyShareContactManager* contact_manager,
      NearbyShareProfileInfoProvider* profile_info_provider,
      PrefService* pref_service,
      leveldb_proto::ProtoDatabaseProvider* proto_database_provider,
      const base::FilePath& profile_path,
      NearbyShareClientFactory* client_factory,
      const base::Clock* clock);

  // NearbyShareCertificateManager:
  std::vector<nearby::sharing::proto::PublicCertificate>
  GetPrivateCertificatesAsPublicCertificates(
      nearby_share::mojom::Visibility visibility) override;
  void GetDecryptedPublicCertificate(
      NearbyShareEncryptedMetadataKey encrypted_metadata_key,
      CertDecryptedCallback callback) override;
  void DownloadPublicCertificates() override;
  void OnStart() override;
  void OnStop() override;
  std::optional<NearbySharePrivateCertificate> GetValidPrivateCertificate(
      nearby_share::mojom::Visibility visibility) const override;
  void UpdatePrivateCertificateInStorage(
      const NearbySharePrivateCertificate& private_certificate) override;

  // NearbyShareContactManager::Observer:
  void OnContactsDownloaded(
      const std::set<std::string>& allowed_contact_ids,
      const std::vector<nearby::sharing::proto::ContactRecord>& contacts,
      uint32_t num_unreachable_contacts_filtered_out) override;
  void OnContactsUploaded(bool did_contacts_change_since_last_upload) override;

  // NearbyShareLocalDeviceDataManager::Observer:
  void OnLocalDeviceDataChanged(bool did_device_name_change,
                                bool did_full_name_change,
                                bool did_icon_change) override;

  // device::BluetoothAdapter::Observer:
  void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
                             bool powered) override;

  void OnGetAdapter(scoped_refptr<device::BluetoothAdapter> bluetooth_adapter);

  // Used by the private certificate expiration scheduler to determine the next
  // private certificate expiration time. Returns base::Time::Min() if
  // certificates are missing. This function never returns std::nullopt.
  std::optional<base::Time> NextPrivateCertificateExpirationTime();

  // Used by the public certificate expiration scheduler to determine the next
  // public certificate expiration time. Returns std::nullopt if no public
  // certificates are present, and no expiration event is scheduled.
  std::optional<base::Time> NextPublicCertificateExpirationTime();

  // Invoked by the private certificate expiration scheduler when an expired
  // private certificate needs to be removed or if no private certificates exist
  // yet. New certificate(s) will be created, and an upload to the Nearby Share
  // server will be requested. If the `adapter_` field is not ready to refresh
  // private certificates NearbyShareCertificateManagerImpl` stores a pending
  // call to refresh the private certificates until the `adapter_` is ready:
  //     - Case 1: [BlueZ] the `adapter_` is ready when the `BluetoothAdapter`
  //       has been retrieved in  `OnGetAdapter()`.
  //     - Case 2: [Floss] the `adapter_` is ready when the `BluetoothAdapter`
  //       has been retrieved in  `OnGetAdapter()` and the `adapter_` is
  //       powered on.
  //     - Case 3: [Floss] if the `BluetoothAdapter` has been retrieved in
  //       `OnGetAdapter()` and the `adapter_` is powered off,
  //       `NearbyShareCertificateManagerImpl` adds itself as a
  //       `AdapterPoweredChanged()` observer, and waits for the `adapter_` to
  //       be powered on. Then, the `adapter_` is ready.
  // Once the `adapter_` is ready as outlined above, a call to
  // `AttemptPrivateCertificateRefresh()` is fired to flush the pending
  // private certificate refresh.
  void AttemptPrivateCertificateRefresh();

  // Invoked by the certificate upload scheduler when private certificates need
  // to be converted to public certificates and uploaded to the Nearby Share
  // server.
  void OnLocalDeviceCertificateUploadRequest();

  void OnLocalDeviceCertificateUploadFinished(bool success);

  // Invoked by the public certificate expiration scheduler when an expired
  // public certificate needs to be removed from storage.
  void OnPublicCertificateExpiration();

  void OnExpiredPublicCertificatesRemoved(bool success);

  // Invoked by the certificate download scheduler when the public certificates
  // from trusted contacts need to be downloaded from Nearby Share server via
  // the ListPublicCertificates RPC.
  void OnDownloadPublicCertificatesRequest(
      std::optional<std::string> page_token,
      size_t page_number,
      size_t certificate_count);

  void OnListPublicCertificatesSuccess(
      size_t page_number,
      size_t certificate_count,
      const nearby::sharing::proto::ListPublicCertificatesResponse& response);
  void OnListPublicCertificatesFailure(size_t page_number,
                                       size_t certificate_count,
                                       ash::nearby::NearbyHttpError error);
  void OnListPublicCertificatesTimeout(size_t page_number,
                                       size_t certificate_count);
  void OnPublicCertificatesAddedToStorage(std::optional<std::string> page_token,
                                          size_t page_number,
                                          size_t certificate_count,
                                          bool success);
  void FinishDownloadPublicCertificates(
      bool success,
      ash::nearby::NearbyHttpResult http_result,
      size_t page_number,
      size_t certificate_count);

  base::OneShotTimer timer_;
  raw_ptr<NearbyShareLocalDeviceDataManager> local_device_data_manager_ =
      nullptr;
  raw_ptr<NearbyShareContactManager> contact_manager_ = nullptr;
  raw_ptr<NearbyShareProfileInfoProvider> profile_info_provider_ = nullptr;
  raw_ptr<PrefService> pref_service_ = nullptr;
  raw_ptr<NearbyShareClientFactory> client_factory_ = nullptr;
  raw_ptr<const base::Clock> clock_;
  std::unique_ptr<NearbyShareCertificateStorage> certificate_storage_;
  std::unique_ptr<ash::nearby::NearbyScheduler>
      private_certificate_expiration_scheduler_;
  std::unique_ptr<ash::nearby::NearbyScheduler>
      public_certificate_expiration_scheduler_;
  std::unique_ptr<ash::nearby::NearbyScheduler>
      upload_local_device_certificates_scheduler_;
  std::unique_ptr<ash::nearby::NearbyScheduler>
      download_public_certificates_scheduler_;
  std::unique_ptr<NearbyShareClient> client_;

  // See documentation in declaration of `AttemptPrivateCertificateRefresh()`.
  // `adapter_` is set asynchronously in a call to `GetBluetoothAdapter()`
  // during the construction of `NearbyShareCertificateManagerImpl`. If
  // private certificates refreshes are requested when `adapter_` is not ready,
  // store a pending call via
  // `is_pending_call_to_refresh_private_certificates_`.
  scoped_refptr<device::BluetoothAdapter> adapter_;
  bool is_pending_call_to_refresh_private_certificates_ = false;
  base::ScopedObservation<device::BluetoothAdapter,
                          device::BluetoothAdapter::Observer>
      adapter_observation_{this};

  base::WeakPtrFactory<NearbyShareCertificateManagerImpl> weak_ptr_factory_{
      this};
};

#endif  // CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_CERTIFICATE_MANAGER_IMPL_H_