// Copyright 2017 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/field_filler.h" #include #include #include "base/feature_list.h" #include "base/i18n/case_conversion.h" #include "base/i18n/string_search.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/address_normalizer.h" #include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/data_model/autofill_data_model.h" #include "components/autofill/core/browser/data_model/credit_card.h" #include "components/autofill/core/browser/data_model/data_model_utils.h" #include "components/autofill/core/browser/data_model/phone_number.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/geo/alternative_state_name_map.h" #include "components/autofill/core/browser/geo/autofill_country.h" #include "components/autofill/core/browser/geo/country_names.h" #include "components/autofill/core/browser/geo/state_names.h" #include "components/autofill/core/browser/proto/states.pb.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_l10n_util.h" #include "components/autofill/core/common/autofill_regexes.h" #include "components/autofill/core/common/autofill_util.h" #include "components/strings/grit/components_strings.h" #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h" #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_formatter.h" #include "ui/base/l10n/l10n_util.h" using base::ASCIIToUTF16; using base::StringToInt; namespace autofill { namespace { // Returns true if the value was successfully set, meaning |value| was found in // the list of select options in |field|. Optionally, the caller may pass // |best_match_index| which will be set to the index of the best match. bool SetSelectControlValue(const std::u16string& value, FormFieldData* field, size_t* best_match_index, std::string* failure_to_fill) { l10n::CaseInsensitiveCompare compare; std::u16string best_match; for (size_t i = 0; i < field->options.size(); ++i) { const SelectOption& option = field->options[i]; if (value == option.value || value == option.content) { // An exact match, use it. best_match = option.value; if (best_match_index) *best_match_index = i; break; } if (compare.StringsEqual(value, option.value) || compare.StringsEqual(value, option.content)) { // A match, but not in the same case. Save it in case an exact match is // not found. best_match = option.value; if (best_match_index) *best_match_index = i; } } if (best_match.empty()) { if (failure_to_fill) { *failure_to_fill += "Did not find value to fill in select control element. "; } return false; } field->value = best_match; return true; } // Like SetSelectControlValue, but searches within the field values and options // for |value|. For example, "NC - North Carolina" would match "north carolina". bool SetSelectControlValueSubstringMatch(const std::u16string& value, bool ignore_whitespace, FormFieldData* field, std::string* failure_to_fill) { int best_match = FieldFiller::FindShortestSubstringMatchInSelect( value, ignore_whitespace, field); if (best_match >= 0) { field->value = field->options[best_match].value; return true; } if (failure_to_fill) { *failure_to_fill += "Did not find substring match for filling select control element. "; } return false; } // Like SetSelectControlValue, but searches within the field values and options // for |value|. First it tokenizes the options, then tries to match against // tokens. For example, "NC - North Carolina" would match "nc" but not "ca". bool SetSelectControlValueTokenMatch(const std::u16string& value, FormFieldData* field, std::string* failure_to_fill) { std::vector tokenized; l10n::CaseInsensitiveCompare compare; for (const SelectOption& option : field->options) { tokenized = base::SplitString(option.value, base::kWhitespaceASCIIAs16, base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); if (std::find_if(tokenized.begin(), tokenized.end(), [&compare, value](std::u16string& rhs) { return compare.StringsEqual(value, rhs); }) != tokenized.end()) { field->value = option.value; return true; } tokenized = base::SplitString(option.content, base::kWhitespaceASCIIAs16, base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); if (std::find_if(tokenized.begin(), tokenized.end(), [&compare, value](std::u16string& rhs) { return compare.StringsEqual(value, rhs); }) != tokenized.end()) { field->value = option.value; return true; } } if (failure_to_fill) { *failure_to_fill += "Did not find token match for filling select control element. "; } return false; } // Helper method to normalize the |admin_area| for the given |country_code|. // The value in |admin_area| will be overwritten. bool NormalizeAdminAreaForCountryCode(std::u16string* admin_area, const std::string& country_code, AddressNormalizer* address_normalizer) { DCHECK(address_normalizer); DCHECK(admin_area); if (admin_area->empty() || country_code.empty()) return false; AutofillProfile tmp_profile; tmp_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code)); tmp_profile.SetRawInfo(ADDRESS_HOME_STATE, *admin_area); if (!address_normalizer->NormalizeAddressSync(&tmp_profile)) return false; *admin_area = tmp_profile.GetRawInfo(ADDRESS_HOME_STATE); return true; } // Will normalize |value| and the options in |field| with |address_normalizer| // (which should not be null), and return whether the fill was successful. bool SetNormalizedStateSelectControlValue(const std::u16string& value, FormFieldData* field, const std::string& country_code, AddressNormalizer* address_normalizer, std::string* failure_to_fill) { DCHECK(address_normalizer); // We attempt to normalize a copy of the field value. If normalization was not // successful, it means the rules were probably not loaded. Give up. Note that // the normalizer will fetch the rule for next time it's called. // TODO(crbug.com/788417): We should probably sanitize |value| before // normalizing. std::u16string field_value = value; if (!NormalizeAdminAreaForCountryCode(&field_value, country_code, address_normalizer)) { if (failure_to_fill) *failure_to_fill += "Could not normalize admin area for country code. "; return false; } // If successful, try filling the normalized value with the existing field // |options|. if (SetSelectControlValue(field_value, field, /*best_match_index=*/nullptr, failure_to_fill)) return true; // Normalize the |field| options in place, using a copy. // TODO(crbug.com/788417): We should probably sanitize the values in // |field_copy| before normalizing. FormFieldData field_copy(*field); bool normalized = false; for (SelectOption& option : field_copy.options) { normalized |= NormalizeAdminAreaForCountryCode(&option.value, country_code, address_normalizer); normalized |= NormalizeAdminAreaForCountryCode( &option.content, country_code, address_normalizer); } // If at least some normalization happened on the field options, try filling // them with |field_value|. size_t best_match_index = 0; if (normalized && SetSelectControlValue(field_value, &field_copy, &best_match_index, failure_to_fill)) { // |best_match_index| now points to the option in |field->options| // that corresponds to our best match. Update |field| with the answer. field->value = field->options[best_match_index].value; return true; } if (failure_to_fill) *failure_to_fill += "Could not set normalized state in control element. "; return false; } // Try to fill a numeric |value| into the given |field|. bool FillNumericSelectControl(int value, FormFieldData* field, std::string* failure_to_fill) { for (const SelectOption& option : field->options) { int num; if ((StringToInt(option.value, &num) && num == value) || (StringToInt(option.content, &num) && num == value)) { field->value = option.value; return true; } } if (failure_to_fill) { *failure_to_fill += "Did not find numeric value to fill in select control element. "; } return false; } bool FillStateSelectControl(const std::u16string& value, FormFieldData* field, const std::string& country_code, AddressNormalizer* address_normalizer, std::string* failure_to_fill) { std::vector abbreviations; std::vector full_names; if (base::FeatureList::IsEnabled( features::kAutofillUseAlternativeStateNameMap)) { // Fetch the corresponding entry from AlternativeStateNameMap. absl::optional state_entry = AlternativeStateNameMap::GetInstance()->GetEntry( AlternativeStateNameMap::CountryCode(country_code), AlternativeStateNameMap::StateName(value)); if (state_entry) { for (const auto& abbr : state_entry->abbreviations()) abbreviations.push_back(base::UTF8ToUTF16(abbr)); if (state_entry->has_canonical_name()) full_names.push_back(base::UTF8ToUTF16(state_entry->canonical_name())); for (const auto& alternative_name : state_entry->alternative_names()) full_names.push_back(base::UTF8ToUTF16(alternative_name)); } else { if (value.size() > 2) { full_names.push_back(value); } else { abbreviations.push_back(value); } } } std::u16string state_name; std::u16string state_abbreviation; // |abbreviation| will be empty for non-US countries. state_names::GetNameAndAbbreviation(value, &state_name, &state_abbreviation); if (!state_name.empty()) full_names.push_back(std::move(state_name)); if (!state_abbreviation.empty()) abbreviations.push_back(std::move(state_abbreviation)); // Remove `abbreviations` from the `full_names` as a precautionary measure in // case the `AlternativeStateNameMap` contains bad data. base::ranges::sort(abbreviations); full_names.erase( base::ranges::remove_if(full_names, [&](const std::u16string& full_name) { return base::ranges::binary_search( abbreviations, full_name); }), full_names.end()); // Try an exact match of the abbreviation first. for (const auto& abbreviation : abbreviations) { if (!abbreviation.empty() && SetSelectControlValue(abbreviation, field, /*best_match_index=*/nullptr, failure_to_fill)) { return true; } } // Try an exact match of the full name. for (const auto& full : full_names) { if (!full.empty() && SetSelectControlValue(full, field, /*best_match_index=*/nullptr, failure_to_fill)) { return true; } } // Try an inexact match of the full name. for (const auto& full : full_names) { if (!full.empty() && SetSelectControlValueSubstringMatch(full, false, field, failure_to_fill)) { return true; } } // Try an inexact match of the abbreviation name. for (const auto& abbreviation : abbreviations) { if (!abbreviation.empty() && SetSelectControlValueTokenMatch(abbreviation, field, failure_to_fill)) { return true; } } // Try to match a normalized |value| of the state and the |field| options. if (address_normalizer && SetNormalizedStateSelectControlValue( value, field, country_code, address_normalizer, failure_to_fill)) { return true; } if (failure_to_fill) *failure_to_fill += "Could not fill state in select control element. "; return false; } bool FillCountrySelectControl(const std::u16string& value, FormFieldData* field_data, std::string* failure_to_fill) { std::string country_code = CountryNames::GetInstance()->GetCountryCode(value); if (country_code.empty()) { if (failure_to_fill) *failure_to_fill += "Cannot fill empty country code. "; return false; } for (const SelectOption& option : field_data->options) { // Canonicalize each