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

#include "chrome/browser/extensions/api/autofill_private/autofill_private_api.h"

#include <stddef.h>

#include <algorithm>
#include <optional>
#include <string>
#include <string_view>
#include <utility>

#include "base/containers/to_vector.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/types/cxx23_to_underlying.h"
#include "base/types/optional_ref.h"
#include "base/uuid.h"
#include "base/values.h"
#include "chrome/browser/autofill/autofill_entity_data_manager_factory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/autofill_private/autofill_ai_util.h"
#include "chrome/browser/extensions/api/autofill_private/autofill_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/user_education/browser_user_education_interface.h"
#include "chrome/common/extensions/api/autofill_private.h"
#include "components/autofill/content/browser/content_autofill_client.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/core/browser/data_manager/addresses/address_data_manager.h"
#include "components/autofill/core/browser/data_manager/autofill_ai/entity_data_manager.h"
#include "components/autofill/core/browser/data_manager/payments/payments_data_manager.h"
#include "components/autofill/core/browser/data_manager/personal_data_manager.h"
#include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
#include "components/autofill/core/browser/data_model/addresses/autofill_structured_address_constants.h"
#include "components/autofill/core/browser/data_model/addresses/autofill_structured_address_utils.h"
#include "components/autofill/core/browser/data_model/autofill_ai/entity_instance.h"
#include "components/autofill/core/browser/data_model/autofill_ai/entity_type.h"
#include "components/autofill/core/browser/data_model/autofill_ai/entity_type_names.h"
#include "components/autofill/core/browser/data_model/payments/credit_card.h"
#include "components/autofill/core/browser/data_model/payments/iban.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/foundations/browser_autofill_manager.h"
#include "components/autofill/core/browser/metrics/address_save_metrics.h"
#include "components/autofill/core/browser/metrics/payments/mandatory_reauth_metrics.h"
#include "components/autofill/core/browser/payments/credit_card_access_manager.h"
#include "components/autofill/core/browser/payments/mandatory_reauth_manager.h"
#include "components/autofill/core/browser/payments/payments_autofill_client.h"
#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
#include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
#include "components/autofill/core/browser/permissions/autofill_ai/autofill_ai_permission_utils.h"
#include "components/autofill/core/browser/studies/autofill_experiments.h"
#include "components/autofill/core/browser/ui/addresses/autofill_address_util.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/dense_set.h"
#include "components/feature_engagement/public/feature_constants.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/strings/grit/components_branded_strings.h"
#include "components/strings/grit/components_strings.h"
#include "components/wallet/core/browser/walletable_permission_utils.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_function_registry.h"
#include "extensions/browser/extensions_browser_client.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui_component.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/localization.h"
#include "third_party/re2/src/re2/re2.h"
#include "ui/base/l10n/l10n_util.h"

