| // Copyright 2015 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 "chrome/browser/extensions/api/autofill_private/autofill_private_api.h" |
| |
| #include <stddef.h> |
| #include <utility> |
| |
| #include "base/guid.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/values.h" |
| #include "chrome/browser/autofill/personal_data_manager_factory.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/extensions/api/autofill_private/autofill_util.h" |
| #include "chrome/common/extensions/api/autofill_private.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "components/autofill/core/browser/autofill_profile.h" |
| #include "components/autofill/core/browser/personal_data_manager.h" |
| #include "extensions/browser/extension_function.h" |
| #include "extensions/browser/extension_function_registry.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 "ui/base/l10n/l10n_util.h" |
| |
| namespace autofill_private = extensions::api::autofill_private; |
| namespace addressinput = i18n::addressinput; |
| |
| namespace { |
| |
| static const char kSettingsOrigin[] = "Chrome settings"; |
| static const char kErrorDataUnavailable[] = "Autofill data unavailable."; |
| |
| // Fills |components| with the address UI components that should be used to |
| // input an address for |country_code| when UI BCP 47 language code is |
| // |ui_language_code|. |
| void PopulateAddressComponents( |
| const std::string& country_code, |
| const std::string& ui_language_code, |
| autofill_private::AddressComponents* address_components) { |
| DCHECK(address_components); |
| |
| i18n::addressinput::Localization localization; |
| localization.SetGetter(l10n_util::GetStringUTF8); |
| std::string best_address_language_code; |
| std::vector<addressinput::AddressUiComponent> components = |
| i18n::addressinput::BuildComponents( |
| country_code, |
| localization, |
| ui_language_code, |
| &best_address_language_code); |
| if (components.empty()) { |
| static const char kDefaultCountryCode[] = "US"; |
| components = i18n::addressinput::BuildComponents( |
| kDefaultCountryCode, |
| localization, |
| ui_language_code, |
| &best_address_language_code); |
| } |
| address_components->language_code = best_address_language_code; |
| DCHECK(!components.empty()); |
| |
| autofill_private::AddressComponentRow* row = nullptr; |
| for (size_t i = 0; i < components.size(); ++i) { |
| if (!row || |
| components[i - 1].length_hint == |
| addressinput::AddressUiComponent::HINT_LONG || |
| components[i].length_hint == |
| addressinput::AddressUiComponent::HINT_LONG) { |
| address_components->components.push_back( |
| autofill_private::AddressComponentRow()); |
| row = &address_components->components.back(); |
| } |
| |
| autofill_private::AddressComponent component; |
| component.field_name = components[i].name; |
| |
| switch (components[i].field) { |
| case i18n::addressinput::COUNTRY: |
| component.field = |
| autofill_private::AddressField::ADDRESS_FIELD_COUNTRY_CODE; |
| break; |
| case i18n::addressinput::ADMIN_AREA: |
| component.field = |
| autofill_private::AddressField::ADDRESS_FIELD_ADDRESS_LEVEL_1; |
| break; |
| case i18n::addressinput::LOCALITY: |
| component.field = |
| autofill_private::AddressField::ADDRESS_FIELD_ADDRESS_LEVEL_2; |
| break; |
| case i18n::addressinput::DEPENDENT_LOCALITY: |
| component.field = |
| autofill_private::AddressField::ADDRESS_FIELD_ADDRESS_LEVEL_3; |
| break; |
| case i18n::addressinput::SORTING_CODE: |
| component.field = |
| autofill_private::AddressField::ADDRESS_FIELD_SORTING_CODE; |
| break; |
| case i18n::addressinput::POSTAL_CODE: |
| component.field = |
| autofill_private::AddressField::ADDRESS_FIELD_POSTAL_CODE; |
| break; |
| case i18n::addressinput::STREET_ADDRESS: |
| component.field = |
| autofill_private::AddressField::ADDRESS_FIELD_ADDRESS_LINES; |
| break; |
| case i18n::addressinput::ORGANIZATION: |
| component.field = |
| autofill_private::AddressField::ADDRESS_FIELD_COMPANY_NAME; |
| break; |
| case i18n::addressinput::RECIPIENT: |
| component.field = |
| autofill_private::AddressField::ADDRESS_FIELD_FULL_NAME; |
| break; |
| } |
| |
| switch (components[i].length_hint) { |
| case addressinput::AddressUiComponent::HINT_LONG: |
| component.is_long_field = true; |
| break; |
| case addressinput::AddressUiComponent::HINT_SHORT: |
| component.is_long_field = false; |
| break; |
| } |
| |
| row->row.push_back(std::move(component)); |
| } |
| } |
| |
| // Searches the |list| for the value at |index|. If this value is present in |
| // any of the rest of the list, then the item (at |index|) is removed. The |
| // comparison of phone number values is done on normalized versions of the phone |
| // number values. |
| void RemoveDuplicatePhoneNumberAtIndex( |
| size_t index, const std::string& country_code, base::ListValue* list) { |
| base::string16 new_value; |
| if (!list->GetString(index, &new_value)) { |
| NOTREACHED() << "List should have a value at index " << index; |
| return; |
| } |
| |
| bool is_duplicate = false; |
| std::string app_locale = g_browser_process->GetApplicationLocale(); |
| for (size_t i = 0; i < list->GetSize() && !is_duplicate; ++i) { |
| if (i == index) |
| continue; |
| |
| base::string16 existing_value; |
| if (!list->GetString(i, &existing_value)) { |
| NOTREACHED() << "List should have a value at index " << i; |
| continue; |
| } |
| is_duplicate = autofill::i18n::PhoneNumbersMatch( |
| new_value, existing_value, country_code, app_locale); |
| } |
| |
| if (is_duplicate) |
| list->Remove(index, nullptr); |
| } |
| |
| } // namespace |
| |
| namespace extensions { |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutofillPrivateSaveAddressFunction |
| |
| AutofillPrivateSaveAddressFunction::AutofillPrivateSaveAddressFunction() |
| : chrome_details_(this) {} |
| |
| AutofillPrivateSaveAddressFunction::~AutofillPrivateSaveAddressFunction() {} |
| |
| ExtensionFunction::ResponseAction AutofillPrivateSaveAddressFunction::Run() { |
| std::unique_ptr<api::autofill_private::SaveAddress::Params> parameters = |
| api::autofill_private::SaveAddress::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters.get()); |
| |
| autofill::PersonalDataManager* personal_data = |
| autofill::PersonalDataManagerFactory::GetForProfile( |
| chrome_details_.GetProfile()); |
| if (!personal_data || !personal_data->IsDataLoaded()) { |
| error_ = kErrorDataUnavailable; |
| return RespondNow(NoArguments()); |
| } |
| |
| api::autofill_private::AddressEntry* address = ¶meters->address; |
| |
| std::string guid = address->guid ? *address->guid : ""; |
| autofill::AutofillProfile profile(guid, kSettingsOrigin); |
| |
| // Strings from JavaScript use UTF-8 encoding. This container is used as an |
| // intermediate container for functions which require UTF-16 strings. |
| std::vector<base::string16> string16Container; |
| |
| if (address->full_names) { |
| std::string full_name; |
| if (!address->full_names->empty()) |
| full_name = address->full_names->at(0); |
| profile.SetInfo(autofill::AutofillType(autofill::NAME_FULL), |
| base::UTF8ToUTF16(full_name), |
| g_browser_process->GetApplicationLocale()); |
| } |
| |
| if (address->company_name) { |
| profile.SetRawInfo( |
| autofill::COMPANY_NAME, |
| base::UTF8ToUTF16(*address->company_name)); |
| } |
| |
| if (address->address_lines) { |
| profile.SetRawInfo( |
| autofill::ADDRESS_HOME_STREET_ADDRESS, |
| base::UTF8ToUTF16(*address->address_lines)); |
| } |
| |
| if (address->address_level1) { |
| profile.SetRawInfo( |
| autofill::ADDRESS_HOME_CITY, |
| base::UTF8ToUTF16(*address->address_level1)); |
| } |
| |
| if (address->address_level2) { |
| profile.SetRawInfo( |
| autofill::ADDRESS_HOME_STATE, |
| base::UTF8ToUTF16(*address->address_level2)); |
| } |
| |
| if (address->address_level3) { |
| profile.SetRawInfo( |
| autofill::ADDRESS_HOME_DEPENDENT_LOCALITY, |
| base::UTF8ToUTF16(*address->address_level3)); |
| } |
| |
| if (address->postal_code) { |
| profile.SetRawInfo( |
| autofill::ADDRESS_HOME_ZIP, |
| base::UTF8ToUTF16(*address->postal_code)); |
| } |
| |
| if (address->sorting_code) { |
| profile.SetRawInfo( |
| autofill::ADDRESS_HOME_SORTING_CODE, |
| base::UTF8ToUTF16(*address->sorting_code)); |
| } |
| |
| if (address->country_code) { |
| profile.SetRawInfo( |
| autofill::ADDRESS_HOME_COUNTRY, |
| base::UTF8ToUTF16(*address->country_code)); |
| } |
| |
| if (address->phone_numbers) { |
| std::string phone; |
| if (!address->phone_numbers->empty()) |
| phone = address->phone_numbers->at(0); |
| profile.SetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER, |
| base::UTF8ToUTF16(phone)); |
| } |
| |
| if (address->email_addresses) { |
| std::string email; |
| if (!address->email_addresses->empty()) |
| email = address->email_addresses->at(0); |
| profile.SetRawInfo(autofill::EMAIL_ADDRESS, base::UTF8ToUTF16(email)); |
| } |
| |
| if (address->language_code) |
| profile.set_language_code(*address->language_code); |
| |
| if (!base::IsValidGUID(profile.guid())) { |
| profile.set_guid(base::GenerateGUID()); |
| personal_data->AddProfile(profile); |
| } else { |
| personal_data->UpdateProfile(profile); |
| } |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutofillPrivateGetAddressComponentsFunction |
| |
| AutofillPrivateGetAddressComponentsFunction:: |
| ~AutofillPrivateGetAddressComponentsFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| AutofillPrivateGetAddressComponentsFunction::Run() { |
| std::unique_ptr<api::autofill_private::GetAddressComponents::Params> |
| parameters = |
| api::autofill_private::GetAddressComponents::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters.get()); |
| |
| autofill_private::AddressComponents components; |
| PopulateAddressComponents( |
| parameters->country_code, |
| g_browser_process->GetApplicationLocale(), |
| &components); |
| |
| return RespondNow(OneArgument(components.ToValue())); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutofillPrivateGetAddressListFunction |
| |
| AutofillPrivateGetAddressListFunction::AutofillPrivateGetAddressListFunction() |
| : chrome_details_(this) {} |
| |
| AutofillPrivateGetAddressListFunction:: |
| ~AutofillPrivateGetAddressListFunction() {} |
| |
| ExtensionFunction::ResponseAction AutofillPrivateGetAddressListFunction::Run() { |
| autofill::PersonalDataManager* personal_data = |
| autofill::PersonalDataManagerFactory::GetForProfile( |
| chrome_details_.GetProfile()); |
| |
| DCHECK(personal_data && personal_data->IsDataLoaded()); |
| |
| autofill_util::AddressEntryList addressList = |
| extensions::autofill_util::GenerateAddressList(*personal_data); |
| |
| return RespondNow(ArgumentList( |
| api::autofill_private::GetAddressList::Results::Create(addressList))); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutofillPrivateSaveCreditCardFunction |
| |
| AutofillPrivateSaveCreditCardFunction::AutofillPrivateSaveCreditCardFunction() |
| : chrome_details_(this) {} |
| |
| AutofillPrivateSaveCreditCardFunction:: |
| ~AutofillPrivateSaveCreditCardFunction() {} |
| |
| ExtensionFunction::ResponseAction AutofillPrivateSaveCreditCardFunction::Run() { |
| std::unique_ptr<api::autofill_private::SaveCreditCard::Params> parameters = |
| api::autofill_private::SaveCreditCard::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters.get()); |
| |
| autofill::PersonalDataManager* personal_data = |
| autofill::PersonalDataManagerFactory::GetForProfile( |
| chrome_details_.GetProfile()); |
| if (!personal_data || !personal_data->IsDataLoaded()) { |
| error_ = kErrorDataUnavailable; |
| return RespondNow(NoArguments()); |
| } |
| |
| api::autofill_private::CreditCardEntry* card = ¶meters->card; |
| |
| std::string guid = card->guid ? *card->guid : ""; |
| autofill::CreditCard credit_card(guid, 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 (!base::IsValidGUID(credit_card.guid())) { |
| credit_card.set_guid(base::GenerateGUID()); |
| personal_data->AddCreditCard(credit_card); |
| } else { |
| personal_data->UpdateCreditCard(credit_card); |
| } |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutofillPrivateRemoveEntryFunction |
| |
| AutofillPrivateRemoveEntryFunction::AutofillPrivateRemoveEntryFunction() |
| : chrome_details_(this) {} |
| |
| AutofillPrivateRemoveEntryFunction::~AutofillPrivateRemoveEntryFunction() {} |
| |
| ExtensionFunction::ResponseAction AutofillPrivateRemoveEntryFunction::Run() { |
| std::unique_ptr<api::autofill_private::RemoveEntry::Params> parameters = |
| api::autofill_private::RemoveEntry::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters.get()); |
| |
| autofill::PersonalDataManager* personal_data = |
| autofill::PersonalDataManagerFactory::GetForProfile( |
| chrome_details_.GetProfile()); |
| if (!personal_data || !personal_data->IsDataLoaded()) { |
| error_ = kErrorDataUnavailable; |
| return RespondNow(NoArguments()); |
| } |
| |
| personal_data->RemoveByGUID(parameters->guid); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutofillPrivateValidatePhoneNumbersFunction |
| |
| AutofillPrivateValidatePhoneNumbersFunction:: |
| ~AutofillPrivateValidatePhoneNumbersFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| AutofillPrivateValidatePhoneNumbersFunction::Run() { |
| std::unique_ptr<api::autofill_private::ValidatePhoneNumbers::Params> |
| parameters = |
| api::autofill_private::ValidatePhoneNumbers::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters.get()); |
| |
| api::autofill_private::ValidatePhoneParams* params = ¶meters->params; |
| |
| // Extract the phone numbers into a ListValue. |
| std::unique_ptr<base::ListValue> phoneNumbers(new base::ListValue); |
| phoneNumbers->AppendStrings(params->phone_numbers); |
| |
| RemoveDuplicatePhoneNumberAtIndex( |
| params->index_of_new_number, params->country_code, phoneNumbers.get()); |
| |
| return RespondNow(OneArgument(std::move(phoneNumbers))); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutofillPrivateMaskCreditCardFunction |
| |
| AutofillPrivateMaskCreditCardFunction::AutofillPrivateMaskCreditCardFunction() |
| : chrome_details_(this) {} |
| |
| AutofillPrivateMaskCreditCardFunction:: |
| ~AutofillPrivateMaskCreditCardFunction() {} |
| |
| ExtensionFunction::ResponseAction AutofillPrivateMaskCreditCardFunction::Run() { |
| std::unique_ptr<api::autofill_private::MaskCreditCard::Params> parameters = |
| api::autofill_private::MaskCreditCard::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters.get()); |
| |
| autofill::PersonalDataManager* personal_data = |
| autofill::PersonalDataManagerFactory::GetForProfile( |
| chrome_details_.GetProfile()); |
| if (!personal_data || !personal_data->IsDataLoaded()) { |
| error_ = kErrorDataUnavailable; |
| return RespondNow(NoArguments()); |
| } |
| |
| personal_data->ResetFullServerCard(parameters->guid); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutofillPrivateGetCreditCardListFunction |
| |
| AutofillPrivateGetCreditCardListFunction:: |
| AutofillPrivateGetCreditCardListFunction() |
| : chrome_details_(this) {} |
| |
| AutofillPrivateGetCreditCardListFunction:: |
| ~AutofillPrivateGetCreditCardListFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| AutofillPrivateGetCreditCardListFunction::Run() { |
| autofill::PersonalDataManager* personal_data = |
| autofill::PersonalDataManagerFactory::GetForProfile( |
| chrome_details_.GetProfile()); |
| |
| DCHECK(personal_data && personal_data->IsDataLoaded()); |
| |
| autofill_util::CreditCardEntryList creditCardList = |
| extensions::autofill_util::GenerateCreditCardList(*personal_data); |
| |
| return RespondNow( |
| ArgumentList(api::autofill_private::GetCreditCardList::Results::Create( |
| creditCardList))); |
| } |
| |
| } // namespace extensions |