// 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.

#include "content/browser/webauth/virtual_authenticator.h"

#include <optional>
#include <utility>

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/uuid.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
#include "device/fido/public_key_credential_rp_entity.h"
#include "device/fido/public_key_credential_user_entity.h"
#include "device/fido/virtual_ctap2_device.h"
#include "device/fido/virtual_u2f_device.h"
#include "mojo/public/cpp/base/big_buffer.h"

namespace content {

VirtualAuthenticator::Options::Options() = default;
VirtualAuthenticator::Options::~Options() = default;

VirtualAuthenticator::VirtualAuthenticator(const Options& options)
    : protocol_(options.protocol),
      ctap2_version_(options.ctap2_version),
      attachment_(options.attachment),
      has_resident_key_(options.has_resident_key),
      has_user_verification_(options.has_user_verification),
      has_large_blob_(options.has_large_blob),
      has_cred_blob_(options.has_cred_blob),
      has_min_pin_length_(options.has_min_pin_length),
      has_prf_(options.has_prf),
      unique_id_(base::Uuid::GenerateRandomV4().AsLowercaseString()),
      state_(base::MakeRefCounted<device::VirtualFidoDevice::State>()) {
  state_->transport = options.transport;
  // If the authenticator has user verification, simulate having set it up
  // already.
  state_->fingerprints_enrolled = has_user_verification_;
  state_->default_backup_eligibility = options.default_backup_eligibility;
  state_->default_backup_state = options.default_backup_state;
  observation_.Observe(state_.get());
  SetUserPresence(true);
}

VirtualAuthenticator::~VirtualAuthenticator() {
  for (Observer& observer : observers_) {
    observer.OnAuthenticatorWillBeDestroyed(this);
  }
}

bool VirtualAuthenticator::AddRegistration(
    std::vector<uint8_t> key_handle,
    const std::string& rp_id,
    base::span<const uint8_t> private_key,
    int32_t counter) {
  std::optional<std::unique_ptr<device::VirtualFidoDevice::PrivateKey>>
      fido_private_key =
          device::VirtualFidoDevice::PrivateKey::FromPKCS8(private_key);
  if (!fido_private_key) {
    return false;
  }

  return state_->registrations
      .emplace(
          std::move(key_handle),
          device::VirtualFidoDevice::RegistrationData(
              std::move(*fido_private_key),
              device::fido_parsing_utils::CreateSHA256Hash(rp_id), counter))
      .second;
}

bool VirtualAuthenticator::AddResidentRegistration(
    std::vector<uint8_t> key_handle,
    std::string rp_id,
    base::span<const uint8_t> private_key,
    int32_t counter,
    std::vector<uint8_t> user_handle,
    std::optional<std::string> user_name,
    std::optional<std::string> user_display_name) {
  std::optional<std::unique_ptr<device::VirtualFidoDevice::PrivateKey>>
      fido_private_key =
          device::VirtualFidoDevice::PrivateKey::FromPKCS8(private_key);
  if (!fido_private_key) {
    return false;
  }

  return state_->InjectResidentKey(
      std::move(key_handle),
      device::PublicKeyCredentialRpEntity(std::move(rp_id)),
      device::PublicKeyCredentialUserEntity(std::move(user_handle),
                                            std::move(user_name),
                                            std::move(user_display_name)),
      counter, std::move(*fido_private_key));
}

void VirtualAuthenticator::ClearRegistrations() {
  device::VirtualFidoDevice::State::RegistrationsMap erased;
  state_->registrations.swap(erased);
  for (const auto& registration : erased) {
    state_->NotifyCredentialDeleted(registration.first);
  }
}

bool VirtualAuthenticator::RemoveRegistration(
    const std::vector<uint8_t>& key_handle) {
  bool removed = state_->registrations.erase(key_handle) != 0;
  if (removed) {
    state_->NotifyCredentialDeleted(key_handle);
  }
  return removed;
}

void VirtualAuthenticator::UpdateUserDetails(std::string_view relying_party_id,
                                             base::span<const uint8_t> user_id,
                                             std::string_view name,
                                             std::string_view display_name) {
  for (auto& registration : state_->registrations) {
    if (registration.second.user && registration.second.rp &&
        registration.second.rp->id == relying_party_id &&
        registration.second.user->id == user_id) {
      registration.second.user->name = name;
      registration.second.user->display_name = display_name;
      state_->NotifyCredentialUpdated(
          std::make_pair(registration.first, &registration.second));
    }
  }
}

void VirtualAuthenticator::SetUserPresence(bool is_user_present) {
  is_user_present_ = is_user_present;
  state_->simulate_press_callback = base::BindRepeating(
      [](bool is_user_present, device::VirtualFidoDevice* device) {
        return is_user_present;
      },
      is_user_present);
}

std::unique_ptr<device::VirtualFidoDevice>
VirtualAuthenticator::ConstructDevice() {
  switch (protocol_) {
    case device::ProtocolVersion::kU2f:
      return std::make_unique<device::VirtualU2fDevice>(state_);
    case device::ProtocolVersion::kCtap2: {
      device::VirtualCtap2Device::Config config;
      switch (ctap2_version_) {
        case device::Ctap2Version::kCtap2_0:
          config.ctap2_versions = {std::begin(device::kCtap2Versions2_0),
                                   std::end(device::kCtap2Versions2_0)};
          break;
        case device::Ctap2Version::kCtap2_1:
          config.ctap2_versions = {std::begin(device::kCtap2Versions2_1),
                                   std::end(device::kCtap2Versions2_1)};
          break;
      }
      config.resident_key_support = has_resident_key_;
      config.large_blob_support = has_large_blob_;
      config.cred_protect_support = config.cred_blob_support = has_cred_blob_;
      config.min_pin_length_extension_support = has_min_pin_length_;
      if (has_prf_) {
        config.prf_support = true;
        // This is required when `prf_support` is set.
        config.internal_account_chooser = true;
      }

      if (
          // Writing a large blob requires obtaining a PinUvAuthToken with
          // permissions if the authenticator is protected by user verification.
          (has_large_blob_ && has_user_verification_) ||
          // PRF support always requires PIN support because the exchange is
          // encrypted.
          has_prf_) {
        config.pin_uv_auth_token_support = true;
      }
      config.internal_uv_support = has_user_verification_;
      config.is_platform_authenticator =
          attachment_ == device::AuthenticatorAttachment::kPlatform;
      config.user_verification_succeeds = is_user_verified_;
      config.advertised_algorithms = {
          device::CoseAlgorithmIdentifier::kEdDSA,
          device::CoseAlgorithmIdentifier::kEs256,
          device::CoseAlgorithmIdentifier::kRs256,
      };
      return std::make_unique<device::VirtualCtap2Device>(state_, config);
    }
    default:
      NOTREACHED();
  }
}

void VirtualAuthenticator::AddObserver(Observer* observer) {
  observers_.AddObserver(observer);
}

void VirtualAuthenticator::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

bool VirtualAuthenticator::HasObserversForTest() {
  return !observers_.empty();
}

void VirtualAuthenticator::SetBackupEligibility(
    const std::vector<uint8_t>& key_handle,
    bool backup_eligibility) {
  state_->registrations.at(key_handle).backup_eligible = backup_eligibility;
}

void VirtualAuthenticator::SetBackupState(
    const std::vector<uint8_t>& key_handle,
    bool backup_state) {
  state_->registrations.at(key_handle).backup_state = backup_state;
}

void VirtualAuthenticator::GetLargeBlob(const std::vector<uint8_t>& key_handle,
                                        GetLargeBlobCallback callback) {
  auto registration = state_->registrations.find(key_handle);
  if (registration == state_->registrations.end()) {
    std::move(callback).Run(std::nullopt);
    return;
  }
  std::optional<device::LargeBlob> blob =
      state_->GetLargeBlob(registration->second);
  if (!blob) {
    std::move(callback).Run(std::nullopt);
    return;
  }
  data_decoder_.Inflate(
      std::move(blob->compressed_data), blob->original_size,
      base::BindOnce(&VirtualAuthenticator::OnLargeBlobUncompressed,
                     weak_factory_.GetWeakPtr(), std::move(callback)));
}

void VirtualAuthenticator::SetLargeBlob(const std::vector<uint8_t>& key_handle,
                                        const std::vector<uint8_t>& blob,
                                        SetLargeBlobCallback callback) {
  data_decoder_.Deflate(
      blob, base::BindOnce(&VirtualAuthenticator::OnLargeBlobCompressed,
                           weak_factory_.GetWeakPtr(), key_handle, blob.size(),
                           std::move(callback)));
}

void VirtualAuthenticator::OnCredentialCreated(
    const device::VirtualFidoDevice::Credential& credential) {
  for (Observer& observer : observers_) {
    observer.OnCredentialCreated(this, credential);
  }
}

void VirtualAuthenticator::OnCredentialDeleted(
    base::span<const uint8_t> credential_id) {
  for (Observer& observer : observers_) {
    observer.OnCredentialDeleted(this, credential_id);
  }
}

void VirtualAuthenticator::OnCredentialUpdated(
    const device::VirtualFidoDevice::Credential& credential) {
  for (Observer& observer : observers_) {
    observer.OnCredentialUpdated(this, credential);
  }
}

void VirtualAuthenticator::OnAssertion(
    const device::VirtualFidoDevice::Credential& credential) {
  for (Observer& observer : observers_) {
    observer.OnAssertion(this, credential);
  }
}

void VirtualAuthenticator::OnLargeBlobUncompressed(
    GetLargeBlobCallback callback,
    base::expected<mojo_base::BigBuffer, std::string> result) {
  std::optional<mojo_base::BigBuffer> value;
  if (result.has_value())
    value = std::move(*result);

  std::move(callback).Run(device::fido_parsing_utils::MaterializeOrNull(value));
}

void VirtualAuthenticator::OnLargeBlobCompressed(
    base::span<const uint8_t> key_handle,
    uint64_t original_size,
    SetLargeBlobCallback callback,
    base::expected<mojo_base::BigBuffer, std::string> result) {
  auto registration = state_->registrations.find(key_handle);
  if (registration == state_->registrations.end()) {
    std::move(callback).Run(false);
    return;
  }
  if (result.has_value()) {
    state_->InjectLargeBlob(
        &registration->second,
        device::LargeBlob(device::fido_parsing_utils::Materialize(*result),
                          original_size));
  }
  std::move(callback).Run(result.has_value());
}

}  // namespace content
