// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/autofill/core/browser/payments/credit_card_fido_authenticator.h"

#include <string>
#include <utility>
#include <vector>

#include "base/base64.h"
#include "base/containers/flat_set.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/payments/fido_authentication_strike_database.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h"
#include "third_party/blink/public/mojom/webauthn/internal_authenticator.mojom.h"
#include "url/gurl.h"

namespace autofill {

namespace {
// Default timeout for user to respond to WebAuthn prompt.
constexpr int kWebAuthnTimeoutMs = 3 * 60 * 1000;  // 3 minutes
constexpr char kGooglePaymentsRpid[] = "google.com";
constexpr char kGooglePaymentsRpName[] = "Google Payments";

std::vector<uint8_t> Base64ToBytes(std::string base64) {
  std::string bytes;
  bool did_succeed = base::Base64Decode(base::StringPiece(base64), &bytes);
  if (did_succeed) {
    return std::vector<uint8_t>(bytes.begin(), bytes.end());
  }
  return std::vector<uint8_t>{};
}

base::Value BytesToBase64(const std::vector<uint8_t> bytes) {
  std::string base64;
  base::Base64Encode(std::string(bytes.begin(), bytes.end()), &base64);
  return base::Value(std::move(base64));
}
}  // namespace

CreditCardFIDOAuthenticator::CreditCardFIDOAuthenticator(AutofillDriver* driver,
                                                         AutofillClient* client)
    : autofill_driver_(driver),
      autofill_client_(client),
      payments_client_(client->GetPaymentsClient()),
      user_is_verifiable_callback_received_(
          base::WaitableEvent::ResetPolicy::AUTOMATIC,
          base::WaitableEvent::InitialState::NOT_SIGNALED) {}

CreditCardFIDOAuthenticator::~CreditCardFIDOAuthenticator() {}

void CreditCardFIDOAuthenticator::Authenticate(
    const CreditCard* card,
    base::WeakPtr<Requester> requester,
    base::TimeTicks form_parsed_timestamp,
    base::Value request_options) {
  card_ = card;
  requester_ = requester;
  form_parsed_timestamp_ = form_parsed_timestamp;

  if (card_ && IsValidRequestOptions(request_options.Clone())) {
    current_flow_ = AUTHENTICATION_FLOW;
    GetAssertion(ParseRequestOptions(std::move(request_options)));
  } else {
    requester_->OnFIDOAuthenticationComplete(/*did_succeed=*/false);
  }
}

void CreditCardFIDOAuthenticator::Register(std::string card_authorization_token,
                                           base::Value creation_options) {
  // If |creation_options| is set, then must enroll a new credential. Otherwise
  // directly send request to payments for opting in.
  card_authorization_token_ = card_authorization_token;
  if (creation_options.is_dict()) {
    if (IsValidCreationOptions(creation_options)) {
      current_flow_ = OPT_IN_WITH_CHALLENGE_FLOW;
      MakeCredential(ParseCreationOptions(creation_options));
    }
  } else {
    current_flow_ = OPT_IN_FETCH_CHALLENGE_FLOW;
    OptChange();
  }
}

void CreditCardFIDOAuthenticator::Authorize(
    std::string card_authorization_token,
    base::Value request_options) {
  card_authorization_token_ = card_authorization_token;
  if (IsValidRequestOptions(request_options)) {
    // If user is already opted-in, then a new card is trying to be
    // authorized. Otherwise, a user with a credential on file is trying to
    // opt-in.
    current_flow_ = IsUserOptedIn() ? FOLLOWUP_AFTER_CVC_AUTH_FLOW
                                    : OPT_IN_WITH_CHALLENGE_FLOW;
    GetAssertion(ParseRequestOptions(std::move(request_options)));
  }
}

void CreditCardFIDOAuthenticator::OptOut() {
  current_flow_ = OPT_OUT_FLOW;
  card_authorization_token_ = std::string();
  OptChange();
}

void CreditCardFIDOAuthenticator::IsUserVerifiable(
    base::OnceCallback<void(bool)> callback) {
  if (base::FeatureList::IsEnabled(
          features::kAutofillCreditCardAuthentication)) {
    if (!authenticator_.is_bound()) {
      autofill_driver_->ConnectToAuthenticator(
          authenticator_.BindNewPipeAndPassReceiver());
    }
    authenticator_->IsUserVerifyingPlatformAuthenticatorAvailable(
        std::move(callback));
  } else {
    std::move(callback).Run(false);
  }
}

bool CreditCardFIDOAuthenticator::IsUserOptedIn() {
  return base::FeatureList::IsEnabled(
             features::kAutofillCreditCardAuthentication) &&
         ::autofill::prefs::IsCreditCardFIDOAuthEnabled(
             autofill_client_->GetPrefs());
}

void CreditCardFIDOAuthenticator::SyncUserOptIn(
    AutofillClient::UnmaskDetails& unmask_details) {
  bool is_user_opted_in = IsUserOptedIn();

  // If payments is offering to opt-in, then that means user is not opted in.
  if (unmask_details.offer_fido_opt_in) {
    is_user_opted_in = false;
  }

  // If payments is requesting a FIDO auth, then that means user is opted in.
  if (unmask_details.unmask_auth_method ==
      AutofillClient::UnmaskAuthMethod::FIDO) {
    is_user_opted_in = true;
  }

  // Update pref setting if needed.
  ::autofill::prefs::SetCreditCardFIDOAuthEnabled(autofill_client_->GetPrefs(),
                                                  is_user_opted_in);
}

void CreditCardFIDOAuthenticator::CancelVerification() {
  current_flow_ = NONE_FLOW;
  // Full card request may not exist when this function is called. The full card
  // request is created in OnDidGetAssertion() but the flow can be cancelled
  // before than.
  if (full_card_request_)
    full_card_request_->OnFIDOVerificationCancelled();
}

#if !defined(OS_ANDROID)
void CreditCardFIDOAuthenticator::OnWebauthnOfferDialogRequested(
    std::string card_authorization_token) {
  card_authorization_token_ = card_authorization_token;
  AutofillMetrics::LogWebauthnOptInPromoShown(
      /*is_checkout_flow=*/!card_authorization_token_.empty());
}

void CreditCardFIDOAuthenticator::OnWebauthnOfferDialogUserResponse(
    bool did_accept) {
  if (did_accept) {
    // Wait until GetAssertion()/MakeCredential() to log user acceptance, since
    // user still has the option to cancel the dialog while the challenge is
    // being fetched.
    Register(card_authorization_token_);
  } else {
    // If user declined, log user decision. User may have initially accepted the
    // dialog, but then chose to cancel while the challenge was being fetched.
    AutofillMetrics::LogWebauthnOptInPromoUserDecision(
        /*is_checkout_flow=*/!card_authorization_token_.empty(),
        current_flow_ == OPT_IN_FETCH_CHALLENGE_FLOW
            ? AutofillMetrics::WebauthnOptInPromoUserDecisionMetric::
                  kDeclinedAfterAccepting
            : AutofillMetrics::WebauthnOptInPromoUserDecisionMetric::
                  kDeclinedImmediately);
    payments_client_->CancelRequest();
    card_authorization_token_ = std::string();
    current_flow_ = NONE_FLOW;
    GetOrCreateFidoAuthenticationStrikeDatabase()->AddStrikes(
        FidoAuthenticationStrikeDatabase::kStrikesToAddWhenOptInOfferDeclined);
    ::autofill::prefs::SetCreditCardFIDOAuthEnabled(
        autofill_client_->GetPrefs(), false);
  }
}
#endif

FidoAuthenticationStrikeDatabase*
CreditCardFIDOAuthenticator::GetOrCreateFidoAuthenticationStrikeDatabase() {
  if (!fido_authentication_strike_database_) {
    fido_authentication_strike_database_ =
        std::make_unique<FidoAuthenticationStrikeDatabase>(
            FidoAuthenticationStrikeDatabase(
                autofill_client_->GetStrikeDatabase()));
  }
  return fido_authentication_strike_database_.get();
}

void CreditCardFIDOAuthenticator::GetAssertion(
    PublicKeyCredentialRequestOptionsPtr request_options) {
  if (!authenticator_.is_bound()) {
    autofill_driver_->ConnectToAuthenticator(
        authenticator_.BindNewPipeAndPassReceiver());
  }
#if !defined(OS_ANDROID)
  // On desktop, during an opt-in flow, close the WebAuthn offer dialog and get
  // ready to show the OS level authentication dialog. If dialog is already
  // closed, then the offer was declined during the fetching challenge process,
  // and thus returned early.
  if (current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW) {
    if (autofill_client_->CloseWebauthnDialog()) {
      // Now that the dialog has closed and will proceed to a WebAuthn prompt,
      // the user must have accepted the dialog without cancelling.
      AutofillMetrics::LogWebauthnOptInPromoUserDecision(
          /*is_checkout_flow=*/!card_authorization_token_.empty(),
          AutofillMetrics::WebauthnOptInPromoUserDecisionMetric::kAccepted);
    } else {
      current_flow_ = NONE_FLOW;
      return;
    }
  }
#endif
  authenticator_->GetAssertion(
      std::move(request_options),
      base::BindOnce(&CreditCardFIDOAuthenticator::OnDidGetAssertion,
                     weak_ptr_factory_.GetWeakPtr()));
}

void CreditCardFIDOAuthenticator::MakeCredential(
    PublicKeyCredentialCreationOptionsPtr creation_options) {
  if (!authenticator_.is_bound()) {
    autofill_driver_->ConnectToAuthenticator(
        authenticator_.BindNewPipeAndPassReceiver());
  }
#if !defined(OS_ANDROID)
  // On desktop, close the WebAuthn offer dialog and get ready to show the OS
  // level authentication dialog. If dialog is already closed, then the offer
  // was declined during the fetching challenge process, and thus returned
  // early.
  if (autofill_client_->CloseWebauthnDialog()) {
    // Now that the dialog has closed and will proceed to a WebAuthn prompt,
    // the user must have accepted the dialog without cancelling.
    AutofillMetrics::LogWebauthnOptInPromoUserDecision(
        /*is_checkout_flow=*/!card_authorization_token_.empty(),
        AutofillMetrics::WebauthnOptInPromoUserDecisionMetric::kAccepted);
  } else {
    current_flow_ = NONE_FLOW;
    return;
  }
#endif
  authenticator_->MakeCredential(
      std::move(creation_options),
      base::BindOnce(&CreditCardFIDOAuthenticator::OnDidMakeCredential,
                     weak_ptr_factory_.GetWeakPtr()));
}

void CreditCardFIDOAuthenticator::OptChange(
    base::Value authenticator_response) {
  payments::PaymentsClient::OptChangeRequestDetails request_details;
  request_details.app_locale =
      autofill_client_->GetPersonalDataManager()->app_locale();

  switch (current_flow_) {
    case OPT_IN_WITH_CHALLENGE_FLOW:
    case OPT_IN_FETCH_CHALLENGE_FLOW:
      request_details.reason =
          payments::PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH;
      break;
    case OPT_OUT_FLOW:
      request_details.reason =
          payments::PaymentsClient::OptChangeRequestDetails::DISABLE_FIDO_AUTH;
      break;
    case FOLLOWUP_AFTER_CVC_AUTH_FLOW:
      request_details.reason = payments::PaymentsClient::
          OptChangeRequestDetails::ADD_CARD_FOR_FIDO_AUTH;
      break;
    default:
      NOTREACHED();
      break;
  }

  // If |authenticator_response| is set, that means the user just signed a
  // challenge. In which case, if |card_authorization_token_| is not empty, then
  // that will be required to bind a previous CVC check with this signature.
  // This will opt the user in and authorize the card corresponding to
  // |card_authorization_token_|.
  // If |authenticator_response| is not set, that means the user was fetching a
  // challenge, in which case |card_authorization_token_| will be required for
  // the subsequent OptChange call.
  AutofillMetrics::WebauthnOptInParameters opt_change_metric;
  bool is_checkout_flow = !card_authorization_token_.empty();
  if (authenticator_response.is_dict()) {
    request_details.fido_authenticator_response =
        std::move(authenticator_response);
    opt_change_metric =
        request_details.fido_authenticator_response.FindKey(
            "fido_assertion_info")
            ? AutofillMetrics::WebauthnOptInParameters::kWithRequestChallenge
            : AutofillMetrics::WebauthnOptInParameters::kWithCreationChallenge;
    if (!card_authorization_token_.empty()) {
      request_details.card_authorization_token = card_authorization_token_;
      card_authorization_token_ = std::string();
    }
  } else {
    opt_change_metric =
        AutofillMetrics::WebauthnOptInParameters::kFetchingChallenge;
  }
  payments_client_->OptChange(
      request_details,
      base::BindOnce(&CreditCardFIDOAuthenticator::OnDidGetOptChangeResult,
                     weak_ptr_factory_.GetWeakPtr()));

  // Logging call if user was attempting to change their opt-in state.
  if (current_flow_ != FOLLOWUP_AFTER_CVC_AUTH_FLOW) {
    bool request_to_opt_in = (current_flow_ != OPT_OUT_FLOW);
    AutofillMetrics::LogWebauthnOptChangeCalled(
        request_to_opt_in, is_checkout_flow, opt_change_metric);
  }
}

void CreditCardFIDOAuthenticator::OnDidGetAssertion(
    AuthenticatorStatus status,
    GetAssertionAuthenticatorResponsePtr assertion_response) {
  LogWebauthnResult(status);

  // End the flow if there was an authentication error.
  if (status != AuthenticatorStatus::SUCCESS) {
    // Report failure to |requester_| if card unmasking was requested.
    if (current_flow_ == AUTHENTICATION_FLOW)
      requester_->OnFIDOAuthenticationComplete(/*did_succeed=*/false);

    // Treat failure to perform user verification as a strong signal not to
    // offer opt-in in the future.
    if (current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW) {
      GetOrCreateFidoAuthenticationStrikeDatabase()->AddStrikes(
          FidoAuthenticationStrikeDatabase::
              kStrikesToAddWhenUserVerificationFailsOnOptInAttempt);
    }

    current_flow_ = NONE_FLOW;
    return;
  }

  if (current_flow_ == AUTHENTICATION_FLOW) {
    base::Value response =
        ParseAssertionResponse(std::move(assertion_response));
    full_card_request_.reset(new payments::FullCardRequest(
        autofill_client_, autofill_client_->GetPaymentsClient(),
        autofill_client_->GetPersonalDataManager(), form_parsed_timestamp_));
    full_card_request_->GetFullCardViaFIDO(
        *card_, AutofillClient::UNMASK_FOR_AUTOFILL,
        weak_ptr_factory_.GetWeakPtr(), std::move(response));
  } else {
    DCHECK(current_flow_ == FOLLOWUP_AFTER_CVC_AUTH_FLOW ||
           current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW);
    base::Value response = base::Value(base::Value::Type::DICTIONARY);
    response.SetKey("fido_assertion_info",
                    ParseAssertionResponse(std::move(assertion_response)));
    OptChange(std::move(response));
  }
}

void CreditCardFIDOAuthenticator::OnDidMakeCredential(
    AuthenticatorStatus status,
    MakeCredentialAuthenticatorResponsePtr attestation_response) {
  LogWebauthnResult(status);

  // End the flow if there was an authentication error.
  if (status != AuthenticatorStatus::SUCCESS) {
    // Treat failure to perform user verification as a strong signal not to
    // offer opt-in in the future.
    if (current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW) {
      GetOrCreateFidoAuthenticationStrikeDatabase()->AddStrikes(
          FidoAuthenticationStrikeDatabase::
              kStrikesToAddWhenUserVerificationFailsOnOptInAttempt);
    }

    current_flow_ = NONE_FLOW;
    return;
  }

  OptChange(ParseAttestationResponse(std::move(attestation_response)));
}

void CreditCardFIDOAuthenticator::OnDidGetOptChangeResult(
    AutofillClient::PaymentsRpcResult result,
    payments::PaymentsClient::OptChangeResponseDetails& response) {
  DCHECK(current_flow_ == OPT_IN_FETCH_CHALLENGE_FLOW ||
         current_flow_ == OPT_OUT_FLOW ||
         current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW ||
         current_flow_ == FOLLOWUP_AFTER_CVC_AUTH_FLOW);

  // Update user preference to keep in sync with server.
  ::autofill::prefs::SetCreditCardFIDOAuthEnabled(
      autofill_client_->GetPrefs(),
      response.user_is_opted_in.value_or(IsUserOptedIn()));

  // End the flow if the server responded with an error.
  if (result != AutofillClient::PaymentsRpcResult::SUCCESS) {
#if !defined(OS_ANDROID)
    if (current_flow_ == OPT_IN_FETCH_CHALLENGE_FLOW)
      autofill_client_->UpdateWebauthnOfferDialogWithError();
#endif
    current_flow_ = NONE_FLOW;
    return;
  }

  // If response contains |creation_options| or |request_options| and the last
  // opt-in attempt did not include a challenge, then invoke WebAuthn
  // registration/verification prompt. Otherwise end the flow.
  if (current_flow_ == OPT_IN_FETCH_CHALLENGE_FLOW) {
    if (response.fido_creation_options.has_value()) {
      Register(card_authorization_token_,
               std::move(response.fido_creation_options.value()));
    } else if (response.fido_request_options.has_value()) {
      Authorize(card_authorization_token_,
                std::move(response.fido_request_options.value()));
    }
  } else {
    current_flow_ = NONE_FLOW;
  }
}

void CreditCardFIDOAuthenticator::OnFullCardRequestSucceeded(
    const payments::FullCardRequest& full_card_request,
    const CreditCard& card,
    const base::string16& cvc) {
  DCHECK_EQ(AUTHENTICATION_FLOW, current_flow_);
  current_flow_ = NONE_FLOW;
  requester_->OnFIDOAuthenticationComplete(/*did_succeed=*/true, &card);
}

void CreditCardFIDOAuthenticator::OnFullCardRequestFailed() {
  DCHECK_EQ(AUTHENTICATION_FLOW, current_flow_);
  current_flow_ = NONE_FLOW;
  requester_->OnFIDOAuthenticationComplete(/*did_succeed=*/false);
}

PublicKeyCredentialRequestOptionsPtr
CreditCardFIDOAuthenticator::ParseRequestOptions(
    const base::Value& request_options) {
  auto options = PublicKeyCredentialRequestOptions::New();

  const auto* rpid = request_options.FindStringKey("relying_party_id");
  options->relying_party_id = rpid ? *rpid : std::string(kGooglePaymentsRpid);

  const auto* challenge = request_options.FindStringKey("challenge");
  DCHECK(challenge);
  options->challenge = Base64ToBytes(*challenge);

  const auto* timeout = request_options.FindKeyOfType(
      "timeout_millis", base::Value::Type::INTEGER);
  options->adjusted_timeout = base::TimeDelta::FromMilliseconds(
      timeout ? timeout->GetInt() : kWebAuthnTimeoutMs);

  options->user_verification = UserVerificationRequirement::kRequired;

  const auto* key_info_list =
      request_options.FindKeyOfType("key_info", base::Value::Type::LIST);
  DCHECK(key_info_list);
  for (const base::Value& key_info : key_info_list->GetList()) {
    options->allow_credentials.push_back(ParseCredentialDescriptor(key_info));
  }

  return options;
}

PublicKeyCredentialCreationOptionsPtr
CreditCardFIDOAuthenticator::ParseCreationOptions(
    const base::Value& creation_options) {
  auto options = PublicKeyCredentialCreationOptions::New();

  const auto* rpid = creation_options.FindStringKey("relying_party_id");
  options->relying_party.id = rpid ? *rpid : kGooglePaymentsRpid;

  const auto* relying_party_name =
      creation_options.FindStringKey("relying_party_name");
  options->relying_party.name =
      relying_party_name ? *relying_party_name : kGooglePaymentsRpName;

  const auto* icon_url = creation_options.FindStringKey("icon_url");
  if (icon_url)
    options->relying_party.icon_url = GURL(*icon_url);

  const std::string gaia =
      autofill_client_->GetIdentityManager()->GetPrimaryAccountInfo().gaia;
  options->user.id = std::vector<uint8_t>(gaia.begin(), gaia.end());
  options->user.name =
      autofill_client_->GetIdentityManager()->GetPrimaryAccountInfo().email;

  base::Optional<AccountInfo> account_info =
      autofill_client_->GetIdentityManager()
          ->FindExtendedAccountInfoForAccountWithRefreshToken(
              autofill_client_->GetPersonalDataManager()
                  ->GetAccountInfoForPaymentsServer());
  if (account_info.has_value()) {
    options->user.display_name = account_info.value().given_name;
    options->user.icon_url = GURL(account_info.value().picture_url);
  } else {
    options->user.display_name = "";
  }

  const auto* challenge = creation_options.FindStringKey("challenge");
  DCHECK(challenge);
  options->challenge = Base64ToBytes(*challenge);

  const auto* identifier_list = creation_options.FindKeyOfType(
      "algorithm_identifier", base::Value::Type::LIST);
  if (identifier_list) {
    for (const base::Value& algorithm_identifier : identifier_list->GetList()) {
      device::PublicKeyCredentialParams::CredentialInfo parameter;
      parameter.type = device::CredentialType::kPublicKey;
      parameter.algorithm = algorithm_identifier.GetInt();
      options->public_key_parameters.push_back(parameter);
    }
  }

  const auto* timeout = creation_options.FindKeyOfType(
      "timeout_millis", base::Value::Type::INTEGER);
  options->adjusted_timeout = base::TimeDelta::FromMilliseconds(
      timeout ? timeout->GetInt() : kWebAuthnTimeoutMs);

  const auto* attestation =
      creation_options.FindStringKey("attestation_conveyance_preference");
  if (!attestation || base::EqualsCaseInsensitiveASCII(*attestation, "NONE")) {
    options->attestation = AttestationConveyancePreference::kNone;
  } else if (base::EqualsCaseInsensitiveASCII(*attestation, "INDIRECT")) {
    options->attestation = AttestationConveyancePreference::kIndirect;
  } else if (base::EqualsCaseInsensitiveASCII(*attestation, "DIRECT")) {
    options->attestation = AttestationConveyancePreference::kDirect;
  } else {
    NOTREACHED();
  }

  // Only allow user-verifying platform authenticators.
  options->authenticator_selection = AuthenticatorSelectionCriteria(
      AuthenticatorAttachment::kPlatform, /*require_resident_key=*/false,
      UserVerificationRequirement::kRequired);

  // List of keys that Payments already knows about, and so should not make a
  // new credential.
  const auto* excluded_keys_list =
      creation_options.FindKeyOfType("key_info", base::Value::Type::LIST);
  if (excluded_keys_list) {
    for (const base::Value& key_info : excluded_keys_list->GetList()) {
      options->exclude_credentials.push_back(
          ParseCredentialDescriptor(key_info));
    }
  }

  return options;
}

PublicKeyCredentialDescriptor
CreditCardFIDOAuthenticator::ParseCredentialDescriptor(
    const base::Value& key_info) {
  std::vector<uint8_t> credential_id;
  const auto* id = key_info.FindStringKey("credential_id");
  DCHECK(id);
  credential_id = Base64ToBytes(*id);

  base::flat_set<FidoTransportProtocol> authenticator_transports;
  const auto* transports = key_info.FindKeyOfType(
      "authenticator_transport_support", base::Value::Type::LIST);
  if (transports && !transports->GetList().empty()) {
    for (const base::Value& transport_type : transports->GetList()) {
      base::Optional<FidoTransportProtocol> protocol =
          device::ConvertToFidoTransportProtocol(
              base::ToLowerASCII(transport_type.GetString()));
      if (protocol.has_value())
        authenticator_transports.insert(*protocol);
    }
  }

  return PublicKeyCredentialDescriptor(CredentialType::kPublicKey,
                                       credential_id, authenticator_transports);
}

base::Value CreditCardFIDOAuthenticator::ParseAssertionResponse(
    GetAssertionAuthenticatorResponsePtr assertion_response) {
  base::Value response = base::Value(base::Value::Type::DICTIONARY);
  response.SetKey("credential_id",
                  BytesToBase64(assertion_response->info->raw_id));
  response.SetKey("authenticator_data",
                  BytesToBase64(assertion_response->authenticator_data));
  response.SetKey("client_data",
                  BytesToBase64(assertion_response->info->client_data_json));
  response.SetKey("signature", BytesToBase64(assertion_response->signature));
  return response;
}

base::Value CreditCardFIDOAuthenticator::ParseAttestationResponse(
    MakeCredentialAuthenticatorResponsePtr attestation_response) {
  base::Value response = base::Value(base::Value::Type::DICTIONARY);

  base::Value fido_attestation_info =
      base::Value(base::Value::Type::DICTIONARY);
  fido_attestation_info.SetKey(
      "client_data",
      BytesToBase64(attestation_response->info->client_data_json));
  fido_attestation_info.SetKey(
      "attestation_object",
      BytesToBase64(attestation_response->attestation_object));

  base::Value authenticator_transport_list =
      base::Value(base::Value::Type::LIST);
  for (FidoTransportProtocol protocol : attestation_response->transports) {
    authenticator_transport_list.Append(
        base::Value(base::ToUpperASCII(device::ToString(protocol))));
  }

  response.SetKey("fido_attestation_info", std::move(fido_attestation_info));
  response.SetKey("authenticator_transport",
                  std::move(authenticator_transport_list));

  return response;
}

bool CreditCardFIDOAuthenticator::IsValidRequestOptions(
    const base::Value& request_options) {
  if (!request_options.is_dict() || request_options.DictEmpty() ||
      !request_options.FindStringKey("challenge") ||
      !request_options.FindKeyOfType("key_info", base::Value::Type::LIST)) {
    return false;
  }

  const auto* key_info_list =
      request_options.FindKeyOfType("key_info", base::Value::Type::LIST);

  if (key_info_list->GetList().empty())
    return false;

  for (const base::Value& key_info : key_info_list->GetList()) {
    if (!key_info.is_dict() || !key_info.FindStringKey("credential_id"))
      return false;
  }

  return true;
}

bool CreditCardFIDOAuthenticator::IsValidCreationOptions(
    const base::Value& creation_options) {
  return creation_options.is_dict() &&
         creation_options.FindStringKey("challenge");
}

void CreditCardFIDOAuthenticator::LogWebauthnResult(
    AuthenticatorStatus status) {
  AutofillMetrics::WebauthnFlowEvent event;
  switch (current_flow_) {
    case AUTHENTICATION_FLOW:
      event = AutofillMetrics::WebauthnFlowEvent::kImmediateAuthentication;
      break;
    case FOLLOWUP_AFTER_CVC_AUTH_FLOW:
      event = AutofillMetrics::WebauthnFlowEvent::kAuthenticationAfterCvc;
      break;
    case OPT_IN_WITH_CHALLENGE_FLOW:
      event = card_authorization_token_.empty()
                  ? AutofillMetrics::WebauthnFlowEvent::kSettingsPageOptIn
                  : AutofillMetrics::WebauthnFlowEvent::kCheckoutOptIn;
      break;
    default:
      NOTREACHED();
      return;
  }

  AutofillMetrics::WebauthnResultMetric metric;
  switch (status) {
    case AuthenticatorStatus::SUCCESS:
      metric = AutofillMetrics::WebauthnResultMetric::kSuccess;
      break;
    case AuthenticatorStatus::NOT_ALLOWED_ERROR:
      metric = AutofillMetrics::WebauthnResultMetric::kNotAllowedError;
      break;
    default:
      metric = AutofillMetrics::WebauthnResultMetric::kOtherError;
      break;
  }
  AutofillMetrics::LogWebauthnResult(event, metric);
}
}  // namespace autofill
