blob: 0a175dab333cfb9215dc53cbc0c395056f0356a0 [file] [log] [blame]
// 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_assistant/browser/user_data_util.h"
#include <numeric>
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/i18n/case_conversion.h"
#include "base/no_destructor.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/geo/address_i18n.h"
#include "components/autofill_assistant/browser/action_value.pb.h"
#include "components/autofill_assistant/browser/cud_condition.pb.h"
#include "components/autofill_assistant/browser/field_formatter.h"
#include "components/autofill_assistant/browser/model.pb.h"
#include "components/autofill_assistant/browser/url_utils.h"
#include "components/autofill_assistant/browser/website_login_manager.h"
#include "components/strings/grit/components_strings.h"
#include "third_party/libaddressinput/chromium/addressinput_util.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
#include "third_party/re2/src/re2/re2.h"
#include "ui/base/l10n/l10n_util.h"
namespace autofill_assistant {
namespace user_data {
namespace {
constexpr char kDefaultLocale[] = "en-US";
template <typename T>
ClientStatus ExtractDataAndFormatClientValue(
const T& client_value,
const ValueExpression& value_expression,
const UserData& user_data,
bool quote_meta,
const std::string& locale,
std::string* out_value) {
if (value_expression.chunk().empty()) {
VLOG(1) << "|value_expression| is empty";
return ClientStatus(INVALID_ACTION);
}
base::flat_map<field_formatter::Key, std::string> data;
std::string localeOrDefault = locale.empty() ? kDefaultLocale : locale;
if (client_value.has_profile()) {
const auto& profile = client_value.profile();
if (profile.identifier().empty()) {
VLOG(1) << "empty |profile.identifier|";
return ClientStatus(INVALID_ACTION);
}
const autofill::AutofillProfile* address =
user_data.selected_address(profile.identifier());
if (address == nullptr) {
VLOG(1) << "Requested unknown address '" << profile.identifier() << "'";
return ClientStatus(PRECONDITION_FAILED);
}
auto address_map =
field_formatter::CreateAutofillMappings(*address, localeOrDefault);
data.insert(address_map.begin(), address_map.end());
}
const autofill::CreditCard* card = user_data.selected_card();
if (card != nullptr) {
auto card_map =
field_formatter::CreateAutofillMappings(*card, localeOrDefault);
data.insert(card_map.begin(), card_map.end());
}
for (const auto& chunk : value_expression.chunk()) {
if (!chunk.has_memory_key() ||
!user_data.HasAdditionalValue(chunk.memory_key())) {
continue;
}
const ValueProto* value = user_data.GetAdditionalValue(chunk.memory_key());
if (value->strings().values().size() == 1) {
data.emplace(field_formatter::Key(chunk.memory_key()),
value->strings().values(0));
}
}
const ClientStatus& format_status = field_formatter::FormatExpression(
value_expression, data, quote_meta, out_value);
if (!format_status.ok()) {
return format_status;
}
if (out_value->empty()) {
VLOG(1) << "|value_expression| result is empty";
return ClientStatus(EMPTY_VALUE_EXPRESSION_RESULT);
}
return OkClientStatus();
}
void OnGetStoredPassword(
base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
bool success,
std::string password) {
if (!success) {
std::move(callback).Run(ClientStatus(AUTOFILL_INFO_NOT_AVAILABLE),
std::string());
return;
}
std::move(callback).Run(OkClientStatus(), password);
}
bool EvaluateCondition(
const base::flat_map<field_formatter::Key, std::string>& data,
const RequiredDataPiece::Condition& condition) {
std::string value;
auto it = data.find(field_formatter::Key(condition.key()));
if (it != data.end()) {
value = it->second;
}
switch (condition.condition_case()) {
case RequiredDataPiece::Condition::kNotEmpty:
return !value.empty();
case RequiredDataPiece::Condition::kRegexp: {
re2::RE2::Options options;
options.set_case_sensitive(
condition.regexp().text_filter().case_sensitive());
re2::RE2 regexp(condition.regexp().text_filter().re2(), options);
return RE2::PartialMatch(value, regexp);
}
case RequiredDataPiece::Condition::CONDITION_NOT_SET:
return false;
}
}
std::vector<std::string> GetValidationErrors(
const base::flat_map<field_formatter::Key, std::string>& data,
const std::vector<RequiredDataPiece>& required_data_pieces) {
std::vector<std::string> errors;
for (const auto& required_data_piece : required_data_pieces) {
if (!EvaluateCondition(data, required_data_piece.condition())) {
errors.push_back(required_data_piece.error_message());
}
}
return errors;
}
std::vector<std::string> GetProfileValidationErrors(
const autofill::AutofillProfile* profile,
const std::vector<RequiredDataPiece>& required_data_pieces) {
if (required_data_pieces.empty()) {
return std::vector<std::string>();
}
return GetValidationErrors(
profile
? field_formatter::CreateAutofillMappings(*profile, kDefaultLocale)
: base::flat_map<field_formatter::Key, std::string>(),
required_data_pieces);
}
// Helper function that compares instances of AutofillProfile by completeness
// in regards to the current options. Full profiles should be ordered before
// empty ones and fall back to compare the profile's last usage.
bool CompletenessCompareContacts(
const std::vector<RequiredDataPiece>& required_data_pieces,
const autofill::AutofillProfile& a,
const base::flat_map<field_formatter::Key, std::string>& data_a,
const autofill::AutofillProfile& b,
const base::flat_map<field_formatter::Key, std::string>& data_b) {
int incomplete_fields_a =
GetValidationErrors(data_a, required_data_pieces).size();
int incomplete_fields_b =
GetValidationErrors(data_b, required_data_pieces).size();
if (incomplete_fields_a != incomplete_fields_b) {
return incomplete_fields_a <= incomplete_fields_b;
}
return a.use_date() > b.use_date();
}
int GetAddressEditorCompletenessRating(
const autofill::AutofillProfile& profile) {
auto address_data = autofill::i18n::CreateAddressDataFromAutofillProfile(
profile, kDefaultLocale);
std::multimap<i18n::addressinput::AddressField,
i18n::addressinput::AddressProblem>
problems;
autofill::addressinput::ValidateRequiredFields(
*address_data, /* filter= */ nullptr, &problems);
return problems.size();
}
int CompletenessCompareAddresses(
const std::vector<RequiredDataPiece>& required_data_pieces,
const autofill::AutofillProfile& a,
const base::flat_map<field_formatter::Key, std::string>& data_a,
const autofill::AutofillProfile& b,
const base::flat_map<field_formatter::Key, std::string>& data_b) {
// Compare by editor completeness first. This is done because the
// AddressEditor only allows storing addresses it considers complete.
int incomplete_fields_a = GetAddressEditorCompletenessRating(a);
int incomplete_fields_b = GetAddressEditorCompletenessRating(b);
if (incomplete_fields_a != incomplete_fields_b) {
return incomplete_fields_b - incomplete_fields_a;
}
incomplete_fields_a =
GetValidationErrors(data_a, required_data_pieces).size();
incomplete_fields_b =
GetValidationErrors(data_b, required_data_pieces).size();
return incomplete_fields_b - incomplete_fields_a;
}
// Helper function that compares instances of AutofillProfile by completeness
// in regards to the current options. Full profiles should be ordered before
// empty ones and fall back to compare the profile's name in case of equality.
bool CompletenessCompareShippingAddresses(
const CollectUserDataOptions& options,
const autofill::AutofillProfile& a,
const base::flat_map<field_formatter::Key, std::string>& data_a,
const autofill::AutofillProfile& b,
const base::flat_map<field_formatter::Key, std::string>& data_b) {
int address_compare = CompletenessCompareAddresses(
options.required_shipping_address_data_pieces, a, data_a, b, data_b);
if (address_compare != 0) {
return address_compare > 0;
}
return a.use_date() > b.use_date();
}
// Helper function that compares instances of PaymentInstrument by completeness
// in regards to the current options. Full payment instruments should be
// ordered before empty ones and fall back to compare the full name on the
// credit card in case of equality.
bool CompletenessComparePaymentInstruments(
const CollectUserDataOptions& options,
const PaymentInstrument& a,
const base::flat_map<field_formatter::Key, std::string>& data_a,
const PaymentInstrument& b,
const base::flat_map<field_formatter::Key, std::string>& data_b) {
DCHECK(a.card);
DCHECK(b.card);
int incomplete_fields_a =
GetValidationErrors(data_a, options.required_credit_card_data_pieces)
.size();
int incomplete_fields_b =
GetValidationErrors(data_b, options.required_credit_card_data_pieces)
.size();
if (incomplete_fields_a != incomplete_fields_b) {
return incomplete_fields_a <= incomplete_fields_b;
}
bool a_has_valid_expiration = a.card->HasValidExpirationDate();
bool b_has_valid_expiration = b.card->HasValidExpirationDate();
if (a_has_valid_expiration != b_has_valid_expiration) {
return !b_has_valid_expiration;
}
bool a_has_valid_number =
(a.card->record_type() != autofill::CreditCard::MASKED_SERVER_CARD &&
a.card->HasValidCardNumber()) ||
(a.card->record_type() == autofill::CreditCard::MASKED_SERVER_CARD &&
!a.card->GetRawInfo(autofill::CREDIT_CARD_NUMBER).empty());
bool b_has_valid_number =
(b.card->record_type() != autofill::CreditCard::MASKED_SERVER_CARD &&
b.card->HasValidCardNumber()) ||
(b.card->record_type() == autofill::CreditCard::MASKED_SERVER_CARD &&
!b.card->GetRawInfo(autofill::CREDIT_CARD_NUMBER).empty());
if (a_has_valid_number != b_has_valid_number) {
return !b_has_valid_number;
}
bool a_has_address = a.billing_address != nullptr;
bool b_has_address = b.billing_address != nullptr;
if (a_has_address != b_has_address) {
return !b_has_address;
}
if (a_has_address && b_has_address) {
int address_compare = CompletenessCompareAddresses(
options.required_billing_address_data_pieces, *a.billing_address,
data_a, *b.billing_address, data_b);
if (address_compare != 0) {
return address_compare > 0;
}
}
return a.card->use_date() > b.card->use_date();
}
bool EvaluateNotEmpty(
const base::flat_map<field_formatter::Key, std::string>& mapping,
autofill::ServerFieldType field_type) {
auto it = mapping.find(field_formatter::Key(static_cast<int>(field_type)));
return it != mapping.end() && !it->second.empty();
}
ClientStatus MoveAutofillValueRegexpToTextFilter(
const UserData* user_data,
SelectorProto::PropertyFilter* value) {
if (!value->has_autofill_value_regexp()) {
return OkClientStatus();
}
if (user_data == nullptr) {
return ClientStatus(PRECONDITION_FAILED);
}
const AutofillValueRegexp& autofill_value_regexp =
value->autofill_value_regexp();
TextFilter text_filter;
text_filter.set_case_sensitive(
autofill_value_regexp.value_expression_re2().case_sensitive());
std::string re2;
ClientStatus re2_status =
GetFormattedClientValue(autofill_value_regexp, *user_data, &re2);
text_filter.set_re2(re2);
// Assigning text_filter will clear autofill_value_regexp.
*value->mutable_text_filter() = text_filter;
return re2_status;
}
} // namespace
std::vector<std::string> GetContactValidationErrors(
const autofill::AutofillProfile* profile,
const CollectUserDataOptions& collect_user_data_options) {
return GetProfileValidationErrors(
profile, collect_user_data_options.required_contact_data_pieces);
}
std::vector<std::string> GetPhoneNumberValidationErrors(
const autofill::AutofillProfile* profile,
const CollectUserDataOptions& collect_user_data_options) {
return GetProfileValidationErrors(
profile, collect_user_data_options.required_phone_number_data_pieces);
}
std::vector<int> SortContactsByCompleteness(
const CollectUserDataOptions& collect_user_data_options,
const std::vector<std::unique_ptr<Contact>>& contacts) {
std::vector<base::flat_map<field_formatter::Key, std::string>>
mapped_contacts;
for (const auto& contact : contacts) {
mapped_contacts.push_back(field_formatter::CreateAutofillMappings(
*contact->profile, kDefaultLocale));
}
std::vector<int> indices(contacts.size());
std::iota(std::begin(indices), std::end(indices), 0);
std::stable_sort(
indices.begin(), indices.end(),
[&collect_user_data_options, &contacts, &mapped_contacts](int i, int j) {
return CompletenessCompareContacts(
collect_user_data_options.required_contact_data_pieces,
*contacts[i]->profile, mapped_contacts[i], *contacts[j]->profile,
mapped_contacts[j]);
});
return indices;
}
std::vector<int> SortPhoneNumbersByCompleteness(
const CollectUserDataOptions& collect_user_data_options,
const std::vector<std::unique_ptr<PhoneNumber>>& phone_numbers) {
std::vector<base::flat_map<field_formatter::Key, std::string>>
mapped_phone_numbers;
for (const auto& phone_number : phone_numbers) {
mapped_phone_numbers.push_back(field_formatter::CreateAutofillMappings(
*phone_number->profile, kDefaultLocale));
}
std::vector<int> indices(phone_numbers.size());
std::iota(std::begin(indices), std::end(indices), 0);
std::stable_sort(
indices.begin(), indices.end(),
[&collect_user_data_options, &phone_numbers, &mapped_phone_numbers](
int i, int j) {
return CompletenessCompareContacts(
collect_user_data_options.required_phone_number_data_pieces,
*phone_numbers[i]->profile, mapped_phone_numbers[i],
*phone_numbers[j]->profile, mapped_phone_numbers[j]);
});
return indices;
}
int GetDefaultContact(const CollectUserDataOptions& collect_user_data_options,
const std::vector<std::unique_ptr<Contact>>& contacts) {
if (contacts.empty()) {
return -1;
}
auto sorted_indices =
SortContactsByCompleteness(collect_user_data_options, contacts);
if (!collect_user_data_options.default_email.empty()) {
for (int index : sorted_indices) {
if (base::UTF16ToUTF8(
contacts[index]->profile->GetRawInfo(autofill::EMAIL_ADDRESS)) ==
collect_user_data_options.default_email) {
return index;
}
}
}
return sorted_indices[0];
}
int GetDefaultPhoneNumber(
const CollectUserDataOptions& collect_user_data_options,
const std::vector<std::unique_ptr<PhoneNumber>>& phone_numbers) {
if (phone_numbers.empty()) {
return -1;
}
auto sorted_indices =
SortPhoneNumbersByCompleteness(collect_user_data_options, phone_numbers);
return sorted_indices[0];
}
std::vector<std::string> GetShippingAddressValidationErrors(
const autofill::AutofillProfile* profile,
const CollectUserDataOptions& collect_user_data_options) {
std::vector<std::string> errors;
if (!collect_user_data_options.request_shipping) {
return errors;
}
if (!collect_user_data_options.required_shipping_address_data_pieces
.empty()) {
errors = GetProfileValidationErrors(
profile,
collect_user_data_options.required_shipping_address_data_pieces);
}
// Require address editor completeness if Assistant validation succeeds. If
// Assistant validation fails, the editor has to be opened and requires
// completeness to save the change, do not append the (potentially duplicate)
// error in this case.
if (errors.empty() && (profile == nullptr ||
GetAddressEditorCompletenessRating(*profile) != 0)) {
errors.push_back(l10n_util::GetStringUTF8(
IDS_AUTOFILL_ASSISTANT_PAYMENT_INFORMATION_MISSING));
}
return errors;
}
std::vector<int> SortShippingAddressesByCompleteness(
const CollectUserDataOptions& collect_user_data_options,
const std::vector<std::unique_ptr<Address>>& addresses) {
std::vector<base::flat_map<field_formatter::Key, std::string>>
mapped_addresses;
for (const auto& address : addresses) {
mapped_addresses.push_back(field_formatter::CreateAutofillMappings(
*address->profile, kDefaultLocale));
}
std::vector<int> indices(addresses.size());
std::iota(std::begin(indices), std::end(indices), 0);
std::stable_sort(indices.begin(), indices.end(),
[&collect_user_data_options, &addresses, &mapped_addresses](
int i, int j) {
return CompletenessCompareShippingAddresses(
collect_user_data_options, *addresses[i]->profile,
mapped_addresses[i], *addresses[j]->profile,
mapped_addresses[j]);
});
return indices;
}
int GetDefaultShippingAddress(
const CollectUserDataOptions& collect_user_data_options,
const std::vector<std::unique_ptr<Address>>& addresses) {
if (addresses.empty()) {
return -1;
}
auto sorted_indices =
SortShippingAddressesByCompleteness(collect_user_data_options, addresses);
return sorted_indices[0];
}
std::vector<std::string> GetPaymentInstrumentValidationErrors(
const autofill::CreditCard* credit_card,
const autofill::AutofillProfile* billing_address,
const CollectUserDataOptions& collect_user_data_options) {
std::vector<std::string> errors;
if (!collect_user_data_options.request_payment_method) {
return errors;
}
if (!collect_user_data_options.required_credit_card_data_pieces.empty()) {
const auto& card_errors = GetValidationErrors(
credit_card ? field_formatter::CreateAutofillMappings(*credit_card,
kDefaultLocale)
: base::flat_map<field_formatter::Key, std::string>(),
collect_user_data_options.required_credit_card_data_pieces);
errors.insert(errors.end(), card_errors.begin(), card_errors.end());
}
if (credit_card && !credit_card->HasValidExpirationDate()) {
errors.push_back(collect_user_data_options.credit_card_expired_text);
}
if (!collect_user_data_options.required_billing_address_data_pieces.empty()) {
const auto& address_errors = GetProfileValidationErrors(
billing_address,
collect_user_data_options.required_billing_address_data_pieces);
errors.insert(errors.end(), address_errors.begin(), address_errors.end());
}
// Require card editor completeness if Assistant validation succeeds. If
// Assistant validation fails, the editor has to be opened and requires
// completeness to save the change, do not append the (potentially duplicate)
// error in this case.
if (errors.empty()) {
if (credit_card &&
credit_card->record_type() !=
autofill::CreditCard::MASKED_SERVER_CARD &&
!credit_card->HasValidCardNumber()) {
// Can't check validity of masked server card numbers, because they are
// incomplete until decrypted.
errors.push_back(l10n_util::GetStringUTF8(
IDS_AUTOFILL_ASSISTANT_PAYMENT_INFORMATION_MISSING));
} else if (!billing_address ||
GetAddressEditorCompletenessRating(*billing_address) != 0) {
errors.push_back(l10n_util::GetStringUTF8(
IDS_AUTOFILL_ASSISTANT_PAYMENT_INFORMATION_MISSING));
}
}
return errors;
}
std::vector<int> SortPaymentInstrumentsByCompleteness(
const CollectUserDataOptions& collect_user_data_options,
const std::vector<std::unique_ptr<PaymentInstrument>>&
payment_instruments) {
std::vector<base::flat_map<field_formatter::Key, std::string>>
mapped_payment_instruments;
for (const auto& payment_instrument : payment_instruments) {
base::flat_map<field_formatter::Key, std::string>
mapped_payment_instrument = field_formatter::CreateAutofillMappings(
*payment_instrument->card, kDefaultLocale);
if (payment_instrument->billing_address != nullptr) {
base::flat_map<field_formatter::Key, std::string> mapped_address =
field_formatter::CreateAutofillMappings(
*payment_instrument->billing_address, kDefaultLocale);
mapped_payment_instrument.insert(mapped_address.begin(),
mapped_address.end());
}
mapped_payment_instruments.push_back(mapped_payment_instrument);
}
std::vector<int> payment_instrument_indices(payment_instruments.size());
std::iota(std::begin(payment_instrument_indices),
std::end(payment_instrument_indices), 0);
std::stable_sort(payment_instrument_indices.begin(),
payment_instrument_indices.end(),
[&collect_user_data_options, &payment_instruments,
&mapped_payment_instruments](int a, int b) {
return CompletenessComparePaymentInstruments(
collect_user_data_options, *payment_instruments[a],
mapped_payment_instruments[a], *payment_instruments[b],
mapped_payment_instruments[b]);
});
return payment_instrument_indices;
}
int GetDefaultPaymentInstrument(
const CollectUserDataOptions& collect_user_data_options,
const std::vector<std::unique_ptr<PaymentInstrument>>&
payment_instruments) {
if (payment_instruments.empty()) {
return -1;
}
auto sorted_indices = SortPaymentInstrumentsByCompleteness(
collect_user_data_options, payment_instruments);
return sorted_indices[0];
}
std::unique_ptr<autofill::AutofillProfile> MakeUniqueFromProfile(
const autofill::AutofillProfile& profile) {
auto unique_profile = std::make_unique<autofill::AutofillProfile>(profile);
// Temporary workaround so that fields like first/last name a properly
// populated.
unique_profile->FinalizeAfterImport();
return unique_profile;
}
ClientStatus GetFormattedClientValue(const AutofillValue& autofill_value,
const UserData& user_data,
std::string* out_value) {
return ExtractDataAndFormatClientValue(
autofill_value, autofill_value.value_expression(), user_data,
/* quote_meta= */ false, autofill_value.locale(), out_value);
}
ClientStatus GetFormattedClientValue(
const AutofillValueRegexp& autofill_value_regexp,
const UserData& user_data,
std::string* out_value) {
return ExtractDataAndFormatClientValue(
autofill_value_regexp,
autofill_value_regexp.value_expression_re2().value_expression(),
user_data,
/* quote_meta= */ true, autofill_value_regexp.locale(), out_value);
}
void GetPasswordManagerValue(
const PasswordManagerValue& password_manager_value,
const ElementFinder::Result& target_element,
const UserData* user_data,
WebsiteLoginManager* website_login_manager,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) {
if (!user_data->selected_login_) {
std::move(callback).Run(ClientStatus(PRECONDITION_FAILED), std::string());
return;
}
auto* target_render_frame_host = target_element.render_frame_host();
if (!target_render_frame_host) {
std::move(callback).Run(ClientStatus(PASSWORD_ORIGIN_MISMATCH),
std::string());
return;
}
switch (password_manager_value.credential_type()) {
case PasswordManagerValue::PASSWORD: {
auto login = *user_data->selected_login_;
// Origin check is done in PWM based on the
// |target_render_frame_host->GetLastCommittedURL()|
login.origin = target_render_frame_host->GetLastCommittedURL()
.DeprecatedGetOriginAsURL();
website_login_manager->GetPasswordForLogin(
login, base::BindOnce(&OnGetStoredPassword, std::move(callback)));
return;
}
case PasswordManagerValue::USERNAME:
std::move(callback).Run(OkClientStatus(),
user_data->selected_login_->username);
return;
case PasswordManagerValue::NOT_SET:
std::move(callback).Run(ClientStatus(INVALID_ACTION), std::string());
return;
}
}
ClientStatus GetClientMemoryStringValue(const std::string& client_memory_key,
const UserData* user_data,
std::string* out_value) {
if (client_memory_key.empty()) {
return ClientStatus(INVALID_ACTION);
}
if (!user_data->HasAdditionalValue(client_memory_key) ||
user_data->GetAdditionalValue(client_memory_key)
->strings()
.values()
.size() != 1) {
VLOG(1) << "Requested key '" << client_memory_key
<< "' not available in client memory";
return ClientStatus(PRECONDITION_FAILED);
}
out_value->assign(
user_data->GetAdditionalValue(client_memory_key)->strings().values(0));
return OkClientStatus();
}
void ResolveTextValue(const TextValue& text_value,
const ElementFinder::Result& target_element,
const ActionDelegate* action_delegate,
base::OnceCallback<void(const ClientStatus&,
const std::string&)> callback) {
std::string value;
ClientStatus status = OkClientStatus();
switch (text_value.value_case()) {
case TextValue::kText:
value = text_value.text();
break;
case TextValue::kAutofillValue: {
status = GetFormattedClientValue(text_value.autofill_value(),
*action_delegate->GetUserData(), &value);
break;
}
case TextValue::kPasswordManagerValue: {
GetPasswordManagerValue(text_value.password_manager_value(),
target_element, action_delegate->GetUserData(),
action_delegate->GetWebsiteLoginManager(),
std::move(callback));
return;
}
case TextValue::kClientMemoryKey: {
status =
GetClientMemoryStringValue(text_value.client_memory_key(),
action_delegate->GetUserData(), &value);
break;
}
case TextValue::VALUE_NOT_SET:
status = ClientStatus(INVALID_ACTION);
}
std::move(callback).Run(status, value);
}
Metrics::UserDataSelectionState GetNewSelectionState(
Metrics::UserDataSelectionState old_state,
UserDataEventType event_type) {
switch (event_type) {
case ENTRY_EDITED: {
switch (old_state) {
case Metrics::UserDataSelectionState::NO_CHANGE:
return Metrics::UserDataSelectionState::EDIT_PRESELECTED;
case Metrics::UserDataSelectionState::SELECTED_DIFFERENT_ENTRY:
return Metrics::UserDataSelectionState::
SELECTED_DIFFERENT_AND_MODIFIED_ENTRY;
case Metrics::UserDataSelectionState::NEW_ENTRY:
case Metrics::UserDataSelectionState::
SELECTED_DIFFERENT_AND_MODIFIED_ENTRY:
case Metrics::UserDataSelectionState::EDIT_PRESELECTED:
return old_state;
}
}
case SELECTION_CHANGED: {
switch (old_state) {
case Metrics::UserDataSelectionState::NO_CHANGE:
case Metrics::UserDataSelectionState::EDIT_PRESELECTED:
return Metrics::UserDataSelectionState::SELECTED_DIFFERENT_ENTRY;
case Metrics::UserDataSelectionState::SELECTED_DIFFERENT_ENTRY:
case Metrics::UserDataSelectionState::NEW_ENTRY:
case Metrics::UserDataSelectionState::
SELECTED_DIFFERENT_AND_MODIFIED_ENTRY:
// We keep the state which represents the greater effort for the user.
return old_state;
}
}
case ENTRY_CREATED:
return Metrics::UserDataSelectionState::NEW_ENTRY;
case UNKNOWN:
case NO_NOTIFICATION:
return old_state;
}
}
int GetFieldBitArrayForAddress(const autofill::AutofillProfile* profile) {
return GetFieldBitArrayForAddressAndPhoneNumber(profile, profile);
}
int GetFieldBitArrayForAddressAndPhoneNumber(
const autofill::AutofillProfile* profile,
const autofill::AutofillProfile* phone_number_profile) {
// Maps from the autofill field type to the respective position in the metrics
// bitarray.
static const base::NoDestructor<std::vector<std::pair<
autofill::ServerFieldType, Metrics::AutofillAssistantProfileFields>>>
fields_to_log(
{{autofill::NAME_FIRST,
Metrics::AutofillAssistantProfileFields::NAME_FIRST},
{autofill::NAME_LAST,
Metrics::AutofillAssistantProfileFields::NAME_LAST},
{autofill::NAME_FULL,
Metrics::AutofillAssistantProfileFields::NAME_FULL},
{autofill::EMAIL_ADDRESS,
Metrics::AutofillAssistantProfileFields::EMAIL_ADDRESS},
{autofill::ADDRESS_HOME_COUNTRY,
Metrics::AutofillAssistantProfileFields::ADDRESS_HOME_COUNTRY},
{autofill::ADDRESS_HOME_STATE,
Metrics::AutofillAssistantProfileFields::ADDRESS_HOME_STATE},
{autofill::ADDRESS_HOME_CITY,
Metrics::AutofillAssistantProfileFields::ADDRESS_HOME_CITY},
{autofill::ADDRESS_HOME_ZIP,
Metrics::AutofillAssistantProfileFields::ADDRESS_HOME_ZIP},
{autofill::ADDRESS_HOME_STREET_ADDRESS,
Metrics::AutofillAssistantProfileFields::ADDRESS_HOME_LINE1}});
// Maps from the phone-related autofill field types to the respective position
// in the metrics bitarray.
static const base::NoDestructor<std::vector<std::pair<
autofill::ServerFieldType, Metrics::AutofillAssistantProfileFields>>>
phone_number_fields_to_log(
{{autofill::PHONE_HOME_NUMBER,
Metrics::AutofillAssistantProfileFields::PHONE_HOME_NUMBER},
{autofill::PHONE_HOME_COUNTRY_CODE,
Metrics::AutofillAssistantProfileFields::PHONE_HOME_COUNTRY_CODE},
{autofill::PHONE_HOME_WHOLE_NUMBER,
Metrics::AutofillAssistantProfileFields::PHONE_HOME_WHOLE_NUMBER}});
int bit_array = 0;
// Check the non-phone fields.
if (profile) {
auto mapping =
field_formatter::CreateAutofillMappings(*profile, kDefaultLocale);
for (auto fields_pair : *fields_to_log) {
if (EvaluateNotEmpty(mapping, fields_pair.first)) {
bit_array |= fields_pair.second;
}
}
}
// Check the phone fields.
if (phone_number_profile) {
auto mapping = field_formatter::CreateAutofillMappings(
*phone_number_profile, kDefaultLocale);
for (auto fields_pair : *phone_number_fields_to_log) {
if (EvaluateNotEmpty(mapping, fields_pair.first)) {
bit_array |= fields_pair.second;
}
}
}
return bit_array;
}
int GetFieldBitArrayForCreditCard(const autofill::CreditCard* card) {
// If the card is nullptr, we consider all fields as missing.
if (!card) {
return 0;
}
auto mapping = field_formatter::CreateAutofillMappings(*card, kDefaultLocale);
// Maps from the autofill field type to the respective position in the metrics
// bitarray.
static const base::NoDestructor<std::vector<std::pair<
autofill::ServerFieldType, Metrics::AutofillAssistantCreditCardFields>>>
fields_to_log(
{{autofill::CREDIT_CARD_NAME_FULL,
Metrics::AutofillAssistantCreditCardFields::CREDIT_CARD_NAME_FULL},
{autofill::CREDIT_CARD_EXP_MONTH,
Metrics::AutofillAssistantCreditCardFields::CREDIT_CARD_EXP_MONTH},
{autofill::CREDIT_CARD_EXP_2_DIGIT_YEAR,
Metrics::AutofillAssistantCreditCardFields::
CREDIT_CARD_EXP_2_DIGIT_YEAR},
{autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR,
Metrics::AutofillAssistantCreditCardFields::
CREDIT_CARD_EXP_4_DIGIT_YEAR}});
int bit_array = 0;
for (auto fields_pair : *fields_to_log) {
if (EvaluateNotEmpty(mapping, fields_pair.first)) {
bit_array |= fields_pair.second;
}
}
if (card->record_type() == autofill::CreditCard::MASKED_SERVER_CARD) {
bit_array |= Metrics::AutofillAssistantCreditCardFields::MASKED;
// If the card is masked, we log the number as valid, to match what
// CollectUserData considers complete for the purposes of enabling the
// "Continue" button.
bit_array |= Metrics::AutofillAssistantCreditCardFields::VALID_NUMBER;
} else if (card->HasValidCardNumber()) {
bit_array |= Metrics::AutofillAssistantCreditCardFields::VALID_NUMBER;
}
return bit_array;
}
ClientStatus ResolveSelectorUserData(SelectorProto* selector,
const UserData* user_data) {
for (auto& filter : *selector->mutable_filters()) {
switch (filter.filter_case()) {
case SelectorProto::Filter::kProperty: {
ClientStatus filter_status = MoveAutofillValueRegexpToTextFilter(
user_data, filter.mutable_property());
if (!filter_status.ok()) {
return filter_status;
}
break;
}
case SelectorProto::Filter::kInnerText:
case SelectorProto::Filter::kValue:
case SelectorProto::Filter::kPseudoElementContent:
case SelectorProto::Filter::kCssStyle:
case SelectorProto::Filter::kCssSelector:
case SelectorProto::Filter::kEnterFrame:
case SelectorProto::Filter::kPseudoType:
case SelectorProto::Filter::kBoundingBox:
case SelectorProto::Filter::kNthMatch:
case SelectorProto::Filter::kLabelled:
case SelectorProto::Filter::kMatchCssSelector:
case SelectorProto::Filter::kOnTop:
case SelectorProto::Filter::FILTER_NOT_SET:
break;
// Do not add default here. In case a new filter gets added (that may
// contain a RegexpFilter) we want this to fail at compilation here.
}
}
return OkClientStatus();
}
} // namespace user_data
} // namespace autofill_assistant