namespace {

namespace autofill_private = extensions::api::autofill_private;
namespace addressinput = i18n::addressinput;

using autofill::AddressDataManager;
using autofill::AutofillEntityDataManagerFactory;
using autofill::EntityDataManager;
using autofill::EntityInstance;
using autofill::EntityType;
using autofill::EntityTypeName;
using autofill::PaymentsDataManager;
using autofill::autofill_metrics::LogMandatoryReauthOptInOrOutUpdateEvent;
using autofill::autofill_metrics::LogMandatoryReauthSettingsPageEditCardEvent;
using autofill::autofill_metrics::MandatoryReauthAuthenticationFlowEvent;
using autofill::autofill_metrics::MandatoryReauthOptInOrOutSource;

static const char kSettingsOrigin[] = "Chrome settings";
static const char kErrorCardDataUnavailable[] = "Credit card data unavailable";
static const char kErrorDataUnavailable[] = "Autofill data unavailable.";
static const char kErrorAutofillAiUnavailable[] =
    "Autofill AI data unavailable.";
static const char kErrorAutofillAiInvalidData[] =
    "The provided Autofill AI entity/attribute is invalid.";
static const char kErrorAutofillAiTypeNameOutOfBounds[] =
    "The provided Autofill AI entity/attribute type name is out of bounds.";
static const char kErrorAutofillAiEntityInstanceNotFound[] =
    "The provided Autofill AI entity instance cannot be found.";
static const char kErrorDeviceAuthUnavailable[] = "Device auth is unvailable";

// Constant to assign a user-verified verification status to the autofill
// profile.
constexpr auto kUserVerified = autofill::VerificationStatus::kUserVerified;

// Dictionary keys used for serializing AddressUiComponent. Those values
// are used as keys in JavaScript code and shouldn't be modified.
constexpr char kFieldTypeKey[] = "field";
constexpr char kFieldLengthKey[] = "isLongField";
constexpr char kFieldNameKey[] = "fieldName";
constexpr char kFieldRequired[] = "isRequired";

// Serializes the AddressUiComponent a map from string to base::Value().
base::Value::Dict AddressUiComponentAsValueMap(
    const autofill::AutofillAddressUIComponent& address_ui_component) {
  base::Value::Dict info;
  info.Set(kFieldNameKey, address_ui_component.name);
  info.Set(kFieldTypeKey, FieldTypeToStringView(address_ui_component.field));
  info.Set(kFieldLengthKey,
           address_ui_component.length_hint ==
               autofill::AutofillAddressUIComponent::HINT_LONG);
  info.Set(kFieldRequired, address_ui_component.is_required);
  return info;
}

bool HasNameSeparator(const std::string& name) {
  if (name.empty()) {
    return false;
  }
  return re2::RE2::PartialMatch(name, autofill::kCjkNameSeparatorsRe);
}

// Logs whether the alternative name in a new/updated profile contains a
// separator.
void RecordAlternativeNameSeparatorUsage(
    const autofill::AutofillProfile& profile,
    const autofill::AutofillProfile* existing_profile) {
  const std::u16string existing_alternative_name =
      existing_profile
          ? existing_profile->GetInfo(autofill::ALTERNATIVE_FULL_NAME,
                                      extensions::ExtensionsBrowserClient::Get()
                                          ->GetApplicationLocale())
          : std::u16string();

  const std::u16string saved_alternative_name = profile.GetInfo(
      autofill::ALTERNATIVE_FULL_NAME,
      extensions::ExtensionsBrowserClient::Get()->GetApplicationLocale());

  if (!saved_alternative_name.empty() &&
      saved_alternative_name != existing_alternative_name) {
    base::UmaHistogramBoolean(
        "Autofill.Settings.EditedAlternativeNameContainsASeparator",
        HasNameSeparator(base::UTF16ToUTF8(saved_alternative_name)));
  }
}

autofill::BrowserAutofillManager* GetBrowserAutofillManager(
    content::WebContents* web_contents) {
  if (!web_contents) {
    return nullptr;
  }
  autofill::ContentAutofillDriver* autofill_driver =
      autofill::ContentAutofillDriver::GetForRenderFrameHost(
          web_contents->GetPrimaryMainFrame());
  if (!autofill_driver)
    return nullptr;
  // This cast is safe, since `AutofillManager` is always a
  // `BrowserAutofillManager` apart from on WebView.
  return static_cast<autofill::BrowserAutofillManager*>(
      &autofill_driver->GetAutofillManager());
}

autofill::AutofillProfile CreateNewAutofillProfile(
    const autofill::AddressDataManager& adm,
    std::optional<std::string_view> country_code) {
  autofill::AutofillProfile::RecordType record_type =
      adm.IsEligibleForAddressAccountStorage()
          ? autofill::AutofillProfile::RecordType::kAccount
          : autofill::AutofillProfile::RecordType::kLocalOrSyncable;
  autofill::AddressCountryCode address_country_code =
      country_code.has_value()
          ? autofill::AddressCountryCode(std::string(*country_code))
          : autofill::i18n_model_definition::kLegacyHierarchyCountryCode;
  return autofill::AutofillProfile(record_type, address_country_code);
}

}  // namespace

namespace extensions {

autofill::AddressDataManager*
AutofillPrivateExtensionFunction::address_data_manager() {
  autofill::ContentAutofillClient* client = autofill_client();
  return client ? &client->GetPersonalDataManager().address_data_manager()
                : nullptr;
}

autofill::ContentAutofillClient*
AutofillPrivateExtensionFunction::autofill_client() {
  return autofill::ContentAutofillClient::FromWebContents(
      GetSenderWebContents());
}

autofill::PaymentsDataManager*
AutofillPrivateExtensionFunction::payments_data_manager() {
  autofill::ContentAutofillClient* client = autofill_client();
  return client ? &client->GetPersonalDataManager().payments_data_manager()
                : nullptr;
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetAccountInfoFunction

ExtensionFunction::ResponseAction AutofillPrivateGetAccountInfoFunction::Run() {
  AddressDataManager* adm = address_data_manager();
  if (!adm || !adm->has_initial_load_finished()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  std::optional<api::autofill_private::AccountInfo> account_info =
      autofill_util::GetAccountInfo(*adm);
  if (account_info.has_value()) {
    return RespondNow(
        ArgumentList(api::autofill_private::GetAccountInfo::Results::Create(
            account_info.value())));
  }

  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateSaveAddressFunction

ExtensionFunction::ResponseAction AutofillPrivateSaveAddressFunction::Run() {
  std::optional<api::autofill_private::SaveAddress::Params> parameters =
      api::autofill_private::SaveAddress::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);

  AddressDataManager* adm = address_data_manager();
  if (!adm || !adm->has_initial_load_finished()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  // If a profile guid is specified, get a copy of the profile identified by it.
  // Otherwise create a new one.
  api::autofill_private::AddressEntry* address = &parameters->address;
  std::string guid = address->guid ? *address->guid : "";
  const bool use_existing_profile = !guid.empty();
  const autofill::AutofillProfile* existing_profile = nullptr;
  if (use_existing_profile) {
    existing_profile = adm->GetProfileByGUID(guid);
    if (!existing_profile)
      return RespondNow(Error(kErrorDataUnavailable));
  }
  std::optional<std::string_view> country_code;
  if (auto it = std::find_if(
          address->fields.begin(), address->fields.end(),
          [](const auto& field) {
            return field.type ==
                   autofill_private::FieldType::kAddressHomeCountry;
          });
      it != address->fields.end()) {
    country_code = it->value;
  }
  autofill::AutofillProfile profile =
      existing_profile ? *existing_profile
                       : CreateNewAutofillProfile(*adm, country_code);

  for (const api::autofill_private::AddressField& field : address->fields) {
    std::u16string trimmed_value;
    base::TrimWhitespace(base::UTF8ToUTF16(field.value), base::TRIM_ALL,
                         &trimmed_value);
    // TODO(crbug.com/385727960): Investigate why we can't use
    // SetInfoWithVerificationStatus here.
    profile.SetRawInfoWithVerificationStatus(
        autofill::TypeNameToFieldType(autofill_private::ToString(field.type)),
        trimmed_value, kUserVerified);
  }
  profile.FinalizeAfterImport();

  RecordAlternativeNameSeparatorUsage(profile, existing_profile);

  if (address->language_code) {
    profile.set_language_code(*address->language_code);
  }

  if (use_existing_profile) {
    adm->UpdateProfile(profile);
  } else {
    adm->AddProfile(profile);
    autofill::autofill_metrics::LogManuallyAddedAddress(
        autofill::autofill_metrics::AutofillManuallyAddedAddressSurface::
            kSettings);
  }

  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateRemoveAddressFunction

ExtensionFunction::ResponseAction AutofillPrivateRemoveAddressFunction::Run() {
  std::optional<api::autofill_private::RemoveAddress::Params> parameters =
      api::autofill_private::RemoveAddress::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);
  AddressDataManager* adm = address_data_manager();
  if (!adm || !adm->has_initial_load_finished()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }
  adm->RemoveProfile(parameters->guid);
  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetCountryListFunction

ExtensionFunction::ResponseAction AutofillPrivateGetCountryListFunction::Run() {
  std::optional<api::autofill_private::GetCountryList::Params> parameters =
      api::autofill_private::GetCountryList::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);

  autofill_util::CountryEntryList country_list;
  if (parameters->for_account_storage) {
    AddressDataManager* adm = address_data_manager();
    if (!adm) {
      return RespondNow(Error(kErrorDataUnavailable));
    }

    // Return an empty list if data is not loaded.
    if (!adm->has_initial_load_finished()) {
      return RespondNow(
          ArgumentList(api::autofill_private::GetCountryList::Results::Create(
              country_list)));
    }
  }
  country_list = autofill_util::GenerateCountryList();
  return RespondNow(ArgumentList(
      api::autofill_private::GetCountryList::Results::Create(country_list)));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetAddressComponentsFunction

ExtensionFunction::ResponseAction
AutofillPrivateGetAddressComponentsFunction::Run() {
  std::optional<api::autofill_private::GetAddressComponents::Params>
      parameters =
          api::autofill_private::GetAddressComponents::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);

  std::vector<std::vector<autofill::AutofillAddressUIComponent>> lines;
  std::string language_code;

  autofill::GetAddressComponents(
      parameters->country_code,
      ExtensionsBrowserClient::Get()->GetApplicationLocale(),
      /*include_literals=*/false, &lines, &language_code);
  // Convert std::vector<std::vector<::i18n::addressinput::AddressUiComponent>>
  // to AddressComponents
  base::Value::Dict address_components;
  base::Value::List rows;

  for (auto& line : lines) {
    base::Value::List row_values;
    for (const autofill::AutofillAddressUIComponent& component : line) {
      row_values.Append(AddressUiComponentAsValueMap(component));
    }
    base::Value::Dict row;
    row.Set("row", std::move(row_values));
    rows.Append(std::move(row));
  }

  address_components.Set("components", std::move(rows));
  address_components.Set("languageCode", language_code);

  return RespondNow(WithArguments(std::move(address_components)));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetAddressListFunction

ExtensionFunction::ResponseAction AutofillPrivateGetAddressListFunction::Run() {
  AddressDataManager* adm = address_data_manager();
  if (!adm || !adm->has_initial_load_finished()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  autofill_util::AddressEntryList address_list =
      autofill_util::GenerateAddressList(*adm);
  return RespondNow(ArgumentList(
      api::autofill_private::GetAddressList::Results::Create(address_list)));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateSaveCreditCardFunction

ExtensionFunction::ResponseAction AutofillPrivateSaveCreditCardFunction::Run() {
  std::optional<api::autofill_private::SaveCreditCard::Params> parameters =
      api::autofill_private::SaveCreditCard::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);

  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  // If a card guid is specified, get a copy of the card identified by it.
  // Otherwise create a new one.
  api::autofill_private::CreditCardEntry* card = &parameters->card;
  std::string guid = card->guid ? *card->guid : "";
  const bool use_existing_card = !guid.empty();
  const autofill::CreditCard* existing_card = nullptr;
  if (use_existing_card) {
    existing_card = paydm->GetCreditCardByGUID(guid);
    if (!existing_card)
      return RespondNow(Error(kErrorDataUnavailable));
  }
  autofill::CreditCard credit_card =
      existing_card ? *existing_card
                    : autofill::CreditCard(
                          base::Uuid::GenerateRandomV4().AsLowercaseString(),
                          kSettingsOrigin);

  if (card->name) {
    credit_card.SetRawInfo(autofill::CREDIT_CARD_NAME_FULL,
                           base::UTF8ToUTF16(*card->name));
  }

  if (card->card_number) {
    credit_card.SetRawInfo(autofill::CREDIT_CARD_NUMBER,
                           base::UTF8ToUTF16(*card->card_number));
  }

  if (card->expiration_month) {
    credit_card.SetRawInfo(autofill::CREDIT_CARD_EXP_MONTH,
                           base::UTF8ToUTF16(*card->expiration_month));
  }

  if (card->expiration_year) {
    credit_card.SetRawInfo(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR,
                           base::UTF8ToUTF16(*card->expiration_year));
  }

  if (card->nickname) {
    credit_card.SetNickname(base::UTF8ToUTF16(*card->nickname));
  }

  if (card->cvc) {
    credit_card.set_cvc(base::UTF8ToUTF16(*card->cvc));
  }

  if (use_existing_card) {
    // Only updates when the card info changes.
    if (existing_card && existing_card->Compare(credit_card) == 0)
      return RespondNow(NoArguments());

    if (existing_card->cvc().empty()) {
      if (credit_card.cvc().empty()) {
        // Record when an existing card without CVC is edited and no CVC was
        // added.
        base::RecordAction(base::UserMetricsAction(
            "AutofillCreditCardsEditedAndCvcWasLeftBlank"));
      } else {
        // Record when an existing card without CVC is edited and CVC was added.
        base::RecordAction(
            base::UserMetricsAction("AutofillCreditCardsEditedAndCvcWasAdded"));
      }
    } else {
      if (credit_card.cvc().empty()) {
        // Record when an existing card with CVC is edited and CVC was removed.
        base::RecordAction(base::UserMetricsAction(
            "AutofillCreditCardsEditedAndCvcWasRemoved"));
      } else if (credit_card.cvc() != existing_card->cvc()) {
        // Record when an existing card with CVC is edited and CVC was updated.
        base::RecordAction(base::UserMetricsAction(
            "AutofillCreditCardsEditedAndCvcWasUpdated"));
      } else {
        // Record when an existing card with CVC is edited and CVC was
        // unchanged.
        base::RecordAction(base::UserMetricsAction(
            "AutofillCreditCardsEditedAndCvcWasUnchanged"));
      }
    }

    // Record when nickname is updated.
    if (credit_card.HasNonEmptyValidNickname() &&
        existing_card->nickname() != credit_card.nickname()) {
      base::RecordAction(
          base::UserMetricsAction("AutofillCreditCardsEditedWithNickname"));
    }

    paydm->UpdateCreditCard(credit_card);
    base::RecordAction(base::UserMetricsAction("AutofillCreditCardsEdited"));
  } else {
    int current_card_count = paydm->GetCreditCards().size();
    paydm->AddCreditCard(credit_card);

    base::RecordAction(base::UserMetricsAction("AutofillCreditCardsAdded"));

    base::UmaHistogramCounts100(
        "Autofill.PaymentMethods.SettingsPage."
        "StoredCreditCardCountBeforeCardAdded",
        current_card_count);
    base::UmaHistogramBoolean(
        "Autofill.PaymentMethodsSettingsPage.CardAddedWithoutExistingCards",
        current_card_count == 0);

    if (credit_card.HasNonEmptyValidNickname()) {
      base::RecordAction(
          base::UserMetricsAction("AutofillCreditCardsAddedWithNickname"));
    }
    if (!credit_card.cvc().empty()) {
      base::RecordAction(
          base::UserMetricsAction("AutofillCreditCardsAddedWithCvc"));
    }
  }
  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateRemovePaymentsEntityFunction

ExtensionFunction::ResponseAction
AutofillPrivateRemovePaymentsEntityFunction::Run() {
  std::optional<api::autofill_private::RemovePaymentsEntity::Params>
      parameters =
          api::autofill_private::RemovePaymentsEntity::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);

  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  if (paydm->GetIbanByGUID(parameters->guid)) {
    base::RecordAction(base::UserMetricsAction("AutofillIbanDeleted"));
  } else if (const autofill::CreditCard* credit_card =
                 paydm->GetCreditCardByGUID(parameters->guid)) {
    base::RecordAction(base::UserMetricsAction("AutofillCreditCardDeleted"));
    if (!credit_card->cvc().empty()) {
      base::RecordAction(
          base::UserMetricsAction("AutofillCreditCardDeletedAndHadCvc"));
    }
    if (credit_card->HasNonEmptyValidNickname()) {
      base::RecordAction(
          base::UserMetricsAction("AutofillCreditCardDeletedAndHadNickname"));
    }
  }

  paydm->RemoveByGUID(parameters->guid);
  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetCreditCardListFunction

ExtensionFunction::ResponseAction
AutofillPrivateGetCreditCardListFunction::Run() {
  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  autofill_util::CreditCardEntryList credit_card_list =
      autofill_util::GenerateCreditCardList(*paydm);
  return RespondNow(
      ArgumentList(api::autofill_private::GetCreditCardList::Results::Create(
          credit_card_list)));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateLogServerCardLinkClickedFunction

ExtensionFunction::ResponseAction
AutofillPrivateLogServerCardLinkClickedFunction::Run() {
  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  paydm->LogServerCardLinkClicked();
  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateLogServerIbanLinkClickedFunction

ExtensionFunction::ResponseAction
AutofillPrivateLogServerIbanLinkClickedFunction::Run() {
  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  paydm->LogServerIbanLinkClicked();
  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateSaveIbanFunction

ExtensionFunction::ResponseAction AutofillPrivateSaveIbanFunction::Run() {
  std::optional<api::autofill_private::SaveIban::Params> parameters =
      api::autofill_private::SaveIban::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);

  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  api::autofill_private::IbanEntry* iban_entry = &parameters->iban;
  CHECK(iban_entry->value);
  const autofill::Iban* existing_iban = nullptr;

  // The IBAN guid is specified if the user tries to update an existing IBAN via
  // the Chrome payment settings page.
  if (iban_entry->guid.has_value() && !iban_entry->guid->empty()) {
    existing_iban = paydm->GetIbanByGUID(*iban_entry->guid);
    CHECK(existing_iban);
  }

  autofill::Iban iban_to_write =
      existing_iban ? *existing_iban : autofill::Iban();

  iban_to_write.set_value(base::UTF8ToUTF16(*iban_entry->value));

  if (iban_entry->nickname) {
    iban_to_write.set_nickname(base::UTF8ToUTF16(*iban_entry->nickname));
  }

  // Add a new IBAN and return if this is not an update.
  if (!existing_iban) {
    paydm->AddAsLocalIban(iban_to_write);
    base::RecordAction(base::UserMetricsAction("AutofillIbanAdded"));
    if (!iban_to_write.nickname().empty()) {
      base::RecordAction(
          base::UserMetricsAction("AutofillIbanAddedWithNickname"));
    }
    return RespondNow(NoArguments());
  }

  // This is an existing IBAN. Update the database entry in case anything has
  // changed.
  if (existing_iban->Compare(iban_to_write) != 0) {
    bool nickname_changed =
        existing_iban->nickname() != iban_to_write.nickname();
    paydm->UpdateIban(iban_to_write);
    base::RecordAction(base::UserMetricsAction("AutofillIbanEdited"));
    if (nickname_changed) {
      base::RecordAction(
          base::UserMetricsAction("AutofillIbanEditedWithNickname"));
    }
  }

  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetIbanListFunction

ExtensionFunction::ResponseAction AutofillPrivateGetIbanListFunction::Run() {
  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  autofill_util::IbanEntryList iban_list =
      autofill_util::GenerateIbanList(*paydm);
  return RespondNow(ArgumentList(
      api::autofill_private::GetIbanList::Results::Create(iban_list)));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateIsValidIbanFunction

ExtensionFunction::ResponseAction AutofillPrivateIsValidIbanFunction::Run() {
  std::optional<api::autofill_private::IsValidIban::Params> parameters =
      api::autofill_private::IsValidIban::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);
  return RespondNow(WithArguments(
      autofill::Iban::IsValid(base::UTF8ToUTF16(parameters->iban_value))));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateAddVirtualCardFunction

ExtensionFunction::ResponseAction AutofillPrivateAddVirtualCardFunction::Run() {
  std::optional<api::autofill_private::AddVirtualCard::Params> parameters =
      api::autofill_private::AddVirtualCard::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);

  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  const autofill::CreditCard* card =
      paydm->GetCreditCardByServerId(parameters->card_id);
  if (!card) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  auto* virtual_card_enrollment_manager =
      autofill_client()
          ->GetPaymentsAutofillClient()
          ->GetVirtualCardEnrollmentManager();
  CHECK(virtual_card_enrollment_manager);
  virtual_card_enrollment_manager->InitVirtualCardEnroll(
      *card, autofill::VirtualCardEnrollmentSource::kSettingsPage,
      base::BindOnce(
          &autofill::VirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble,
          base::Unretained(virtual_card_enrollment_manager)));
  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateRemoveVirtualCardFunction

ExtensionFunction::ResponseAction
AutofillPrivateRemoveVirtualCardFunction::Run() {
  std::optional<api::autofill_private::RemoveVirtualCard::Params> parameters =
      api::autofill_private::RemoveVirtualCard::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);

  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  const autofill::CreditCard* card =
      paydm->GetCreditCardByServerId(parameters->card_id);
  if (!card)
    return RespondNow(Error(kErrorDataUnavailable));

  autofill::BrowserAutofillManager* autofill_manager =
      GetBrowserAutofillManager(GetSenderWebContents());
  if (!autofill_manager) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  autofill::VirtualCardEnrollmentManager* virtual_card_enrollment_manager =
      autofill_manager->client()
          .GetPaymentsAutofillClient()
          ->GetVirtualCardEnrollmentManager();

  virtual_card_enrollment_manager->Unenroll(
      card->instrument_id(),
      /*virtual_card_enrollment_update_response_callback=*/std::nullopt);
  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetPayOverTimeIssuerListFunction

ExtensionFunction::ResponseAction
AutofillPrivateGetPayOverTimeIssuerListFunction::Run() {
  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  autofill_util::PayOverTimeIssuerEntryList pay_over_time_issuer_list =
      autofill_util::GeneratePayOverTimeIssuerList(*paydm);
  return RespondNow(ArgumentList(
      api::autofill_private::GetPayOverTimeIssuerList::Results::Create(
          pay_over_time_issuer_list)));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction

ExtensionFunction::ResponseAction
AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction::Run() {
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_OHOS)
  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  // We will be modifying the pref `kAutofillPaymentMethodsMandatoryReauth`
  // asynchronously. The pref value directly correlates to the mandatory auth
  // toggle.
  // We are also logging the start of the auth flow and
  // `!IsPaymentMethodsMandatoryReauthEnabled()` denotes that the user is either
  // opting in or out.
  base::RecordAction(base::UserMetricsAction(
      "PaymentsUserAuthTriggeredForMandatoryAuthToggle"));
  LogMandatoryReauthOptInOrOutUpdateEvent(
      MandatoryReauthOptInOrOutSource::kSettingsPage,
      /*opt_in=*/!paydm->IsPaymentMethodsMandatoryReauthEnabled(),
      MandatoryReauthAuthenticationFlowEvent::kFlowStarted);
  autofill_client()
      ->GetPaymentsAutofillClient()
      ->GetOrCreatePaymentsMandatoryReauthManager()
      ->AuthenticateWithMessage(
          l10n_util::GetStringUTF16(
              IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT),
          base::BindOnce(
              &AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction::
                  UpdateMandatoryAuthTogglePref,
              this));

  return RespondNow(NoArguments());
#else
  return RespondNow(Error(kErrorDeviceAuthUnavailable));
#endif  // BUILDFLAG (IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_OHOS)
}

// Update the Mandatory auth toggle pref and log whether the auth was successful
// or not.
void AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction::
    UpdateMandatoryAuthTogglePref(bool reauth_succeeded) {
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_OHOS)
  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm) {
    return;
  }

  // `opt_in` bool denotes whether the user is trying to opt in or out of the
  // mandatory reauth feature. If the mandatory reauth toggle on the settings is
  // currently enabled, then the `opt_in` bool will be false because the user is
  // opting-out, otherwise the `opt_in` bool will be true.
  const bool opt_in = !paydm->IsPaymentMethodsMandatoryReauthEnabled();
  LogMandatoryReauthOptInOrOutUpdateEvent(
      MandatoryReauthOptInOrOutSource::kSettingsPage, opt_in,
      reauth_succeeded ? MandatoryReauthAuthenticationFlowEvent::kFlowSucceeded
                       : MandatoryReauthAuthenticationFlowEvent::kFlowFailed);
  if (reauth_succeeded) {
    base::RecordAction(base::UserMetricsAction(
        "PaymentsUserAuthSuccessfulForMandatoryAuthToggle"));
    paydm->SetPaymentMethodsMandatoryReauthEnabled(opt_in);
  }
#endif
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetLocalCardFunction

ExtensionFunction::ResponseAction AutofillPrivateGetLocalCardFunction::Run() {
  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  if (paydm->IsPaymentMethodsMandatoryReauthEnabled()) {
    base::RecordAction(base::UserMetricsAction(
        "PaymentsUserAuthTriggeredToShowEditLocalCardDialog"));
    LogMandatoryReauthSettingsPageEditCardEvent(
        MandatoryReauthAuthenticationFlowEvent::kFlowStarted);

#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_OHOS)
    // Based on the result of the auth, we will be asynchronously returning the
    // card if the user can edit the local card.
    autofill_client()
        ->GetPaymentsAutofillClient()
        ->GetOrCreatePaymentsMandatoryReauthManager()
        ->AuthenticateWithMessage(
            l10n_util::GetStringUTF16(
                IDS_PAYMENTS_AUTOFILL_EDIT_CARD_MANDATORY_REAUTH_PROMPT),
            base::BindOnce(
                &AutofillPrivateGetLocalCardFunction::OnReauthFinished, this));
#else
    // This Autofill private API is only available on desktop systems and
    // IsPaymentMethodsMandatoryReauthEnabled() ensures that it's only enabled
    // for MacOS and Windows.
    NOTREACHED();
#endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_OHOS)
  } else {
    ReturnCreditCard();
  }
  // Due to async nature of AuthenticateWithMessage() on mandatory re-auth
  // manager and delayed return on ReturnCreditCard(), we use the below check to
  // make sure we have a `Respond` captured. If we didn't have this check, then
  // we would show the edit card dialog box even before the user successfully
  // completes the auth.
  return did_respond() ? AlreadyResponded() : RespondLater();
}

// This is triggered after the reauth is completed and a local card may be
// returned based on the auth result. We also log whether the auth was
// successful or not.
void AutofillPrivateGetLocalCardFunction::OnReauthFinished(bool can_retrieve) {
  if (!can_retrieve) {
    LogMandatoryReauthSettingsPageEditCardEvent(
        MandatoryReauthAuthenticationFlowEvent::kFlowFailed);
    Respond(NoArguments());
    return;
  }
  base::RecordAction(base::UserMetricsAction(
      "PaymentsUserAuthSuccessfulToShowEditLocalCardDialog"));
  LogMandatoryReauthSettingsPageEditCardEvent(
      MandatoryReauthAuthenticationFlowEvent::kFlowSucceeded);
  ReturnCreditCard();
}

void AutofillPrivateGetLocalCardFunction::ReturnCreditCard() {
  PaymentsDataManager* paydm = payments_data_manager();
  CHECK(paydm);

  std::optional<autofill_private::GetLocalCard::Params> parameters =
      autofill_private::GetLocalCard::Params::Create(args());
  if (auto* card_from_guid = paydm->GetCreditCardByGUID(parameters->guid)) {
    return Respond(ArgumentList(autofill_private::GetLocalCard::Results::Create(
        autofill_util::CreditCardToCreditCardEntry(
            *card_from_guid, *paydm,
            /*mask_local_cards=*/false))));
  }
  return Respond(Error(kErrorCardDataUnavailable));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateCheckIfDeviceAuthAvailableFunction

ExtensionFunction::ResponseAction
AutofillPrivateCheckIfDeviceAuthAvailableFunction::Run() {
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_OHOS)
  autofill::ContentAutofillClient* client =
      autofill::ContentAutofillClient::FromWebContents(GetSenderWebContents());
  if (client) {
    return RespondNow(WithArguments(autofill::IsDeviceAuthAvailable(
        client->GetDeviceAuthenticator().get())));
  }
#endif  // BUILDFLAG (IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_OHOS)
  return RespondNow(Error(kErrorDeviceAuthUnavailable));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateBulkDeleteAllCvcsFunction

ExtensionFunction::ResponseAction
AutofillPrivateBulkDeleteAllCvcsFunction::Run() {
  PaymentsDataManager* paydm = payments_data_manager();
  if (!paydm || !paydm->is_payments_data_loaded()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  // Clear local and server CVCs from the webdata database. For server CVCs,
  // this will also clear them from the Chrome sync server and thus other
  // devices.
  paydm->ClearLocalCvcs();
  paydm->ClearServerCvcs();

  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateSetAutofillSyncToggleEnabledFunction

ExtensionFunction::ResponseAction
AutofillPrivateSetAutofillSyncToggleEnabledFunction::Run() {
  AddressDataManager* adm = address_data_manager();
  if (!adm || !adm->has_initial_load_finished()) {
    return RespondNow(Error(kErrorDataUnavailable));
  }

  std::optional<api::autofill_private::SetAutofillSyncToggleEnabled::Params>
      parameters =
          api::autofill_private::SetAutofillSyncToggleEnabled::Params::Create(
              args());
  EXTENSION_FUNCTION_VALIDATE(parameters);
  adm->SetAutofillSelectableTypeEnabled(parameters->enabled);
  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateAddOrUpdateEntityInstanceFunction

ExtensionFunction::ResponseAction
AutofillPrivateAddOrUpdateEntityInstanceFunction::Run() {
  std::optional<autofill_private::AddOrUpdateEntityInstance::Params>
      parameters =
          autofill_private::AddOrUpdateEntityInstance::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);

  const autofill_private::EntityInstance& private_api_entity_instance =
      parameters->entity_instance;
  std::optional<EntityInstance> entity_instance =
      autofill_ai_util::PrivateApiEntityInstanceToEntityInstance(
          private_api_entity_instance,
          g_browser_process->GetApplicationLocale());
  if (!entity_instance.has_value()) {
    return RespondNow(Error(kErrorAutofillAiInvalidData));
  }

  Profile* profile = Profile::FromBrowserContext(browser_context());
  EntityDataManager* entity_data_manager =
      profile ? AutofillEntityDataManagerFactory::GetForProfile(profile)
              : nullptr;

  if (!entity_data_manager) {
    return RespondNow(Error(kErrorAutofillAiUnavailable));
  }
  entity_data_manager->AddOrUpdateEntityInstance(entity_instance.value());
  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateRemoveEntityInstanceFunction

ExtensionFunction::ResponseAction
AutofillPrivateRemoveEntityInstanceFunction::Run() {
  std::optional<autofill_private::RemoveEntityInstance::Params> parameters =
      autofill_private::RemoveEntityInstance::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);

  Profile* profile = Profile::FromBrowserContext(browser_context());
  EntityDataManager* entity_data_manager =
      profile ? AutofillEntityDataManagerFactory::GetForProfile(profile)
              : nullptr;

  if (!entity_data_manager) {
    return RespondNow(Error(kErrorAutofillAiUnavailable));
  }
  entity_data_manager->RemoveEntityInstance(
      EntityInstance::EntityId(parameters->guid));
  return RespondNow(NoArguments());
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateLoadEntityInstancesFunction

ExtensionFunction::ResponseAction
AutofillPrivateLoadEntityInstancesFunction::Run() {
  Profile* profile = Profile::FromBrowserContext(browser_context());
  EntityDataManager* entity_data_manager =
      profile ? AutofillEntityDataManagerFactory::GetForProfile(profile)
              : nullptr;

  if (!entity_data_manager) {
    return RespondNow(Error(kErrorAutofillAiUnavailable));
  }
  std::vector<autofill_private::EntityInstanceWithLabels> result =
      autofill_ai_util::EntityInstancesToPrivateApiEntityInstancesWithLabels(
          entity_data_manager->GetEntityInstances(),
          g_browser_process->GetApplicationLocale());
  return RespondNow(ArgumentList(
      autofill_private::LoadEntityInstances::Results::Create(result)));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetEntityInstanceByGuidFunction

ExtensionFunction::ResponseAction
AutofillPrivateGetEntityInstanceByGuidFunction::Run() {
  std::optional<autofill_private::GetEntityInstanceByGuid::Params> parameters =
      autofill_private::GetEntityInstanceByGuid::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);

  Profile* profile = Profile::FromBrowserContext(browser_context());
  EntityDataManager* entity_data_manager =
      profile ? AutofillEntityDataManagerFactory::GetForProfile(profile)
              : nullptr;

  if (!entity_data_manager) {
    return RespondNow(Error(kErrorAutofillAiUnavailable));
  }
  base::optional_ref<const EntityInstance> entity_instance =
      entity_data_manager->GetEntityInstance(
          EntityInstance::EntityId(parameters->guid));
  if (!entity_instance.has_value()) {
    return RespondNow(Error(kErrorAutofillAiEntityInstanceNotFound));
  }
  return RespondNow(ArgumentList(
      api::autofill_private::GetEntityInstanceByGuid::Results::Create(
          autofill_ai_util::EntityInstanceToPrivateApiEntityInstance(
              entity_instance.value(), autofill_client()->GetAppLocale()))));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetWritableEntityTypesFunction

ExtensionFunction::ResponseAction
AutofillPrivateGetWritableEntityTypesFunction::Run() {
  auto all_types = autofill::DenseSet<EntityType>::all();

  std::vector<autofill_private::EntityType> result;
  result.reserve(all_types.size());
  for (EntityType entity_type : all_types) {
    if (!entity_type.enabled(
            autofill_client()->GetVariationConfigCountryCode())) {
      continue;
    }
    if (entity_type.read_only()) {
      continue;
    }
    // TODO(crbug.com/454892936): Provide the correct value for
    // `supports_wallet_storage`.
    result.push_back(autofill_ai_util::EntityTypeToPrivateApiEntityType(
        entity_type, /*supports_wallet_storage=*/false));
  }

  return RespondNow(ArgumentList(
      autofill_private::GetWritableEntityTypes::Results::Create(result)));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetAllAttributeTypesForEntityTypeNameFunction

ExtensionFunction::ResponseAction
AutofillPrivateGetAllAttributeTypesForEntityTypeNameFunction::Run() {
  std::optional<autofill_private::GetAllAttributeTypesForEntityTypeName::Params>
      parameters = autofill_private::GetAllAttributeTypesForEntityTypeName::
          Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);

  std::optional<EntityTypeName> entity_type_name =
      autofill::ToSafeEntityTypeName(parameters->entity_type_name);
  if (!entity_type_name.has_value()) {
    return RespondNow(Error(kErrorAutofillAiTypeNameOutOfBounds));
  }

  EntityType entity_type(entity_type_name.value());
  std::vector<autofill_private::AttributeType> result = base::ToVector(
      entity_type.attributes(),
      [](const autofill::AttributeType& attribute_type) {
        autofill_private::AttributeType private_api_attribute_type;
        private_api_attribute_type.type_name =
            base::to_underlying(attribute_type.name());
        private_api_attribute_type.type_name_as_string =
            base::UTF16ToUTF8(attribute_type.GetNameForI18n());
        private_api_attribute_type.data_type = autofill_ai_util::
            AttributeTypeDataTypeToPrivateApiAttributeTypeDataType(
                attribute_type.data_type());
        return private_api_attribute_type;
      });
  return RespondNow(ArgumentList(
      autofill_private::GetAllAttributeTypesForEntityTypeName::Results::Create(
          result)));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetAutofillAiOptInStatusFunction

ExtensionFunction::ResponseAction
AutofillPrivateGetAutofillAiOptInStatusFunction::Run() {
  return RespondNow(ArgumentList(
      api::autofill_private::GetAutofillAiOptInStatus::Results::Create(
          autofill::GetAutofillAiOptInStatus(*autofill_client()))));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateSetAutofillAiOptInStatusFunction

ExtensionFunction::ResponseAction
AutofillPrivateSetAutofillAiOptInStatusFunction::Run() {
  std::optional<autofill_private::SetAutofillAiOptInStatus::Params> parameters =
      autofill_private::SetAutofillAiOptInStatus::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(parameters);
  using enum autofill::AutofillAiOptInStatus;
  if (!autofill::SetAutofillAiOptInStatus(
          *autofill_client(), parameters->opted_in ? kOptedIn : kOptedOut)) {
    return RespondNow(ArgumentList(
        api::autofill_private::SetAutofillAiOptInStatus::Results::Create(
            /*success=*/false)));
  }

  if (parameters->opted_in) {
    autofill_client()->NotifyIphFeatureUsed(
        autofill::AutofillClient::IphFeature::kAutofillAi);
  }

  return RespondNow(ArgumentList(
      api::autofill_private::SetAutofillAiOptInStatus::Results::Create(
          /*success=*/true)));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateGetWalletablePassDetectionOptInStatusFunction

ExtensionFunction::ResponseAction
AutofillPrivateGetWalletablePassDetectionOptInStatusFunction::Run() {
  return RespondNow(WithArguments(wallet::GetWalletablePassDetectionOptInStatus(
      autofill_client()->GetPrefs(), autofill_client()->GetIdentityManager())));
}

////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateSetWalletablePassDetectionOptInStatusFunction

ExtensionFunction::ResponseAction
AutofillPrivateSetWalletablePassDetectionOptInStatusFunction::Run() {
  std::optional<autofill_private::SetWalletablePassDetectionOptInStatus::Params>
      params = autofill_private::SetWalletablePassDetectionOptInStatus::Params::
          Create(args());
  EXTENSION_FUNCTION_VALIDATE(params);
  wallet::SetWalletablePassDetectionOptInStatus(
      autofill_client()->GetPrefs(), autofill_client()->GetIdentityManager(),
      params->opted_in);
  return RespondNow(NoArguments());
}

}  // namespace extensions