diff options
Diffstat (limited to 'chromium/components/autofill/core')
189 files changed, 5443 insertions, 3115 deletions
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn index 44b052554fe..ea02a8035e7 100644 --- a/chromium/components/autofill/core/browser/BUILD.gn +++ b/chromium/components/autofill/core/browser/BUILD.gn @@ -56,8 +56,6 @@ jumbo_static_library("browser") { "autofill_handler_proxy.h", "autofill_ie_toolbar_import_win.cc", "autofill_ie_toolbar_import_win.h", - "autofill_internals_service.cc", - "autofill_internals_service.h", "autofill_manager.cc", "autofill_manager.h", "autofill_manager_test_delegate.h", @@ -145,12 +143,11 @@ jumbo_static_library("browser") { "geo/state_names.h", "geo/subkey_requester.cc", "geo/subkey_requester.h", - "logging/log_buffer.cc", - "logging/log_buffer.h", "logging/log_buffer_submitter.cc", "logging/log_buffer_submitter.h", "logging/log_manager.cc", "logging/log_manager.h", + "logging/log_protobufs.h", "logging/log_receiver.h", "logging/log_router.cc", "logging/log_router.h", @@ -197,6 +194,8 @@ jumbo_static_library("browser") { "payments/strike_database_integrator_base.h", "payments/strike_database_integrator_test_strike_database.cc", "payments/strike_database_integrator_test_strike_database.h", + "payments/upi_vpa_save_manager.cc", + "payments/upi_vpa_save_manager.h", "personal_data_manager.cc", "personal_data_manager.h", "personal_data_manager_observer.h", @@ -296,8 +295,10 @@ jumbo_static_library("browser") { "ui/mobile_label_formatter.h", "ui/payments/card_expiration_date_fix_flow_view_delegate_mobile.cc", "ui/payments/card_expiration_date_fix_flow_view_delegate_mobile.h", - "ui/payments/card_name_fix_flow_view_delegate_mobile.cc", - "ui/payments/card_name_fix_flow_view_delegate_mobile.h", + "ui/payments/card_name_fix_flow_controller.h", + "ui/payments/card_name_fix_flow_controller_impl.cc", + "ui/payments/card_name_fix_flow_controller_impl.h", + "ui/payments/card_name_fix_flow_view.h", ] } @@ -318,6 +319,8 @@ jumbo_static_library("browser") { "autofill_policy_handler.h", "payments/credit_card_fido_authenticator.cc", "payments/credit_card_fido_authenticator.h", + "payments/fido_authentication_strike_database.cc", + "payments/fido_authentication_strike_database.h", ] } @@ -441,6 +444,8 @@ jumbo_static_library("test_support") { "test_autofill_profile_validator_delayed.h", "test_autofill_provider.cc", "test_autofill_provider.h", + "test_autofill_tick_clock.cc", + "test_autofill_tick_clock.h", "test_event_waiter.h", "test_form_data_importer.cc", "test_form_data_importer.h", @@ -481,6 +486,7 @@ jumbo_static_library("test_support") { "//testing/gtest", "//third_party/libaddressinput:test_support", "//third_party/libaddressinput:util", + "//third_party/re2:re2", "//ui/accessibility", "//ui/gfx:test_support", "//ui/gfx/geometry", @@ -532,7 +538,6 @@ source_set("unit_tests") { "autofill_experiments_unittest.cc", "autofill_external_delegate_unittest.cc", "autofill_ie_toolbar_import_win_unittest.cc", - "autofill_internals_service_unittest.cc", "autofill_manager_unittest.cc", "autofill_merge_unittest.cc", "autofill_metrics_unittest.cc", @@ -565,7 +570,6 @@ source_set("unit_tests") { "geo/phone_number_i18n_unittest.cc", "geo/subkey_requester_unittest.cc", "logging/log_buffer_submitter_unittest.cc", - "logging/log_buffer_unittest.cc", "logging/log_manager_unittest.cc", "logging/log_router_unittest.cc", "payments/credit_card_access_manager_unittest.cc", @@ -603,6 +607,7 @@ source_set("unit_tests") { sources += [ "autofill_assistant_unittest.cc", "ui/mobile_label_formatter_unittest.cc", + "ui/payments/card_name_fix_flow_controller_impl_unittest.cc", ] } diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc index dd8098f25d8..973ecf62bb7 100644 --- a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc @@ -150,7 +150,7 @@ class AutocompleteHistoryManagerTest : public testing::Test { date_last_used); } - base::test::TaskEnvironment task_environment_; + base::test::SingleThreadTaskEnvironment task_environment_; scoped_refptr<MockWebDataService> web_data_service_; std::unique_ptr<AutocompleteHistoryManager> autocomplete_manager_; std::unique_ptr<PrefService> prefs_; diff --git a/chromium/components/autofill/core/browser/autofill_address_util.cc b/chromium/components/autofill/core/browser/autofill_address_util.cc index 9908b219b85..e621752b495 100644 --- a/chromium/components/autofill/core/browser/autofill_address_util.cc +++ b/chromium/components/autofill/core/browser/autofill_address_util.cc @@ -154,38 +154,4 @@ void GetAddressComponents(const std::string& country_code, } } -// Sets data related to the country <select>. -void SetCountryData(const PersonalDataManager& manager, - base::DictionaryValue* localized_strings, - const std::string& ui_language_code) { - autofill::CountryComboboxModel model; - model.SetCountries(manager, base::Callback<bool(const std::string&)>(), - ui_language_code); - const std::vector<std::unique_ptr<autofill::AutofillCountry>>& countries = - model.countries(); - localized_strings->SetString("defaultCountryCode", - countries.front()->country_code()); - - // An ordered list of options to show in the <select>. - auto country_list = std::make_unique<base::ListValue>(); - for (size_t i = 0; i < countries.size(); ++i) { - auto option_details = std::make_unique<base::DictionaryValue>(); - option_details->SetString("name", model.GetItemAt(i)); - option_details->SetString( - "value", countries[i] ? countries[i]->country_code() : "separator"); - country_list->Append(std::move(option_details)); - } - localized_strings->Set("autofillCountrySelectList", std::move(country_list)); - - auto default_country_components = std::make_unique<base::ListValue>(); - std::string default_country_language_code; - GetAddressComponents(countries.front()->country_code(), ui_language_code, - default_country_components.get(), - &default_country_language_code); - localized_strings->Set("autofillDefaultCountryComponents", - std::move(default_country_components)); - localized_strings->SetString("autofillDefaultCountryLanguageCode", - default_country_language_code); -} - } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_address_util.h b/chromium/components/autofill/core/browser/autofill_address_util.h index c962f8db10b..1e8b93f76d0 100644 --- a/chromium/components/autofill/core/browser/autofill_address_util.h +++ b/chromium/components/autofill/core/browser/autofill_address_util.h @@ -75,11 +75,6 @@ void GetAddressComponents(const std::string& country_code, base::ListValue* address_components, std::string* components_language_code); -// Sets data related to the country combobox. -void SetCountryData(const PersonalDataManager& manager, - base::DictionaryValue* localized_strings, - const std::string& ui_language_code); - } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_ADDRESS_UTIL_H_ diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css index 8dcdccf06e3..de7620a179d 100644 --- a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css +++ b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css @@ -66,6 +66,10 @@ background-color: #FFECB3; } +.log-entry[scope='AbortParsing'] { + background-color: #FFCDD2; +} + .log-entry[scope='Filling'] { background-color: #D1C4E9; } diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html new file mode 100644 index 00000000000..f1675379114 --- /dev/null +++ b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html @@ -0,0 +1,51 @@ +<!doctype html> +<html> +<head> +<!-- 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. --> +<meta charset="utf-8"> + +<!-- TODO(crbug.com/487000): Remove this entire html file once the following is +injected by web. --> +<script src="chrome://resources/js/ios/web_ui.js"></script> + +<script src="chrome://resources/js/util.js"></script> +<script src="autofill_and_password_manager_internals.js"></script> +<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css"> +<link rel="stylesheet" href="autofill_and_password_manager_internals.css"> +</head> +<body> +<h1 id="h1-title"></h1> +<div id="logging-note"></div> +<div id="logging-note-incognito"></div> +<div id="version-info"> + <table> + <tr> + <td class="label">Version:</td> + <td class="version"><span>$i18n{version}</span> + (<span>$i18n{official}</span>) + <span>$i18n{version_modifier}</span></td> + </tr> + <tr> + <td class="label">Revision:</td> + <td class="version"><span>$i18n{cl}</span></td> + </tr> + <tr> + <td class="label">User Agent:</td> + <td class="version"><span>$i18n{useragent}</span></td> + </tr> + <tr> + <td class="label">App Locale:</td> + <td class="version"><span>$i18n{app_locale}</span></td> + </tr> + <tr> + <td class="label">Variations:</td> + <td class="version" id="variations-list"></td> + </tr> + </table> +</div> +<div id="log-entries"> +</div> +</body> +</html> diff --git a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc index 95b0e1aef02..a47451ca2e5 100644 --- a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc @@ -148,7 +148,7 @@ class AutofillAssistantTest : public testing::Test { return static_cast<CardUnmaskDelegate*>(full_card_request); } - base::test::TaskEnvironment task_environment_; + base::test::SingleThreadTaskEnvironment task_environment_; TestAutofillClient autofill_client_; testing::NiceMock<TestAutofillDriver> autofill_driver_; TestPersonalDataManager pdm_; diff --git a/chromium/components/autofill/core/browser/autofill_client.cc b/chromium/components/autofill/core/browser/autofill_client.cc index 98d69be2b43..aaa1e239912 100644 --- a/chromium/components/autofill/core/browser/autofill_client.cc +++ b/chromium/components/autofill/core/browser/autofill_client.cc @@ -23,4 +23,8 @@ LogManager* AutofillClient::GetLogManager() const { return nullptr; } +bool AutofillClient::CloseWebauthnOfferDialog() { + return false; +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h index 09e305852ec..2ed56cfc478 100644 --- a/chromium/components/autofill/core/browser/autofill_client.h +++ b/chromium/components/autofill/core/browser/autofill_client.h @@ -6,6 +6,7 @@ #define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CLIENT_H_ #include <memory> +#include <set> #include <string> #include <vector> @@ -15,6 +16,7 @@ #include "base/strings/string16.h" #include "base/values.h" #include "build/build_config.h" +#include "components/autofill/core/browser/payments/legal_message_line.h" #include "components/autofill/core/browser/payments/risk_data_loader.h" #include "components/autofill/core/browser/ui/popup_types.h" #include "components/security_state/core/security_state.h" @@ -282,11 +284,11 @@ class AutofillClient : public RiskDataLoader { virtual void ShowLocalCardMigrationDialog( base::OnceClosure show_migration_dialog_closure) = 0; - // Shows a dialog with the given |legal_message| and the |user_email|. Runs - // |start_migrating_cards_callback| if the user would like the selected cards - // in the |migratable_credit_cards| to be uploaded to cloud. + // Shows a dialog with the given |legal_message_lines| and the |user_email|. + // Runs |start_migrating_cards_callback| if the user would like the selected + // cards in the |migratable_credit_cards| to be uploaded to cloud. virtual void ConfirmMigrateLocalCardToCloud( - std::unique_ptr<base::DictionaryValue> legal_message, + const LegalMessageLines& legal_message_lines, const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) = 0; @@ -304,13 +306,33 @@ class AutofillClient : public RiskDataLoader { const std::vector<MigratableCreditCard>& migratable_credit_cards, MigrationDeleteCardCallback delete_local_card_callback) = 0; +#if !defined(OS_ANDROID) && !defined(OS_IOS) + // Will show a dialog indicating the card verification is in progress. It is + // shown after verification starts only if the WebAuthn is enabled. + // Implemented only on desktop. + virtual void ShowVerifyPendingDialog( + base::OnceClosure cancel_card_verification_callback) = 0; + + // Close the verify pending dialog once the card verificiation is completed or + // verification falls back to CVC. + virtual void CloseVerifyPendingDialog() = 0; +#endif + // Will show a dialog offering the option to use device's platform // authenticator in the future instead of CVC to verify the card being - // unmasked. Runs |callback| is the OK button or the cancel button in the + // unmasked. Runs |callback| if the OK button or the cancel button in the // dialog is clicked. This is only implemented on desktop. virtual void ShowWebauthnOfferDialog( WebauthnOfferDialogCallback callback) = 0; + // Will close the WebAuthn offer dialog. Returns true if dialog was visible + // and has been closed. Implemented only on desktop. + virtual bool CloseWebauthnOfferDialog(); + + // Will update the WebAuthn offer dialog content to the error state. + // Implemented only on desktop. + virtual void UpdateWebauthnOfferDialogWithError() {} + // Runs |callback| if the |profile| should be imported as personal data. virtual void ConfirmSaveAutofillProfile(const AutofillProfile& profile, base::OnceClosure callback) = 0; @@ -326,11 +348,14 @@ class AutofillClient : public RiskDataLoader { AutofillClient::SaveCreditCardOptions options, LocalSaveCardPromptCallback callback) = 0; -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_IOS) // Display the cardholder name fix flow prompt and run the |callback| if // the card should be uploaded to payments with updated name from the user. virtual void ConfirmAccountNameFixFlow( base::OnceCallback<void(const base::string16&)> callback) = 0; +#endif // defined(OS_ANDROID) || defined(OS_IOS) + +#if defined(OS_ANDROID) // Display the expiration date fix flow prompt with the |card| details // and run the |callback| if the card should be uploaded to payments with // updated expiration date from the user. @@ -341,8 +366,8 @@ class AutofillClient : public RiskDataLoader { #endif // defined(OS_ANDROID) // Runs |callback| once the user makes a decision with respect to the - // offer-to-save prompt. Displays the contents of |legal_message| to the user. - // Displays a cardholder name textfield in the bubble if + // offer-to-save prompt. Displays the contents of |legal_message_lines| + // to the user. Displays a cardholder name textfield in the bubble if // |options.should_request_name_from_user| is true. Displays // a pair of expiration date dropdowns in the bubble if // |should_request_expiration_date_from_user| is true. On desktop, shows the @@ -352,7 +377,7 @@ class AutofillClient : public RiskDataLoader { // not offer to save at all. virtual void ConfirmSaveCreditCardToCloud( const CreditCard& card, - std::unique_ptr<base::DictionaryValue> legal_message, + const LegalMessageLines& legal_message_lines, SaveCreditCardOptions options, UploadSaveCardPromptCallback callback) = 0; diff --git a/chromium/components/autofill/core/browser/autofill_data_util.cc b/chromium/components/autofill/core/browser/autofill_data_util.cc index 02d4f378146..35620873ba7 100644 --- a/chromium/components/autofill/core/browser/autofill_data_util.cc +++ b/chromium/components/autofill/core/browser/autofill_data_util.cc @@ -55,12 +55,6 @@ const PaymentRequestData kPaymentRequestData[]{ {autofill::kVisaCard, "visa", IDR_AUTOFILL_CC_VISA, IDS_AUTOFILL_CC_VISA}, }; -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) -const PaymentRequestData kGooglePayBrandingRequestData = { - "googlePay", "googlePay", IDR_AUTOFILL_GOOGLE_PAY, - IDS_AUTOFILL_CC_GOOGLE_PAY}; -#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) - const PaymentRequestData kGenericPaymentRequestData = { autofill::kGenericCard, "generic", IDR_AUTOFILL_CC_GENERIC, IDS_AUTOFILL_CC_GENERIC}; @@ -464,70 +458,12 @@ base::string16 JoinNameParts(base::StringPiece16 given, return base::JoinString(full_name, base::ASCIIToUTF16(separator)); } -bool ProfileMatchesFullName(base::StringPiece16 full_name, - const autofill::AutofillProfile& profile) { - const base::string16 kSpace = base::ASCIIToUTF16(" "); - const base::string16 kPeriodSpace = base::ASCIIToUTF16(". "); - - // First Last - base::string16 candidate = profile.GetRawInfo(autofill::NAME_FIRST) + kSpace + - profile.GetRawInfo(autofill::NAME_LAST); - if (!full_name.compare(candidate)) { - return true; - } - - // First Middle Last - candidate = profile.GetRawInfo(autofill::NAME_FIRST) + kSpace + - profile.GetRawInfo(autofill::NAME_MIDDLE) + kSpace + - profile.GetRawInfo(autofill::NAME_LAST); - if (!full_name.compare(candidate)) { - return true; - } - - // First M Last - candidate = profile.GetRawInfo(autofill::NAME_FIRST) + kSpace + - profile.GetRawInfo(autofill::NAME_MIDDLE_INITIAL) + kSpace + - profile.GetRawInfo(autofill::NAME_LAST); - if (!full_name.compare(candidate)) { - return true; - } - - // First M. Last - candidate = profile.GetRawInfo(autofill::NAME_FIRST) + kSpace + - profile.GetRawInfo(autofill::NAME_MIDDLE_INITIAL) + kPeriodSpace + - profile.GetRawInfo(autofill::NAME_LAST); - if (!full_name.compare(candidate)) { - return true; - } - - // Last First - candidate = profile.GetRawInfo(autofill::NAME_LAST) + kSpace + - profile.GetRawInfo(autofill::NAME_FIRST); - if (!full_name.compare(candidate)) { - return true; - } - - // LastFirst - candidate = profile.GetRawInfo(autofill::NAME_LAST) + - profile.GetRawInfo(autofill::NAME_FIRST); - if (!full_name.compare(candidate)) { - return true; - } - - return false; -} - const PaymentRequestData& GetPaymentRequestData( const std::string& issuer_network) { for (const PaymentRequestData& data : kPaymentRequestData) { if (issuer_network == data.issuer_network) return data; } -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) - if (issuer_network == kGooglePayBrandingRequestData.issuer_network) { - return kGooglePayBrandingRequestData; - } -#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) return kGenericPaymentRequestData; } diff --git a/chromium/components/autofill/core/browser/autofill_data_util.h b/chromium/components/autofill/core/browser/autofill_data_util.h index a6060345333..d99dc25369e 100644 --- a/chromium/components/autofill/core/browser/autofill_data_util.h +++ b/chromium/components/autofill/core/browser/autofill_data_util.h @@ -96,11 +96,6 @@ base::string16 JoinNameParts(base::StringPiece16 given, base::StringPiece16 middle, base::StringPiece16 family); -// Returns true iff |full_name| is a concatenation of some combination of the -// first/middle/last (incl. middle initial) in |profile|. -bool ProfileMatchesFullName(base::StringPiece16 full_name, - const autofill::AutofillProfile& profile); - // Returns the Payment Request API basic card payment spec data for the provided // autofill credit card |network|. Will set the network and the icon to // "generic" for any unrecognized type. diff --git a/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc b/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc index 7b1ea28d9fa..2646b113750 100644 --- a/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc @@ -233,33 +233,6 @@ INSTANTIATE_TEST_SUITE_P( // Has a middle-name, too unusual )); -TEST(AutofillDataUtilTest, ProfileMatchesFullName) { - autofill::AutofillProfile profile; - autofill::test::SetProfileInfo( - &profile, "First", "Middle", "Last", "fml@example.com", "Acme inc", - "123 Main", "Apt 2", "Laredo", "TX", "77300", "US", "832-555-1000"); - - EXPECT_TRUE(ProfileMatchesFullName(base::UTF8ToUTF16("First Last"), profile)); - - EXPECT_TRUE( - ProfileMatchesFullName(base::UTF8ToUTF16("First Middle Last"), profile)); - - EXPECT_TRUE( - ProfileMatchesFullName(base::UTF8ToUTF16("First M Last"), profile)); - - EXPECT_TRUE( - ProfileMatchesFullName(base::UTF8ToUTF16("First M. Last"), profile)); - - EXPECT_TRUE( - ProfileMatchesFullName(base::UTF8ToUTF16("Last First"), profile)); - - EXPECT_TRUE( - ProfileMatchesFullName(base::UTF8ToUTF16("LastFirst"), profile)); - - EXPECT_FALSE( - ProfileMatchesFullName(base::UTF8ToUTF16("Kirby Puckett"), profile)); -} - struct ValidCountryCodeTestCase { std::string country_code; bool expected_result; diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.cc b/chromium/components/autofill/core/browser/autofill_download_manager.cc index 4513830064b..47f0b71fd95 100644 --- a/chromium/components/autofill/core/browser/autofill_download_manager.cc +++ b/chromium/components/autofill/core/browser/autofill_download_manager.cc @@ -16,6 +16,7 @@ #include "base/metrics/field_trial_params.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" +#include "base/numerics/ranges.h" #include "base/numerics/safe_conversions.h" #include "base/rand_util.h" #include "base/strings/strcat.h" @@ -24,11 +25,10 @@ #include "base/strings/stringprintf.h" #include "base/threading/thread_task_runner_handle.h" #include "components/autofill/core/browser/autofill_driver.h" -#include "components/autofill/core/browser/autofill_internals_service.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/form_structure.h" -#include "components/autofill/core/browser/logging/log_buffer.h" #include "components/autofill/core/browser/logging/log_manager.h" +#include "components/autofill/core/browser/logging/log_protobufs.h" #include "components/autofill/core/browser/proto/legacy_proto_bridge.h" #include "components/autofill/core/browser/proto/server.pb.h" #include "components/autofill/core/common/autofill_clock.h" @@ -37,6 +37,8 @@ #include "components/autofill/core/common/autofill_internals/logging_scope.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" +#include "components/autofill/core/common/autofill_tick_clock.h" +#include "components/autofill/core/common/logging/log_buffer.h" #include "components/autofill/core/common/mojom/autofill_types.mojom.h" #include "components/google/core/common/google_util.h" #include "components/history/core/browser/history_service.h" @@ -906,7 +908,7 @@ bool AutofillDownloadManager::StartRequest(FormRequestData request_data) { url_loader_factory.get(), base::BindOnce(&AutofillDownloadManager::OnSimpleLoaderComplete, base::Unretained(this), std::move(--url_loaders_.end()), - std::move(request_data), base::TimeTicks::Now())); + std::move(request_data), AutofillTickClock::NowTicks())); return true; } @@ -966,9 +968,9 @@ std::string AutofillDownloadManager::GetCombinedSignature( int AutofillDownloadManager::GetMaxServerAttempts() { // This value is constant for the life of the browser, so we cache it // statically on first use to avoid re-parsing the param on each retry - // opportunity. The range is forced to be within [1, 20]. - static int max_attempts = - std::max(1, std::min(20, kAutofillMaxServerAttempts.Get())); + // opportunity. + static const int max_attempts = + base::ClampToRange(kAutofillMaxServerAttempts.Get(), 1, 20); return max_attempts; } @@ -997,7 +999,7 @@ void AutofillDownloadManager::OnSimpleLoaderComplete( LogHttpResponseData(request_data.request_type, response_code, simple_loader->NetError(), - base::TimeTicks::Now() - request_start); + AutofillTickClock::NowTicks() - request_start); // Handle error if there is and return. if (!success) { diff --git a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc index d3fbc3484e4..a62afad14f7 100644 --- a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc @@ -34,6 +34,7 @@ #include "components/autofill/core/browser/randomized_encoder.h" #include "components/autofill/core/browser/test_autofill_clock.h" #include "components/autofill/core/browser/test_autofill_driver.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/form_data.h" @@ -229,8 +230,9 @@ class AutofillDownloadManagerTest : public AutofillDownloadManager::Observer, response.signature = form_signature; response.error = http_error; response.type_of_response = - request_type == AutofillDownloadManager::REQUEST_QUERY ? - REQUEST_QUERY_FAILED : REQUEST_UPLOAD_FAILED; + request_type == AutofillDownloadManager::REQUEST_QUERY + ? REQUEST_QUERY_FAILED + : REQUEST_UPLOAD_FAILED; responses_.push_back(response); } @@ -393,7 +395,8 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) { "<field autofilltype=\"31\" />" "<field autofilltype=\"33\" />" "</autofillqueryresponse>", - "", "<html></html>", + "", + "<html></html>", }; // Return them out of sequence. @@ -408,7 +411,7 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) { // Request 2: Unsuccessful upload. request = test_url_loader_factory_.GetPendingRequest(2); test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList( - request, network::CreateResourceResponseHead(net::HTTP_NOT_FOUND), + request, network::CreateURLResponseHead(net::HTTP_NOT_FOUND), responses[2], network::URLLoaderCompletionStatus(net::OK)); histogram.ExpectBucketCount("Autofill.Upload.HttpResponseOrErrorCode", net::HTTP_NOT_FOUND, 1); @@ -464,8 +467,7 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) { AutofillMetrics::QUERY_SENT, 2); histogram.ExpectUniqueSample("Autofill.Query.Method", METHOD_GET, 2); test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList( - request, - network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), + request, network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), responses[0], network::URLLoaderCompletionStatus(net::OK)); histogram.ExpectBucketCount("Autofill.Query.HttpResponseOrErrorCode", net::HTTP_INTERNAL_SERVER_ERROR, 1); @@ -489,7 +491,7 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) { network::URLLoaderCompletionStatus status(net::OK); status.exists_in_cache = true; test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList( - request, network::CreateResourceResponseHead(net::HTTP_OK), responses[0], + request, network::CreateURLResponseHead(net::HTTP_OK), responses[0], status); // Check Request 5. @@ -845,9 +847,8 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Query) { // Request error incurs a retry after 1 second. test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList( - request, - network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), "", - network::URLLoaderCompletionStatus(net::OK)); + request, network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), + "", network::URLLoaderCompletionStatus(net::OK)); EXPECT_EQ(1U, responses_.size()); EXPECT_LT(download_manager_.loader_backoff_.GetTimeUntilRelease(), @@ -864,7 +865,7 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Query) { // Next error incurs a retry after 2 seconds. test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList( request, - network::CreateResourceResponseHead(net::HTTP_REQUEST_ENTITY_TOO_LARGE), + network::CreateURLResponseHead(net::HTTP_REQUEST_ENTITY_TOO_LARGE), "<html></html>", network::URLLoaderCompletionStatus(net::OK)); EXPECT_EQ(2U, responses_.size()); @@ -915,9 +916,8 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Upload) { // Error incurs a retry after 1 second. test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList( - request, - network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), "", - network::URLLoaderCompletionStatus(net::OK)); + request, network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), + "", network::URLLoaderCompletionStatus(net::OK)); EXPECT_EQ(1U, responses_.size()); EXPECT_LT(download_manager_.loader_backoff_.GetTimeUntilRelease(), base::TimeDelta::FromMilliseconds(1100)); @@ -959,8 +959,8 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Upload) { request = test_url_loader_factory_.GetPendingRequest(2); test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList( request, - network::CreateResourceResponseHead(net::HTTP_REQUEST_ENTITY_TOO_LARGE), - "", network::URLLoaderCompletionStatus(net::OK)); + network::CreateURLResponseHead(net::HTTP_REQUEST_ENTITY_TOO_LARGE), "", + network::URLLoaderCompletionStatus(net::OK)); ASSERT_EQ(test_url_loader_factory_.NumPending(), 0); histogram.ExpectBucketCount("Autofill.Upload.HttpResponseOrErrorCode", net::HTTP_REQUEST_ENTITY_TOO_LARGE, 1); @@ -1012,7 +1012,7 @@ TEST_F(AutofillDownloadManagerTest, RetryLimit_Query) { // Request error incurs a retry after 1 second. test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList( request, - network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), + network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), "<html></html>", network::URLLoaderCompletionStatus(net::OK)); EXPECT_EQ(1U, responses_.size()); @@ -1089,8 +1089,8 @@ TEST_F(AutofillDownloadManagerTest, RetryLimit_Upload) { // Simulate a server failure. test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList( request, - network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), - "", network::URLLoaderCompletionStatus(net::OK)); + network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), "", + network::URLLoaderCompletionStatus(net::OK)); // Check that it was a failure. ASSERT_EQ(1U, responses_.size()); @@ -1206,25 +1206,25 @@ TEST_F(AutofillDownloadManagerTest, CacheQueryTest) { // Limit cache to two forms. LimitCache(2); - const char *responses[] = { - "<autofillqueryresponse>" + const char* responses[] = { + "<autofillqueryresponse>" "<field autofilltype=\"0\" />" "<field autofilltype=\"3\" />" "<field autofilltype=\"5\" />" - "</autofillqueryresponse>", - "<autofillqueryresponse>" + "</autofillqueryresponse>", + "<autofillqueryresponse>" "<field autofilltype=\"0\" />" "<field autofilltype=\"3\" />" "<field autofilltype=\"5\" />" "<field autofilltype=\"9\" />" - "</autofillqueryresponse>", - "<autofillqueryresponse>" + "</autofillqueryresponse>", + "<autofillqueryresponse>" "<field autofilltype=\"0\" />" "<field autofilltype=\"3\" />" "<field autofilltype=\"5\" />" "<field autofilltype=\"9\" />" "<field autofilltype=\"0\" />" - "</autofillqueryresponse>", + "</autofillqueryresponse>", }; base::HistogramTester histogram; @@ -2179,7 +2179,7 @@ TEST_P(AutofillUploadTest, PeriodicReset) { base::HistogramTester histogram_tester; TestAutofillClock test_clock; - test_clock.SetNow(base::Time::Now()); + test_clock.SetNow(AutofillClock::Now()); // The first attempt should succeed. EXPECT_TRUE(SendUploadRequest(form_structure, true, {}, "", true)); @@ -2237,7 +2237,7 @@ TEST_P(AutofillUploadTest, ResetOnClearUploadHisotry) { base::HistogramTester histogram_tester; TestAutofillClock test_clock; - test_clock.SetNow(base::Time::Now()); + test_clock.SetNow(AutofillClock::Now()); // The first attempt should succeed. EXPECT_TRUE(SendUploadRequest(form_structure, true, {}, "", true)); diff --git a/chromium/components/autofill/core/browser/autofill_driver.h b/chromium/components/autofill/core/browser/autofill_driver.h index b9e205706e4..e8998205270 100644 --- a/chromium/components/autofill/core/browser/autofill_driver.h +++ b/chromium/components/autofill/core/browser/autofill_driver.h @@ -107,9 +107,9 @@ class AutofillDriver { const base::string16& value) = 0; // Tells the renderer to set the currently focused node's corresponding - // accessibility node to |autofill_suggestions_available|. + // accessibility node's autofill state to |state|. virtual void RendererShouldSetSuggestionAvailability( - bool autofill_suggestions_available) = 0; + const mojom::AutofillState state) = 0; // Informs the renderer that the popup has been hidden. virtual void PopupHidden() = 0; diff --git a/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc b/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc index 54c431018dd..48ccf45049e 100644 --- a/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc @@ -100,7 +100,7 @@ class AutofillDriverFactoryTest : public testing::Test { protected: // For TestAutofillDriver. - base::test::TaskEnvironment task_environment_; + base::test::SingleThreadTaskEnvironment task_environment_; MockAutofillClient client_; diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc index 4ad323a4874..dd2bd3874d8 100644 --- a/chromium/components/autofill/core/browser/autofill_experiments.cc +++ b/chromium/components/autofill/core/browser/autofill_experiments.cc @@ -12,7 +12,6 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" -#include "components/autofill/core/browser/autofill_internals_service.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/logging/log_manager.h" #include "components/autofill/core/browser/payments/payments_util.h" diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.cc b/chromium/components/autofill/core/browser/autofill_external_delegate.cc index 60c4d7feb19..a5507ab6194 100644 --- a/chromium/components/autofill/core/browser/autofill_external_delegate.cc +++ b/chromium/components/autofill/core/browser/autofill_external_delegate.cc @@ -153,10 +153,10 @@ bool AutofillExternalDelegate::HasActiveScreenReader() const { } void AutofillExternalDelegate::OnAutofillAvailabilityEvent( - bool has_suggestions) { + const mojom::AutofillState state) { // Availability of suggestions should be communicated to Blink because // accessibility objects live in both the renderer and browser processes. - driver_->RendererShouldSetSuggestionAvailability(has_suggestions); + driver_->RendererShouldSetSuggestionAvailability(state); } void AutofillExternalDelegate::SetCurrentDataListValues( @@ -373,18 +373,6 @@ void AutofillExternalDelegate::ApplyAutofillOptions( #endif } -// On iOS, GooglePayIcon comes at the begining and hence prepended to the list. -#if defined(OS_IOS) - if (base::FeatureList::IsEnabled( - features::kAutofillDownstreamUseGooglePayBrandingOniOS) && - is_all_server_suggestions) { - Suggestion googlepay_icon; - googlepay_icon.icon = "googlePay"; - googlepay_icon.frontend_id = POPUP_ITEM_ID_GOOGLE_PAY_BRANDING; - suggestions->insert(suggestions->begin(), googlepay_icon); - } -#endif - #if defined(OS_ANDROID) if (IsKeyboardAccessoryEnabled()) { suggestions->back().icon = "settings"; diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.h b/chromium/components/autofill/core/browser/autofill_external_delegate.h index 2e2b8139e78..7cde61e18ac 100644 --- a/chromium/components/autofill/core/browser/autofill_external_delegate.h +++ b/chromium/components/autofill/core/browser/autofill_external_delegate.h @@ -86,9 +86,9 @@ class AutofillExternalDelegate : public AutofillPopupDelegate { // Returns true if there is a screen reader installed on the machine. virtual bool HasActiveScreenReader() const; - // Indicates on focus changed if autofill is available or unavailable, so - // state can be announced by screen readers. - virtual void OnAutofillAvailabilityEvent(bool has_suggestions); + // Indicates on focus changed if autofill/autocomplete is available or + // unavailable, so state can be announced by screen readers. + virtual void OnAutofillAvailabilityEvent(const mojom::AutofillState state); // Set the data list value associated with the current field. void SetCurrentDataListValues( diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc index a2c018bfd72..89dd815bd17 100644 --- a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc @@ -36,7 +36,6 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/geometry/rect.h" -using autofill::features::kAutofillDownstreamUseGooglePayBrandingOniOS; using base::ASCIIToUTF16; using testing::_; @@ -181,7 +180,7 @@ class AutofillExternalDelegateUnitTest : public testing::Test { kQueryId, suggestions, /*autoselect_first_suggestion=*/false); } - base::test::TaskEnvironment task_environment_; + base::test::SingleThreadTaskEnvironment task_environment_; testing::NiceMock<MockAutofillClient> autofill_client_; std::unique_ptr<testing::NiceMock<MockAutofillDriver>> autofill_driver_; @@ -769,54 +768,6 @@ TEST_F(AutofillExternalDelegateUnitTest, ShouldShowGooglePayIcon) { kQueryId, autofill_item, /*autoselect_first_suggestion=*/false, true); } -#if defined(OS_IOS) -TEST_F(AutofillExternalDelegateUnitTest, ShouldShowGooglePayIconOniOS) { - // Turn on feature flag. - base::test::ScopedFeatureList scoped_feature_list_; - scoped_feature_list_.InitAndEnableFeature( - kAutofillDownstreamUseGooglePayBrandingOniOS); - IssueOnQuery(kQueryId); - - auto element_icons = - testing::ElementsAre("googlePay", std::string(), "googlePay"); - EXPECT_CALL(autofill_client_, - ShowAutofillPopup(_, _, SuggestionVectorIconsAre(element_icons), - false, PopupType::kPersonalInformation, _)); - - std::vector<Suggestion> autofill_item; - autofill_item.push_back(Suggestion()); - autofill_item[0].frontend_id = kAutofillProfileId; - - // This should call ShowAutofillPopup. - external_delegate_->OnSuggestionsReturned( - kQueryId, autofill_item, /*autoselect_first_suggestion=*/false, true); -} - -TEST_F(AutofillExternalDelegateUnitTest, - ShouldNotShowGooglePayIconOniOSIfExperimentOff) { - // Turn on feature flag. - base::test::ScopedFeatureList scoped_feature_list_; - scoped_feature_list_.InitAndDisableFeature( - kAutofillDownstreamUseGooglePayBrandingOniOS); - IssueOnQuery(kQueryId); - - auto element_icons = testing::ElementsAre( - std::string(), - std::string() /* Autofill setting item does not have icon. */); - EXPECT_CALL(autofill_client_, - ShowAutofillPopup(_, _, SuggestionVectorIconsAre(element_icons), - false, PopupType::kPersonalInformation, _)); - - std::vector<Suggestion> autofill_item; - autofill_item.push_back(Suggestion()); - autofill_item[0].frontend_id = kAutofillProfileId; - - // This should call ShowAutofillPopup. - external_delegate_->OnSuggestionsReturned( - kQueryId, autofill_item, /*autoselect_first_suggestion=*/false, false); -} -#endif // defined(OS_IOS) - TEST_F(AutofillExternalDelegateUnitTest, ShouldNotShowGooglePayIconIfSuggestionsContainLocalCards) { IssueOnQuery(kQueryId); diff --git a/chromium/components/autofill/core/browser/autofill_field.cc b/chromium/components/autofill/core/browser/autofill_field.cc index 7068d125081..1381fb7c800 100644 --- a/chromium/components/autofill/core/browser/autofill_field.cc +++ b/chromium/components/autofill/core/browser/autofill_field.cc @@ -14,39 +14,28 @@ namespace autofill { -AutofillField::AutofillField() - : server_type_(NO_SERVER_DATA), - heuristic_type_(UNKNOWN_TYPE), - overall_type_(AutofillType(NO_SERVER_DATA)), - html_type_(HTML_TYPE_UNSPECIFIED), - html_mode_(HTML_MODE_NONE), - phone_part_(IGNORED), - credit_card_number_offset_(0), - previously_autofilled_(false), - only_fill_when_focused_(false), - generation_type_(AutofillUploadContents::Field::NO_GENERATION), - generated_password_changed_(false), - vote_type_(AutofillUploadContents::Field::NO_INFORMATION) {} +AutofillField::AutofillField() = default; + +AutofillField::AutofillField(FieldSignature field_signature) + : field_signature_(field_signature) {} AutofillField::AutofillField(const FormFieldData& field, const base::string16& unique_name) : FormFieldData(field), unique_name_(unique_name), - server_type_(NO_SERVER_DATA), - heuristic_type_(UNKNOWN_TYPE), - overall_type_(AutofillType(NO_SERVER_DATA)), - html_type_(HTML_TYPE_UNSPECIFIED), - html_mode_(HTML_MODE_NONE), - phone_part_(IGNORED), - credit_card_number_offset_(0), - previously_autofilled_(false), - only_fill_when_focused_(false), - parseable_name_(field.name), - generation_type_(AutofillUploadContents::Field::NO_GENERATION), - generated_password_changed_(false), - vote_type_(AutofillUploadContents::Field::NO_INFORMATION) {} - -AutofillField::~AutofillField() {} + parseable_name_(field.name) { + field_signature_ = + CalculateFieldSignatureByNameAndType(name, form_control_type); +} + +AutofillField::~AutofillField() = default; + +std::unique_ptr<AutofillField> AutofillField::CreateForPasswordManagerUpload( + FieldSignature field_signature) { + std::unique_ptr<AutofillField> field; + field.reset(new AutofillField(field_signature)); + return field; +} void AutofillField::set_heuristic_type(ServerFieldType type) { if (type >= 0 && type < MAX_VALID_FIELD_TYPE && @@ -178,7 +167,9 @@ bool AutofillField::IsEmpty() const { } FieldSignature AutofillField::GetFieldSignature() const { - return CalculateFieldSignatureByNameAndType(name, form_control_type); + return field_signature_ + ? *field_signature_ + : CalculateFieldSignatureByNameAndType(name, form_control_type); } std::string AutofillField::FieldSignatureAsStr() const { diff --git a/chromium/components/autofill/core/browser/autofill_field.h b/chromium/components/autofill/core/browser/autofill_field.h index e46ff91865a..30856f92d7b 100644 --- a/chromium/components/autofill/core/browser/autofill_field.h +++ b/chromium/components/autofill/core/browser/autofill_field.h @@ -43,6 +43,12 @@ class AutofillField : public FormFieldData { AutofillField(const FormFieldData& field, const base::string16& unique_name); virtual ~AutofillField(); + // Creates AutofillField that has bare minimum information for uploading + // votes, namely a field signature. Warning: do not use for Autofill code, + // since it is likely missing some fields. + static std::unique_ptr<AutofillField> CreateForPasswordManagerUpload( + FieldSignature field_signature); + const base::string16& unique_name() const { return unique_name_; } ServerFieldType heuristic_type() const { return heuristic_type_; } @@ -129,9 +135,6 @@ class AutofillField : public FormFieldData { // field). bool IsFieldFillable() const; - void set_default_value(const std::string& value) { default_value_ = value; } - const std::string& default_value() const { return default_value_; } - void set_initial_value_hash(uint32_t value) { initial_value_hash_ = value; } base::Optional<uint32_t> initial_value_hash() { return initial_value_hash_; } @@ -181,14 +184,17 @@ class AutofillField : public FormFieldData { void NormalizePossibleTypesValidities(); private: + explicit AutofillField(FieldSignature field_signature); + // Whether the heuristics or server predict a credit card field. bool IsCreditCardPrediction() const; + base::Optional<FieldSignature> field_signature_; // The unique name of this field, generated by Autofill. base::string16 unique_name_; // The type of the field, as determined by the Autofill server. - ServerFieldType server_type_; + ServerFieldType server_type_ = NO_SERVER_DATA; // The possible types of the field, as determined by the Autofill server, // including |server_type_| as the first item. @@ -200,7 +206,7 @@ class AutofillField : public FormFieldData { base::Optional<PasswordRequirementsSpec> password_requirements_; // The type of the field, as determined by the local heuristics. - ServerFieldType heuristic_type_; + ServerFieldType heuristic_type_ = UNKNOWN_TYPE; // The type of the field. Overrides all other types (html_type_, // heuristic_type_, server_type_). @@ -209,11 +215,11 @@ class AutofillField : public FormFieldData { AutofillType overall_type_; // The type of the field, as specified by the site author in HTML. - HtmlFieldType html_type_; + HtmlFieldType html_type_ = HTML_TYPE_UNSPECIFIED; // The "mode" of the field, as specified by the site author in HTML. // Currently this is used to distinguish between billing and shipping fields. - HtmlFieldMode html_mode_; + HtmlFieldMode html_mode_ = HTML_MODE_NONE; // The set of possible types for this field. ServerFieldTypeSet possible_types_; @@ -222,10 +228,7 @@ class AutofillField : public FormFieldData { ServerFieldTypeValidityStatesMap possible_types_validities_; // Used to track whether this field is a phone prefix or suffix. - PhonePart phone_part_; - - // The default value returned by the Autofill server. - std::string default_value_; + PhonePart phone_part_ = IGNORED; // A low-entropy hash of the field's initial value before user-interactions or // automatic fillings. This field is used to detect static placeholders. @@ -233,13 +236,13 @@ class AutofillField : public FormFieldData { // Used to hold the position of the first digit to be copied as a substring // from credit card number. - size_t credit_card_number_offset_; + size_t credit_card_number_offset_ = 0; // Whether the field was autofilled then later edited. - bool previously_autofilled_; + bool previously_autofilled_ = false; // Whether the field should be filled when it is not the highlighted field. - bool only_fill_when_focused_; + bool only_fill_when_focused_ = false; // The parseable name attribute, with unnecessary information removed (such as // a common prefix shared with other fields). Will be used for heuristics @@ -247,15 +250,17 @@ class AutofillField : public FormFieldData { base::string16 parseable_name_; // The type of password generation event, if it happened. - AutofillUploadContents::Field::PasswordGenerationType generation_type_; + AutofillUploadContents::Field::PasswordGenerationType generation_type_ = + AutofillUploadContents::Field::NO_GENERATION; // Whether the generated password was changed by user. - bool generated_password_changed_; + bool generated_password_changed_ = false; // The vote type, if the autofill type is USERNAME or any password vote. // Otherwise, the field is ignored. |vote_type_| provides context as to what // triggered the vote. - AutofillUploadContents::Field::VoteType vote_type_; + AutofillUploadContents::Field::VoteType vote_type_ = + AutofillUploadContents::Field::NO_INFORMATION; DISALLOW_COPY_AND_ASSIGN(AutofillField); }; diff --git a/chromium/components/autofill/core/browser/autofill_handler.cc b/chromium/components/autofill/core/browser/autofill_handler.cc index 065949cfb27..057fda666c7 100644 --- a/chromium/components/autofill/core/browser/autofill_handler.cc +++ b/chromium/components/autofill/core/browser/autofill_handler.cc @@ -8,7 +8,10 @@ #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/logging/log_manager.h" #include "components/autofill/core/common/autofill_data_validation.h" +#include "components/autofill/core/common/autofill_internals/log_message.h" +#include "components/autofill/core/common/autofill_internals/logging_scope.h" #include "components/autofill/core/common/autofill_payments_features.h" +#include "components/autofill/core/common/autofill_tick_clock.h" #include "components/autofill/core/common/signatures_util.h" #include "ui/gfx/geometry/rect_f.h" @@ -82,34 +85,27 @@ void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms, // the pointer values. std::set<FormSignature> new_form_signatures; for (const FormData& form : forms) { - const auto parse_form_start_time = TimeTicks::Now(); + const auto parse_form_start_time = AutofillTickClock::NowTicks(); FormStructure* cached_form_structure = nullptr; FormStructure* form_structure = nullptr; // Try to find the FormStructure that corresponds to |form| if the form // contains credit card fields only. // |cached_form_structure| may still be nullptr after this call. - if (base::FeatureList::IsEnabled(features::kAutofillImportDynamicForms)) { - ignore_result(FindCachedForm(form, &cached_form_structure)); - bool only_contains_credit_card_fields = true; - if (cached_form_structure) { - for (const FormType& form_type : - cached_form_structure->GetFormTypes()) { - if (form_type != CREDIT_CARD_FORM) { - only_contains_credit_card_fields = false; - break; - } + ignore_result(FindCachedForm(form, &cached_form_structure)); + if (cached_form_structure) { + for (const FormType& form_type : cached_form_structure->GetFormTypes()) { + if (form_type != CREDIT_CARD_FORM) { + cached_form_structure = nullptr; + break; } } - if (!only_contains_credit_card_fields) { - cached_form_structure = nullptr; - } } if (!ParseForm(form, cached_form_structure, &form_structure)) continue; DCHECK(form_structure); new_form_signatures.insert(form_structure->form_signature()); - AutofillMetrics::LogParseFormTiming(TimeTicks::Now() - + AutofillMetrics::LogParseFormTiming(AutofillTickClock::NowTicks() - parse_form_start_time); } @@ -274,12 +270,17 @@ bool AutofillHandler::ParseForm(const FormData& form, const FormStructure* cached_form, FormStructure** parsed_form_structure) { DCHECK(parsed_form_structure); - if (form_structures_.size() >= kAutofillHandlerMaxFormCacheSize) + if (form_structures_.size() >= kAutofillHandlerMaxFormCacheSize) { + if (log_manager_) { + log_manager_->Log() << LoggingScope::kAbortParsing + << LogMessage::kAbortParsingTooManyForms << form; + } return false; + } auto form_structure = std::make_unique<FormStructure>(form); form_structure->ParseFieldTypesFromAutocompleteAttributes(); - if (!form_structure->ShouldBeParsed()) + if (!form_structure->ShouldBeParsed(log_manager_)) return false; if (cached_form) { @@ -291,9 +292,8 @@ bool AutofillHandler::ParseForm(const FormData& form, if (observer_for_testing_) observer_for_testing_->OnFormParsed(); - if (form_structure.get()->value_from_dynamic_change_form()) { + if (form_structure.get()->value_from_dynamic_change_form()) value_from_dynamic_change_form_ = true; - } } form_structure->DetermineHeuristicTypes(log_manager_); diff --git a/chromium/components/autofill/core/browser/autofill_internals_service.cc b/chromium/components/autofill/core/browser/autofill_internals_service.cc deleted file mode 100644 index 3f21b7db1d7..00000000000 --- a/chromium/components/autofill/core/browser/autofill_internals_service.cc +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/autofill/core/browser/autofill_internals_service.h" - -namespace autofill { - -LogBuffer& operator<<(LogBuffer& buf, LoggingScope scope) { - if (!buf.active()) - return buf; - return buf << Tag{"div"} << Attrib{"scope", LoggingScopeToString(scope)} - << Attrib{"class", "log-entry"}; -} - -LogBuffer& operator<<(LogBuffer& buf, LogMessage message) { - if (!buf.active()) - return buf; - return buf << Tag{"div"} << Attrib{"message", LogMessageToString(message)} - << Attrib{"class", "log-message"} << LogMessageValue(message); -} - -} // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_internals_service.h b/chromium/components/autofill/core/browser/autofill_internals_service.h deleted file mode 100644 index b5c81130d26..00000000000 --- a/chromium/components/autofill/core/browser/autofill_internals_service.h +++ /dev/null @@ -1,24 +0,0 @@ -// 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. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_INTERNALS_SERVICE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_INTERNALS_SERVICE_H_ - -#include "base/macros.h" -#include "components/autofill/core/browser/logging/log_buffer.h" -#include "components/autofill/core/browser/logging/log_router.h" -#include "components/autofill/core/common/autofill_internals/log_message.h" -#include "components/autofill/core/common/autofill_internals/logging_scope.h" - -namespace autofill { - -// TODO(crbug.com/928595) This is a temporary home for these operations. -// Find a properly named file. -LogBuffer& operator<<(LogBuffer& buf, LoggingScope scope); - -LogBuffer& operator<<(LogBuffer& buf, LogMessage message); - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_INTERNALS_SERVICE_H_ diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc index 98281bbf87f..a23e3c536e6 100644 --- a/chromium/components/autofill/core/browser/autofill_manager.cc +++ b/chromium/components/autofill/core/browser/autofill_manager.cc @@ -42,7 +42,6 @@ #include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/autofill_external_delegate.h" #include "components/autofill/core/browser/autofill_field.h" -#include "components/autofill/core/browser/autofill_internals_service.h" #include "components/autofill/core/browser/autofill_manager_test_delegate.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/autofill_type.h" @@ -68,9 +67,12 @@ #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_data_validation.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_internals/log_message.h" +#include "components/autofill/core/common/autofill_internals/logging_scope.h" #include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" +#include "components/autofill/core/common/autofill_tick_clock.h" #include "components/autofill/core/common/autofill_util.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_data_predictions.h" @@ -345,6 +347,17 @@ AutofillField* GetBestPossibleCVCField( return HeuristicallyFindCVCField(form_structure); } +// Some autofill types are detected based on values and not based on form +// features. We may decide that it's an autofill form after submission. +bool ContainsAutofillableValue(const autofill::FormStructure& form) { + return std::any_of(form.begin(), form.end(), + [](const std::unique_ptr<autofill::AutofillField>& field) { + return base::Contains(field->possible_types(), + UPI_VPA) || + IsUPIVirtualPaymentAddress(field->value); + }); +} + } // namespace AutofillManager::FillingContext::FillingContext() = default; @@ -587,8 +600,10 @@ void AutofillManager::OnFormSubmittedImpl(const FormData& form, enable_ablation_logging_, sync_state_, *submitted_form); } - if (!submitted_form->IsAutofillable()) + if (!submitted_form->IsAutofillable() && + !ContainsAutofillableValue(*submitted_form)) { return; + } // Update Personal Data with the form's submitted data. // Also triggers offering local/upload credit card save, if applicable. @@ -660,8 +675,8 @@ bool AutofillManager::MaybeStartVoteUploadProcess( base::BindOnce(&AutofillManager::UploadFormDataAsyncCallback, weak_ptr_factory_.GetWeakPtr(), base::Owned(form_structure.release()), - initial_interaction_timestamp_, base::TimeTicks::Now(), - observed_submission)); + initial_interaction_timestamp_, + AutofillTickClock::NowTicks(), observed_submission)); return true; } @@ -927,7 +942,7 @@ void AutofillManager::FillOrPreviewProfileForm( auto filling_context = std::make_unique<FillingContext>(); filling_context->temp_data_model = profile; filling_context->filled_field_name = autofill_field->unique_name(); - filling_context->original_fill_time = base::TimeTicks::Now(); + filling_context->original_fill_time = AutofillTickClock::NowTicks(); entry = std::move(filling_context); } } @@ -993,10 +1008,13 @@ void AutofillManager::OnFocusNoLongerOnForm() { #if defined(OS_CHROMEOS) // There is no way of determining whether ChromeVox is in use, so assume it's // being used. - external_delegate_->OnAutofillAvailabilityEvent(false); + external_delegate_->OnAutofillAvailabilityEvent( + mojom::AutofillState::kNoSuggestions); #else - if (external_delegate_->HasActiveScreenReader()) - external_delegate_->OnAutofillAvailabilityEvent(false); + if (external_delegate_->HasActiveScreenReader()) { + external_delegate_->OnAutofillAvailabilityEvent( + mojom::AutofillState::kNoSuggestions); + } #endif } @@ -1018,8 +1036,10 @@ void AutofillManager::OnFocusOnFormFieldImpl(const FormData& form, GetAvailableSuggestions(form, field, &suggestions, &context); external_delegate_->OnAutofillAvailabilityEvent( - context.suppress_reason == SuppressReason::kNotSuppressed && - !suggestions.empty()); + (context.suppress_reason == SuppressReason::kNotSuppressed && + !suggestions.empty()) + ? mojom::AutofillState::kAutofillAvailable + : mojom::AutofillState::kNoSuggestions); } void AutofillManager::OnSelectControlDidChangeImpl( @@ -1355,6 +1375,9 @@ void AutofillManager::OnSuggestionsReturned( int query_id, bool autoselect_first_suggestion, const std::vector<Suggestion>& suggestions) { + external_delegate_->OnAutofillAvailabilityEvent( + !suggestions.empty() ? mojom::AutofillState::kAutocompleteAvailable + : mojom::AutofillState::kNoSuggestions); external_delegate_->OnSuggestionsReturned(query_id, suggestions, autoselect_first_suggestion); } @@ -2199,7 +2222,7 @@ bool AutofillManager::ShouldTriggerRefill(const FormStructure& form_structure) { form_structure); FillingContext* filling_context = itr->second.get(); - base::TimeTicks now = base::TimeTicks::Now(); + base::TimeTicks now = AutofillTickClock::NowTicks(); base::TimeDelta delta = now - filling_context->original_fill_time; if (filling_context->attempted_refill && diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h index 905f5b8ff4a..d0954dea221 100644 --- a/chromium/components/autofill/core/browser/autofill_manager.h +++ b/chromium/components/autofill/core/browser/autofill_manager.h @@ -312,9 +312,6 @@ class AutofillManager : public AutofillHandler, } // Exposed for testing. - AutofillExternalDelegate* external_delegate() { return external_delegate_; } - - // Exposed for testing. void set_download_manager(AutofillDownloadManager* manager) { download_manager_.reset(manager); } @@ -673,6 +670,8 @@ class AutofillManager : public AutofillHandler, CreditCardSelectedFormEvents); FRIEND_TEST_ALL_PREFIXES(AutofillMetricsIFrameTest, CreditCardFilledFormEvents); + FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, + CreditCardUnmaskingPreflightCall); FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, CreditCardGetRealPanDuration); FRIEND_TEST_ALL_PREFIXES(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents); diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc index 3aee9d14555..57355a6eeeb 100644 --- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc @@ -58,6 +58,7 @@ #include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" +#include "components/autofill/core/common/autofill_tick_clock.h" #include "components/autofill/core/common/autofill_util.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" @@ -561,6 +562,13 @@ class AutofillManagerTest : public testing::Test { autofill_manager_->credit_card_access_manager_->cvc_authenticator_ ->full_card_request_.get(); DCHECK(full_card_request); + + // Mock user response. + payments::FullCardRequest::UserProvidedUnmaskDetails details; + details.cvc = base::ASCIIToUTF16("123"); + full_card_request->OnUnmaskPromptAccepted(details); + + // Mock payments response. payments::PaymentsClient::UnmaskResponseDetails response; full_card_request->OnDidGetRealPan(result, response.with_real_pan(real_pan)); @@ -5816,8 +5824,8 @@ TEST_F(AutofillManagerTest, OnTextFieldDidChangeAndUnfocus_Upload) { form.fields[1].value = ASCIIToUTF16("Presley"); form.fields[2].value = ASCIIToUTF16("theking@gmail.com"); // Simulate editing a field. - autofill_manager_->OnTextFieldDidChange(form, form.fields.front(), - gfx::RectF(), base::TimeTicks::Now()); + autofill_manager_->OnTextFieldDidChange( + form, form.fields.front(), gfx::RectF(), AutofillTickClock::NowTicks()); // Simulate lost of focus on the form. autofill_manager_->OnFocusNoLongerOnForm(); @@ -5866,8 +5874,8 @@ TEST_F(AutofillManagerTest, OnTextFieldDidChangeAndNavigation_Upload) { form.fields[1].value = ASCIIToUTF16("Presley"); form.fields[2].value = ASCIIToUTF16("theking@gmail.com"); // Simulate editing a field. - autofill_manager_->OnTextFieldDidChange(form, form.fields.front(), - gfx::RectF(), base::TimeTicks::Now()); + autofill_manager_->OnTextFieldDidChange( + form, form.fields.front(), gfx::RectF(), AutofillTickClock::NowTicks()); // Simulate a navigation so that the pending form is uploaded. autofill_manager_->Reset(); @@ -5915,7 +5923,8 @@ TEST_F(AutofillManagerTest, OnDidFillAutofillFormDataAndUnfocus_Upload) { form.fields[0].value = ASCIIToUTF16("Elvis"); form.fields[1].value = ASCIIToUTF16("Presley"); form.fields[2].value = ASCIIToUTF16("theking@gmail.com"); - autofill_manager_->OnDidFillAutofillFormData(form, base::TimeTicks::Now()); + autofill_manager_->OnDidFillAutofillFormData(form, + AutofillTickClock::NowTicks()); // Simulate lost of focus on the form. autofill_manager_->OnFocusNoLongerOnForm(); @@ -7670,6 +7679,58 @@ TEST_F(AutofillManagerTest, HasSubstr("Autofill.FormEvents.Address")))); } +// Test that we import data when the field type is determined by the value and +// without any heuristics on the attributes. +TEST_F(AutofillManagerTest, ImportDataWhenValueDetected) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kAutofillSaveAndFillVPA); + + FormData form; + form.url = GURL("https://wwww.foo.com"); + + FormFieldData field; + test::CreateTestFormField("VPA:", "vpa", "", "text", &field); + form.fields.push_back(field); + + FormsSeen({form}); + autofill_manager_->SetExpectedSubmittedFieldTypes({{UPI_VPA}}); + autofill_manager_->SetExpectedObservedSubmission(true); + autofill_manager_->SetCallParentUploadFormData(true); + form.submission_event = + mojom::SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + form.fields[0].value = ASCIIToUTF16("user@indianbank"); + FormSubmitted(form); + + EXPECT_EQ(1, personal_data_.num_times_save_vpa_called()); +} + +// Test that we do not import VPA data when in incognito. +TEST_F(AutofillManagerTest, DontImportVPAWhenIncognito) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kAutofillSaveAndFillVPA); + autofill_driver_->SetIsIncognito(true); + + FormData form; + form.url = GURL("https://wwww.foo.com"); + + FormFieldData field; + test::CreateTestFormField("VPA:", "vpa", "", "text", &field); + form.fields.push_back(field); + + FormsSeen({form}); + autofill_manager_->SetExpectedSubmittedFieldTypes({{UPI_VPA}}); + autofill_manager_->SetExpectedObservedSubmission(true); + autofill_manager_->SetCallParentUploadFormData(true); + form.submission_event = + mojom::SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + form.fields[0].value = ASCIIToUTF16("user@indianbank"); + FormSubmitted(form); + + EXPECT_EQ(0, personal_data_.num_times_save_vpa_called()); +} + // Test param indicates if there is an active screen reader. class OnFocusOnFormFieldTest : public AutofillManagerTest, public testing::WithParamInterface<bool> { diff --git a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc index a845b3daed5..b3d5aff7e5c 100644 --- a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc @@ -20,6 +20,7 @@ #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/data_driven_test.h" +#include "components/autofill/core/browser/data_model/autofill_profile_comparator.h" #include "components/autofill/core/browser/form_data_importer.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/geo/country_names.h" @@ -128,11 +129,9 @@ class PersonalDataManagerMock : public PersonalDataManager { }; PersonalDataManagerMock::PersonalDataManagerMock() - : PersonalDataManager("en-US") { -} + : PersonalDataManager("en-US") {} -PersonalDataManagerMock::~PersonalDataManagerMock() { -} +PersonalDataManagerMock::~PersonalDataManagerMock() {} void PersonalDataManagerMock::Reset() { profiles_.clear(); @@ -141,8 +140,8 @@ void PersonalDataManagerMock::Reset() { std::string PersonalDataManagerMock::SaveImportedProfile( const AutofillProfile& profile) { std::vector<AutofillProfile> profiles; - std::string merged_guid = - MergeProfile(profile, &profiles_, "en-US", &profiles); + std::string merged_guid = AutofillProfileComparator::MergeProfile( + profile, &profiles_, "en-US", &profiles); if (merged_guid == profile.guid()) profiles_.push_back(std::make_unique<AutofillProfile>(profile)); return merged_guid; @@ -202,8 +201,7 @@ AutofillMergeTest::AutofillMergeTest() : DataDrivenTest(GetTestDataDir()) { } } -AutofillMergeTest::~AutofillMergeTest() { -} +AutofillMergeTest::~AutofillMergeTest() {} void AutofillMergeTest::SetUp() { test::DisableSystemServices(nullptr); @@ -247,8 +245,7 @@ void AutofillMergeTest::MergeProfiles(const std::string& profiles, do { ++separator_pos; } while (separator_pos < line.size() && line[separator_pos] == ' '); - base::string16 value = - base::UTF8ToUTF16(line.substr(separator_pos)); + base::string16 value = base::UTF8ToUTF16(line.substr(separator_pos)); base::ReplaceFirstSubstringAfterOffset( &value, 0, base::ASCIIToUTF16("\\n"), base::ASCIIToUTF16("\n")); @@ -279,12 +276,15 @@ void AutofillMergeTest::MergeProfiles(const std::string& profiles, // Import the profile. std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> unused_imported_vpa; form_data_importer_->ImportFormData(form_structure, true, // address autofill enabled, true, // credit card autofill enabled false, // should return local card - &imported_credit_card); + &imported_credit_card, + &unused_imported_vpa); EXPECT_FALSE(imported_credit_card); + EXPECT_FALSE(unused_imported_vpa.has_value()); // Clear the |form| to start a new profile. form.fields.clear(); diff --git a/chromium/components/autofill/core/browser/autofill_metrics.cc b/chromium/components/autofill/core/browser/autofill_metrics.cc index e2ad2699390..ad4203a2a02 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics.cc +++ b/chromium/components/autofill/core/browser/autofill_metrics.cc @@ -22,6 +22,7 @@ #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_prefs.h" +#include "components/autofill/core/common/autofill_tick_clock.h" #include "components/autofill/core/common/form_data.h" #include "services/metrics/public/cpp/metrics_utils.h" #include "services/metrics/public/cpp/ukm_builders.h" @@ -767,10 +768,17 @@ void AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel( histogram_name += "Local"; } - base::UmaHistogramEnumeration( - security_state::GetSecurityLevelHistogramName( - histogram_name, security_level), - metric, NUM_SAVE_CARD_PROMPT_METRICS); + base::UmaHistogramEnumeration(security_state::GetSecurityLevelHistogramName( + histogram_name, security_level), + metric, NUM_SAVE_CARD_PROMPT_METRICS); +} + +// static +void AutofillMetrics::LogCreditCardUploadFeedbackMetric( + CreditCardUploadFeedbackMetric metric) { + DCHECK_LT(metric, NUM_CREDIT_CARD_UPLOAD_FEEDBACK_METRICS); + UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardUploadFeedback", metric, + NUM_CREDIT_CARD_UPLOAD_FEEDBACK_METRICS); } // static @@ -922,6 +930,117 @@ void AutofillMetrics::LogSaveCardWithFirstAndLastNameComplete(bool is_local) { } // static +void AutofillMetrics::LogCardUnmaskDurationAfterWebauthn( + const base::TimeDelta& duration, + AutofillClient::PaymentsRpcResult result) { + std::string suffix; + switch (result) { + case AutofillClient::SUCCESS: + suffix = "Success"; + break; + case AutofillClient::TRY_AGAIN_FAILURE: + case AutofillClient::PERMANENT_FAILURE: + suffix = "Failure"; + break; + case AutofillClient::NETWORK_ERROR: + suffix = "NetworkError"; + break; + case AutofillClient::NONE: + NOTREACHED(); + return; + } + base::UmaHistogramLongTimes("Autofill.BetterAuth.CardUnmaskDuration.Fido", + duration); + base::UmaHistogramLongTimes( + "Autofill.BetterAuth.CardUnmaskDuration.Fido." + suffix, duration); +} + +// static +void AutofillMetrics::LogCardUnmaskPreflightCalled() { + UMA_HISTOGRAM_BOOLEAN("Autofill.BetterAuth.CardUnmaskPreflightCalled", true); +} + +// static +void AutofillMetrics::LogCardUnmaskPreflightDuration( + const base::TimeDelta& duration) { + base::UmaHistogramLongTimes("Autofill.BetterAuth.CardUnmaskPreflightDuration", + duration); +} + +// static +void AutofillMetrics::LogWebauthnOptChangeCalled( + bool request_to_opt_in, + bool is_checkout_flow, + WebauthnOptInParameters metric) { + if (!request_to_opt_in) { + DCHECK(!is_checkout_flow); + base::UmaHistogramBoolean( + "Autofill.BetterAuth.OptOutCalled.FromSettingsPage", true); + return; + } + + std::string histogram_name = "Autofill.BetterAuth.OptInCalled."; + histogram_name += is_checkout_flow ? "FromCheckoutFlow" : "FromSettingsPage"; + base::UmaHistogramEnumeration(histogram_name, metric); +} + +// static +void AutofillMetrics::LogWebauthnOptInPromoShown(bool is_checkout_flow) { + std::string suffix = + is_checkout_flow ? "FromCheckoutFlow" : "FromSettingsPage"; + base::UmaHistogramBoolean("Autofill.BetterAuth.OptInPromoShown." + suffix, + true); +} + +// static +void AutofillMetrics::LogWebauthnOptInPromoUserDecision( + bool is_checkout_flow, + WebauthnOptInPromoUserDecisionMetric metric) { + std::string suffix = + (is_checkout_flow ? "FromCheckoutFlow" : "FromSettingsPage"); + base::UmaHistogramEnumeration( + "Autofill.BetterAuth.OptInPromoUserDecision." + suffix, metric); +} + +// static +void AutofillMetrics::LogCardUnmaskTypeDecision( + CardUnmaskTypeDecisionMetric metric) { + base::UmaHistogramEnumeration("Autofill.BetterAuth.CardUnmaskTypeDecision", + metric); +} + +// static +void AutofillMetrics::LogUserPerceivedLatencyOnCardSelection( + PreflightCallEvent event, + bool fido_auth_enabled) { + std::string histogram_name = + "Autofill.BetterAuth.UserPerceivedLatencyOnCardSelection."; + histogram_name += fido_auth_enabled ? "OptedIn" : "OptedOut"; + base::UmaHistogramEnumeration(histogram_name, event); +} + +// static +void AutofillMetrics::LogWebauthnResult(WebauthnFlowEvent event, + WebauthnResultMetric metric) { + std::string histogram_name = "Autofill.BetterAuth.WebauthnResult."; + switch (event) { + case WebauthnFlowEvent::kImmediateAuthentication: + histogram_name += "ImmediateAuthentication"; + break; + case WebauthnFlowEvent::kAuthenticationAfterCvc: + histogram_name += "AuthenticationAfterCVC"; + break; + case WebauthnFlowEvent::kCheckoutOptIn: + histogram_name += "CheckoutOptIn"; + break; + case WebauthnFlowEvent::kSettingsPageOptIn: + histogram_name += "SettingsPageOptIn"; + break; + } + base::UmaHistogramEnumeration(histogram_name, metric); +} + +// static void AutofillMetrics::LogUnmaskPromptEvent(UnmaskPromptEvent event) { UMA_HISTOGRAM_ENUMERATION("Autofill.UnmaskPrompt.Events", event, NUM_UNMASK_PROMPT_EVENTS); @@ -1186,10 +1305,9 @@ void AutofillMetrics::LogUserHappinessBySecurityLevel( return; } - base::UmaHistogramEnumeration( - security_state::GetSecurityLevelHistogramName( - histogram_name, security_level), - metric, NUM_USER_HAPPINESS_METRICS); + base::UmaHistogramEnumeration(security_state::GetSecurityLevelHistogramName( + histogram_name, security_level), + metric, NUM_USER_HAPPINESS_METRICS); } // static @@ -1974,8 +2092,9 @@ int64_t AutofillMetrics::FormInteractionsUkmLogger::MillisecondsSinceFormParsed( const base::TimeTicks& form_parsed_timestamp) const { DCHECK(!form_parsed_timestamp.is_null()); // Use the pinned timestamp as the current time if it's set. - base::TimeTicks now = - pinned_timestamp_.is_null() ? base::TimeTicks::Now() : pinned_timestamp_; + base::TimeTicks now = pinned_timestamp_.is_null() + ? AutofillTickClock::NowTicks() + : pinned_timestamp_; return ukm::GetExponentialBucketMin( (now - form_parsed_timestamp).InMilliseconds(), @@ -1987,7 +2106,7 @@ AutofillMetrics::UkmTimestampPin::UkmTimestampPin( : logger_(logger) { DCHECK(logger_); DCHECK(!logger_->has_pinned_timestamp()); - logger_->set_pinned_timestamp(base::TimeTicks::Now()); + logger_->set_pinned_timestamp(AutofillTickClock::NowTicks()); } AutofillMetrics::UkmTimestampPin::~UkmTimestampPin() { diff --git a/chromium/components/autofill/core/browser/autofill_metrics.h b/chromium/components/autofill/core/browser/autofill_metrics.h index 7ebd53ccb73..278be51a96c 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics.h +++ b/chromium/components/autofill/core/browser/autofill_metrics.h @@ -6,6 +6,7 @@ #define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_METRICS_H_ #include <stddef.h> +#include <memory> #include <set> #include <string> #include <utility> @@ -119,6 +120,8 @@ class AutofillMetrics { // All the required conditions were satisfied even though the form is // dynamic changed. UPLOAD_OFFERED_FROM_DYNAMIC_CHANGE_FORM = 1 << 17, + // The legal message was invalid. + UPLOAD_NOT_OFFERED_INVALID_LEGAL_MESSAGE = 1 << 18, // Update |kNumCardUploadDecisionMetrics| when adding new enum here. }; @@ -299,6 +302,17 @@ class AutofillMetrics { NUM_SAVE_CARD_PROMPT_METRICS, }; + enum CreditCardUploadFeedbackMetric { + // The loading indicator animation which indicates uploading is in progress + // is successfully shown. + CREDIT_CARD_UPLOAD_FEEDBACK_LOADING_ANIMATION_SHOWN, + // The credit card icon with the saving failure badge is shown. + CREDIT_CARD_UPLOAD_FEEDBACK_FAILURE_ICON_SHOWN, + // The failure icon is clicked and the save card failure bubble is shown. + CREDIT_CARD_UPLOAD_FEEDBACK_FAILURE_BUBBLE_SHOWN, + NUM_CREDIT_CARD_UPLOAD_FEEDBACK_METRICS, + }; + // Metrics to measure user interaction with the Manage Cards view // shown when user clicks on the save card icon after accepting // to save a card. @@ -492,7 +506,9 @@ class AutofillMetrics { NOT_OFFERED_SINGLE_LOCAL_CARD = 7, // User used an unsupported local card, we will abort the migration. NOT_OFFERED_USE_UNSUPPORTED_LOCAL_CARD = 8, - kMaxValue = NOT_OFFERED_USE_UNSUPPORTED_LOCAL_CARD, + // Legal message was invalid, we will abort the migration. + NOT_OFFERED_INVALID_LEGAL_MESSAGE = 9, + kMaxValue = NOT_OFFERED_INVALID_LEGAL_MESSAGE, }; // Metrics to track events when local credit card migration is offered. @@ -680,6 +696,79 @@ class AutofillMetrics { NUM_UNMASK_PROMPT_EVENTS, }; + // Events related to user-perceived latency due to GetDetailsForGetRealPan + // call. + enum class PreflightCallEvent { + // Returned before card chosen. + kPreflightCallReturnedBeforeCardChosen = 0, + // Did not return before card was chosen. When opted-in, this means + // the UI had to wait for the call to return. When opted-out, this means we + // did not offer to opt-in. + kCardChosenBeforePreflightCallReturned = 1, + // Preflight call was irrelevant; skipped waiting. + kDidNotChooseMaskedCard = 2, + kMaxValue = kDidNotChooseMaskedCard, + }; + + // Metric for tracking which authentication method was used for a user with + // FIDO authentication enabled. + enum class CardUnmaskTypeDecisionMetric { + // Only WebAuthn prompt was shown. + kFidoOnly = 0, + // CVC authentication was required in addition to WebAuthn. + kCvcThenFido = 1, + kMaxValue = kCvcThenFido, + }; + + // Possible scenarios where a WebAuthn prompt may show. + enum class WebauthnFlowEvent { + // WebAuthn is immediately prompted for unmasking. + kImmediateAuthentication = 0, + // WebAuthn is prompted after a CVC check. + kAuthenticationAfterCvc = 1, + // WebAuthn is prompted after being offered to opt-in from a checkout flow. + kCheckoutOptIn = 2, + // WebAuthn is prompted after being offered to opt-in from the settings + // page. + kSettingsPageOptIn = 3, + kMaxValue = kSettingsPageOptIn, + }; + + // The result of a WebAuthn user-verification prompt. + enum class WebauthnResultMetric { + // User-verification succeeded. + kSuccess = 0, + // Other checks failed (e.g. invalid domain, algorithm unsupported, etc.) + kOtherError = 1, + // User either failed verification or cancelled. + kNotAllowedError = 2, + kMaxValue = kNotAllowedError, + }; + + // The user decision for the WebAuthn opt-in promo. + enum class WebauthnOptInPromoUserDecisionMetric { + // User accepted promo. + kAccepted = 0, + // User immediately declined promo. + kDeclinedImmediately = 1, + // Once user accepts the dialog, a round-trip call to Payments is sent, + // which is required for user authentication. The user has the option to + // cancel the dialog before the round-trip call is returned. + kDeclinedAfterAccepting = 2, + kMaxValue = kDeclinedAfterAccepting, + }; + + // The parameters with which opt change was called. + enum class WebauthnOptInParameters { + // Call made to fetch a challenge. + kFetchingChallenge = 0, + // Call made with signature of creation challenge. + kWithCreationChallenge = 1, + // Call made with signature of request challenge. + kWithRequestChallenge = 2, + kMaxValue = kWithRequestChallenge, + }; + // Possible results of Payments RPCs. enum PaymentsRpcResult { // Request succeeded. @@ -955,6 +1044,8 @@ class AutofillMetrics { SaveCardPromptMetric metric, bool is_uploading, security_state::SecurityLevel security_level); + static void LogCreditCardUploadFeedbackMetric( + CreditCardUploadFeedbackMetric metric); static void LogManageCardsPromptMetric(ManageCardsPromptMetric metric, bool is_uploading); static void LogScanCreditCardPromptMetric(ScanCreditCardPromptMetric metric); @@ -1028,6 +1119,48 @@ class AutofillMetrics { static void LogUserHappinessByProfileFormType(UserHappinessMetric metric, uint32_t profile_form_bitmask); + // Logs the card fetch latency after a WebAuthn prompt. + static void LogCardUnmaskDurationAfterWebauthn( + const base::TimeDelta& duration, + AutofillClient::PaymentsRpcResult result); + + // Logs the count of calls to PaymentsClient::GetUnmaskDetails() (aka + // GetDetailsForGetRealPan). + static void LogCardUnmaskPreflightCalled(); + + // Logs the duration of the PaymentsClient::GetUnmaskDetails() call (aka + // GetDetailsForGetRealPan). + static void LogCardUnmaskPreflightDuration(const base::TimeDelta& duration); + + // Logs the count of calls to PaymentsClient::OptChange() (aka + // UpdateAutofillUserPreference). + static void LogWebauthnOptChangeCalled(bool request_to_opt_in, + bool is_checkout_flow, + WebauthnOptInParameters metric); + + // Logs the number of times the opt-in promo for enabling FIDO authentication + // for card unmasking has been shown. + static void LogWebauthnOptInPromoShown(bool is_checkout_flow); + + // Logs the user response to the opt-in promo for enabling FIDO authentication + // for card unmasking. + static void LogWebauthnOptInPromoUserDecision( + bool is_checkout_flow, + WebauthnOptInPromoUserDecisionMetric metric); + + // Logs which unmask type was used for a user with FIDO authentication + // enabled. + static void LogCardUnmaskTypeDecision(CardUnmaskTypeDecisionMetric metric); + + // Logs the existence of any user-perceived latency between selecting a Google + // Payments server card and seeing a card unmask prompt. + static void LogUserPerceivedLatencyOnCardSelection(PreflightCallEvent event, + bool fido_auth_enabled); + + // Logs the result of a WebAuthn prompt. + static void LogWebauthnResult(WebauthnFlowEvent event, + WebauthnResultMetric metric); + // Logs |event| to the unmask prompt events histogram. static void LogUnmaskPromptEvent(UnmaskPromptEvent event); @@ -1258,13 +1391,6 @@ class AutofillMetrics { // autofilled to support synthetic fields. static void LogHiddenOrPresentationalSelectFieldsFilled(); - // Logs the the |ukm_entry_name| with the specified |url| and the specified - // |metrics|. Returns whether the ukm was sucessfully logged. - static bool LogUkm(ukm::UkmRecorder* ukm_recorder, - const GURL& url, - const std::string& ukm_entry_name, - const std::vector<std::pair<const char*, int>>& metrics); - // Converts form type to bit vector to store in UKM. static int64_t FormTypesToBitVector(const std::set<FormType>& form_types); @@ -1288,7 +1414,7 @@ class AutofillMetrics { private: static void Log(AutocompleteEvent event); - static const int kNumCardUploadDecisionMetrics = 18; + static const int kNumCardUploadDecisionMetrics = 19; DISALLOW_IMPLICIT_CONSTRUCTORS(AutofillMetrics); }; diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc index 33cc102717a..1eac2646442 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc @@ -21,6 +21,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/time/time.h" +#include "build/build_config.h" #include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/autofill_external_delegate.h" #include "components/autofill/core/browser/autofill_test_utils.h" @@ -28,6 +29,7 @@ #include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h" #include "components/autofill/core/browser/metrics/form_events.h" #include "components/autofill/core/browser/mock_autocomplete_history_manager.h" +#include "components/autofill/core/browser/payments/credit_card_access_manager.h" #include "components/autofill/core/browser/payments/test_credit_card_save_manager.h" #include "components/autofill/core/browser/payments/test_payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" @@ -35,6 +37,7 @@ #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_autofill_manager.h" +#include "components/autofill/core/browser/test_autofill_tick_clock.h" #include "components/autofill/core/browser/test_form_data_importer.h" #include "components/autofill/core/browser/test_form_structure.h" #include "components/autofill/core/browser/test_personal_data_manager.h" @@ -43,6 +46,8 @@ #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" +#include "components/autofill/core/common/autofill_tick_clock.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" #include "components/prefs/pref_service.h" @@ -57,6 +62,10 @@ #include "ui/gfx/geometry/rect.h" #include "url/gurl.h" +#if !defined(OS_IOS) +#include "components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h" +#endif + using base::ASCIIToUTF16; using base::Bucket; using base::TimeTicks; @@ -268,6 +277,10 @@ class AutofillMetricsTest : public testing::Test { bool include_masked_server_credit_card, bool include_full_server_credit_card); + // If set to true, then user is capable of using FIDO authentication for card + // unmasking. + void SetFidoEligibility(bool is_verifiable); + // Mocks a RPC response from payments. void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result, const std::string& real_pan); @@ -343,6 +356,13 @@ void AutofillMetricsTest::SetUp() { autofill_manager_.get(), autofill_driver_.get()); autofill_manager_->SetExternalDelegate(external_delegate_.get()); +#if !defined(OS_IOS) + autofill_manager_->credit_card_access_manager() + ->set_fido_authenticator_for_testing( + std::make_unique<TestCreditCardFIDOAuthenticator>( + autofill_driver_.get(), &autofill_client_)); +#endif + // Initialize the TestPersonalDataManager with some default data. CreateTestAutofillProfiles(); } @@ -392,6 +412,22 @@ void AutofillMetricsTest::RecreateProfile(bool is_server) { personal_data_->Refresh(); } +void AutofillMetricsTest::SetFidoEligibility(bool is_verifiable) { + CreditCardAccessManager* access_manager = + autofill_manager_->credit_card_access_manager(); +#if !defined(OS_IOS) + static_cast<TestCreditCardFIDOAuthenticator*>( + access_manager->GetOrCreateFIDOAuthenticator()) + ->SetUserVerifiable(is_verifiable); +#endif + static_cast<payments::TestPaymentsClient*>( + autofill_client_.GetPaymentsClient()) + ->AllowFidoRegistration(true); + access_manager->is_authentication_in_progress_ = false; + access_manager->can_fetch_unmask_details_.Signal(); + access_manager->is_user_verifiable_ = base::nullopt; +} + void AutofillMetricsTest::OnDidGetRealPan( AutofillClient::PaymentsRpcResult result, const std::string& real_pan) { @@ -400,6 +436,12 @@ void AutofillMetricsTest::OnDidGetRealPan( ->GetOrCreateCVCAuthenticator() ->full_card_request_.get(); DCHECK(full_card_request); + + // Fake user response. + payments::FullCardRequest::UserProvidedUnmaskDetails details; + details.cvc = base::ASCIIToUTF16("123"); + full_card_request->OnUnmaskPromptAccepted(details); + payments::PaymentsClient::UnmaskResponseDetails response; full_card_request->OnDidGetRealPan(result, response.with_real_pan(real_pan)); } @@ -1809,7 +1851,7 @@ TEST_F(AutofillMetricsTest, TimingMetrics) { // Simulate a OnFormsSeen() call that should trigger the recording. std::vector<FormData> forms; forms.push_back(form); - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); // Because these metrics are related to timing, it is not possible to know in // advance which bucket the sample will fall into, so we just need to make @@ -2655,7 +2697,7 @@ TEST_F(AutofillMetricsTest, base::test::ScopedFeatureList features; features.InitAndEnableFeature( kAutofillEnforceMinRequiredFieldsForHeuristics); - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); autofill_manager_->Reset(); EXPECT_EQ(0ul, test_ukm_recorder_->entries_count()); @@ -2668,7 +2710,7 @@ TEST_F(AutofillMetricsTest, // Expect the "form parsed without field type hints" metric and the // "form loaded" form interaction event to be logged. { - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); autofill_manager_->Reset(); VerifyDeveloperEngagementUkm( @@ -2718,7 +2760,7 @@ TEST_F(AutofillMetricsTest, // Expect the "form parsed without field type hints" metric and the // "form loaded" form interaction event to be logged. { - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); autofill_manager_->Reset(); VerifyDeveloperEngagementUkm( @@ -2760,7 +2802,7 @@ TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) { // interaction event to be logged. { SCOPED_TRACE("VPA is the only hint"); - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); VerifyDeveloperEngagementUkm( test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false, @@ -2777,7 +2819,7 @@ TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) { { SCOPED_TRACE("VPA and other autocomplete hint present"); - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); VerifyDeveloperEngagementUkm( test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false, @@ -3254,7 +3296,7 @@ TEST_F(AutofillMetricsTest, UpiVpaUkmTest) { std::vector<FormData> forms(1, form); { - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); VerifySubmitFormUkm(test_ukm_recorder_, forms.back(), AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, @@ -4252,6 +4294,124 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardFilledFormEvents) { } } +// Test that we log preflight calls for credit card unmasking. +TEST_F(AutofillMetricsTest, CreditCardUnmaskingPreflightCall) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillCreditCardAuthentication); + std::string preflight_call_metric = + "Autofill.BetterAuth.CardUnmaskPreflightCalled"; + std::string preflight_latency_metric = + "Autofill.BetterAuth.CardUnmaskPreflightDuration"; + + // Set up our form data. + FormData form; + FormFieldData field; + std::vector<ServerFieldType> field_types; + test::CreateTestFormField("Credit card", "card", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_NUMBER); + + // Simulate having seen this form on page load. + // |form_structure| will be owned by |autofill_manager_|. + autofill_manager_->AddSeenForm(form, field_types, field_types); + + { + // Create local cards and set user as eligible for FIDO authentication. + base::HistogramTester histogram_tester; + RecreateCreditCards(true /* include_local_credit_card */, + false /* include_masked_server_credit_card */, + false /* include_full_server_credit_card */); + SetFidoEligibility(true); + autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, + form.fields[0]); + // If no masked server cards are available, then no preflight call is made. + histogram_tester.ExpectTotalCount(preflight_call_metric, 0); + histogram_tester.ExpectTotalCount(preflight_latency_metric, 0); + } + + { + // Create masked server cards and set user as ineligible for FIDO + // authentication. + base::HistogramTester histogram_tester; + RecreateCreditCards(false /* include_local_credit_card */, + true /* include_masked_server_credit_card */, + false /* include_full_server_credit_card */); + SetFidoEligibility(false); + autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, + form.fields[0]); + // If user is not verifiable, then no preflight call is made. + histogram_tester.ExpectTotalCount(preflight_call_metric, 0); + histogram_tester.ExpectTotalCount(preflight_latency_metric, 0); + } + + { + // Create full server cards and set user as eligible for FIDO + // authentication. + base::HistogramTester histogram_tester; + RecreateCreditCards(false /* include_local_credit_card */, + false /* include_masked_server_credit_card */, + true /* include_full_server_credit_card */); + SetFidoEligibility(false); + autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, + form.fields[0]); + // If no masked server cards are available, then no preflight call is made. + histogram_tester.ExpectTotalCount(preflight_call_metric, 0); + histogram_tester.ExpectTotalCount(preflight_latency_metric, 0); + } + + { + // Create masked server cards and set user as eligible for FIDO + // authentication. + base::HistogramTester histogram_tester; + RecreateCreditCards(false /* include_local_credit_card */, + true /* include_masked_server_credit_card */, + false /* include_full_server_credit_card */); + SetFidoEligibility(true); + autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, + form.fields[0]); + std::string guid( + "10000000-0000-0000-0000-000000000002"); // masked server card + autofill_manager_->FillOrPreviewForm( + AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(), + autofill_manager_->MakeFrontendID(guid, std::string())); + // Preflight call is made only if a masked server card is available and the + // user is eligible for FIDO authentication (except iOS). +#if defined(OS_IOS) + histogram_tester.ExpectTotalCount(preflight_call_metric, 0); + histogram_tester.ExpectTotalCount(preflight_latency_metric, 0); +#else + histogram_tester.ExpectTotalCount(preflight_call_metric, 1); + histogram_tester.ExpectTotalCount(preflight_latency_metric, 1); +#endif + } + + { + // Create all types of cards and set user as eligible for FIDO + // authentication. + base::HistogramTester histogram_tester; + RecreateCreditCards(true /* include_local_credit_card */, + true /* include_masked_server_credit_card */, + true /* include_full_server_credit_card */); + SetFidoEligibility(true); + autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, + form.fields[0]); + std::string guid( + "10000000-0000-0000-0000-000000000002"); // masked server card + autofill_manager_->FillOrPreviewForm( + AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(), + autofill_manager_->MakeFrontendID(guid, std::string())); + // Preflight call is made only if a masked server card is available and the + // user is eligible for FIDO authentication (except iOS). +#if defined(OS_IOS) + histogram_tester.ExpectTotalCount(preflight_call_metric, 0); + histogram_tester.ExpectTotalCount(preflight_latency_metric, 0); +#else + histogram_tester.ExpectTotalCount(preflight_call_metric, 1); + histogram_tester.ExpectTotalCount(preflight_latency_metric, 1); +#endif + } +} + // Test that we log submitted form events for credit cards. TEST_F(AutofillMetricsTest, CreditCardGetRealPanDuration) { // Creating masked card @@ -4400,12 +4560,10 @@ TEST_P(AutofillMetricsIFrameTest, SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_WRONG_SIZE_CARD, - 1); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_WRONG_SIZE_CARD, 1); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_WRONG_SIZE_CARD, - 1); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_WRONG_SIZE_CARD, 1); } TEST_P(AutofillMetricsIFrameTest, @@ -4447,12 +4605,10 @@ TEST_P(AutofillMetricsIFrameTest, SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_FAIL_LUHN_CHECK_CARD, - 1); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_FAIL_LUHN_CHECK_CARD, 1); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_FAIL_LUHN_CHECK_CARD, - 1); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_FAIL_LUHN_CHECK_CARD, 1); } TEST_P(AutofillMetricsIFrameTest, @@ -4495,12 +4651,10 @@ TEST_P(AutofillMetricsIFrameTest, SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_UNKNOWN_CARD, - 1); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_UNKNOWN_CARD, 1); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_UNKNOWN_CARD, - 1); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_UNKNOWN_CARD, 1); } TEST_P(AutofillMetricsIFrameTest, @@ -4543,12 +4697,10 @@ TEST_P(AutofillMetricsIFrameTest, SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, - 1); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, 1); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, - 1); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, 1); } TEST_P(AutofillMetricsIFrameTest, @@ -4596,27 +4748,22 @@ TEST_P(AutofillMetricsIFrameTest, SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, - 0); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, 0); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, - 0); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_UNKNOWN_CARD, - 0); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_UNKNOWN_CARD, 0); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, - 0); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_NO_CARD, 0); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, - 0); + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, 0); } TEST_F(AutofillMetricsTest, ShouldNotLogFormEventNoCardForAddressForm) { @@ -5020,12 +5167,10 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard", FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE, 1); @@ -5052,12 +5197,10 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 0); } // Reset the autofill manager state and purge UKM logs. @@ -5098,12 +5241,10 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 0); @@ -5130,12 +5271,10 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 0); VerifyUkm( test_ukm_recorder_, form, UkmSuggestionsShownType::kEntryName, @@ -5364,12 +5503,10 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) { FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard", FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE, 1); @@ -5396,12 +5533,10 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) { FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 0); } // Reset the autofill manager state. @@ -5441,12 +5576,10 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) { FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 0); @@ -5473,12 +5606,10 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) { FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.CreditCard", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( credit_card_form_events_frame_histogram_, - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 0); } } @@ -6167,8 +6298,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) { FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 0); @@ -6183,8 +6313,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) { FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 0); // Check if FormEvent UKM is logged properly auto entries = @@ -6308,8 +6437,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) { FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 0); @@ -6324,8 +6452,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) { FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 0); // Check if FormEvent UKM is logged properly auto entries = test_ukm_recorder_->GetEntriesByName(UkmFormEventType::kEntryName); @@ -6358,8 +6485,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) { FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 0); @@ -6374,8 +6500,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) { FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE, 0); histogram_tester.ExpectBucketCount( "Autofill.FormEvents.Address", - FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, - 0); + FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 0); // Check if FormEvent UKM is logged properly auto entries = test_ukm_recorder_->GetEntriesByName(UkmFormEventType::kEntryName); @@ -6566,7 +6691,8 @@ TEST_F(AutofillMetricsTest, AutofillIsDisabledAtPageLoad) { TEST_F(AutofillMetricsTest, DaysSinceLastUse_CreditCard) { base::HistogramTester histogram_tester; CreditCard credit_card; - credit_card.set_use_date(base::Time::Now() - base::TimeDelta::FromDays(21)); + credit_card.set_use_date(AutofillClock::Now() - + base::TimeDelta::FromDays(21)); credit_card.RecordAndLogUse(); histogram_tester.ExpectBucketCount("Autofill.DaysSinceLastUse.CreditCard", 21, 1); @@ -6576,7 +6702,7 @@ TEST_F(AutofillMetricsTest, DaysSinceLastUse_CreditCard) { TEST_F(AutofillMetricsTest, DaysSinceLastUse_Profile) { base::HistogramTester histogram_tester; AutofillProfile profile; - profile.set_use_date(base::Time::Now() - base::TimeDelta::FromDays(13)); + profile.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(13)); profile.RecordAndLogUse(); histogram_tester.ExpectBucketCount("Autofill.DaysSinceLastUse.Profile", 13, 1); @@ -6605,7 +6731,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { // Expect no notifications when the form is first seen. { base::HistogramTester histogram_tester; - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); histogram_tester.ExpectTotalCount("Autofill.FormSubmittedState", 0); VerifyDeveloperEngagementUkm( @@ -6911,7 +7037,7 @@ TEST_F( { base::HistogramTester histogram_tester; base::UserActionTester user_action_tester; - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); VerifyDeveloperEngagementUkm( test_ukm_recorder_, form, /*is_for_credit_card=*/false, {FormType::ADDRESS_FORM}, @@ -7463,7 +7589,12 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) { } // Verify that we correctly log metrics tracking the duration of form fill. +// TODO(crbug.com/1009364) Test is flake on many builders. TEST_F(AutofillMetricsTest, FormFillDuration) { + base::TimeTicks now = AutofillTickClock::NowTicks(); + TestAutofillTickClock test_clock; + test_clock.SetNowTicks(now); + // Load a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); @@ -7502,8 +7633,13 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { // Expect only form load metrics to be logged if the form is submitted without // user interaction. { + SCOPED_TRACE("Test 1"); base::HistogramTester histogram_tester; - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); + base::TimeTicks parse_time = autofill_manager_->form_structures() + .begin() + ->second->form_parsed_timestamp(); + test_clock.SetNowTicks(parse_time + base::TimeDelta::FromMicroseconds(17)); autofill_manager_->OnFormSubmitted(form, false, SubmissionSource::FORM_SUBMISSION); @@ -7521,14 +7657,16 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { // Expect metric to be logged if the user manually edited a form field. { + SCOPED_TRACE("Test 2"); base::HistogramTester histogram_tester; - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); base::TimeTicks parse_time = autofill_manager_->form_structures() .begin() ->second->form_parsed_timestamp(); autofill_manager_->OnTextFieldDidChange( form, form.fields.front(), gfx::RectF(), parse_time + base::TimeDelta::FromMicroseconds(3)); + test_clock.SetNowTicks(parse_time + base::TimeDelta::FromMicroseconds(17)); autofill_manager_->OnFormSubmitted(form, false, SubmissionSource::FORM_SUBMISSION); @@ -7548,13 +7686,15 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { // Expect metric to be logged if the user autofilled the form. form.fields[0].is_autofilled = true; { + SCOPED_TRACE("Test 3"); base::HistogramTester histogram_tester; - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); base::TimeTicks parse_time = autofill_manager_->form_structures() .begin() ->second->form_parsed_timestamp(); autofill_manager_->OnDidFillAutofillFormData( form, parse_time + base::TimeDelta::FromMicroseconds(5)); + test_clock.SetNowTicks(parse_time + base::TimeDelta::FromMicroseconds(17)); autofill_manager_->OnFormSubmitted(form, false, SubmissionSource::FORM_SUBMISSION); @@ -7575,17 +7715,20 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { // and autofilled others. Messages can arrive out of order, so make sure they // take precedence appropriately. { + SCOPED_TRACE("Test 4"); base::HistogramTester histogram_tester; - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); base::TimeTicks parse_time = autofill_manager_->form_structures() .begin() ->second->form_parsed_timestamp(); autofill_manager_->OnDidFillAutofillFormData( form, parse_time + base::TimeDelta::FromMicroseconds(5)); + autofill_manager_->OnTextFieldDidChange( form, form.fields.front(), gfx::RectF(), parse_time + base::TimeDelta::FromMicroseconds(3)); + test_clock.SetNowTicks(parse_time + base::TimeDelta::FromMicroseconds(17)); autofill_manager_->OnFormSubmitted(form, false, SubmissionSource::FORM_SUBMISSION); @@ -7605,17 +7748,19 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { // Make sure that loading another form doesn't affect metrics from the first // form. { + SCOPED_TRACE("Test 5"); base::HistogramTester histogram_tester; - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); base::TimeTicks parse_time = autofill_manager_->form_structures() .begin() ->second->form_parsed_timestamp(); - autofill_manager_->OnFormsSeen(second_forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(second_forms, AutofillTickClock::NowTicks()); autofill_manager_->OnDidFillAutofillFormData( form, parse_time + base::TimeDelta::FromMicroseconds(5)); autofill_manager_->OnTextFieldDidChange( form, form.fields.front(), gfx::RectF(), parse_time + base::TimeDelta::FromMicroseconds(3)); + test_clock.SetNowTicks(parse_time + base::TimeDelta::FromMicroseconds(17)); autofill_manager_->OnFormSubmitted(form, false, SubmissionSource::FORM_SUBMISSION); @@ -7635,14 +7780,16 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { // Make sure that submitting a form that was loaded later will report the // later loading time. { + SCOPED_TRACE("Test 6"); base::HistogramTester histogram_tester; - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); - autofill_manager_->OnFormsSeen(second_forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); + autofill_manager_->OnFormsSeen(second_forms, AutofillTickClock::NowTicks()); base::TimeTicks parse_time{}; for (const auto& kv : autofill_manager_->form_structures()) { if (kv.second->form_parsed_timestamp() > parse_time) parse_time = kv.second->form_parsed_timestamp(); } + test_clock.SetNowTicks(parse_time + base::TimeDelta::FromMicroseconds(17)); autofill_manager_->OnFormSubmitted(second_form, false, SubmissionSource::FORM_SUBMISSION); @@ -7941,7 +8088,7 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) { // Expect to log NEW_PROFILE_CREATED for the metric since a new profile is // submitted. - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); autofill_manager_->OnFormSubmitted(form, false, SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted", @@ -7954,7 +8101,7 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) { // Expect to log EXISTING_PROFILE_USED for the metric since the same profile // is submitted. - autofill_manager_->OnFormsSeen(second_forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(second_forms, AutofillTickClock::NowTicks()); autofill_manager_->OnFormSubmitted(second_form, false, SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted", @@ -7967,7 +8114,7 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) { // Expect to log NEW_PROFILE_CREATED for the metric since a new profile is // submitted. - autofill_manager_->OnFormsSeen(third_forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(third_forms, AutofillTickClock::NowTicks()); autofill_manager_->OnFormSubmitted(third_form, false, SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted", @@ -7980,7 +8127,7 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) { // Expect to log EXISTING_PROFILE_UPDATED for the metric since the profile was // updated. - autofill_manager_->OnFormsSeen(fourth_forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(fourth_forms, AutofillTickClock::NowTicks()); autofill_manager_->OnFormSubmitted(fourth_form, false, SubmissionSource::FORM_SUBMISSION); histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted", @@ -8434,9 +8581,9 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel) { base::HistogramTester histogram_tester; AutofillMetrics::LogUserHappinessBySecurityLevel( AutofillMetrics::FIELD_WAS_AUTOFILLED, PASSWORD_FORM, - security_state::SecurityLevel::HTTP_SHOW_WARNING); + security_state::SecurityLevel::WARNING); histogram_tester.ExpectBucketCount( - "Autofill.UserHappiness.Password.HTTP_SHOW_WARNING", + "Autofill.UserHappiness.Password.WARNING", AutofillMetrics::FIELD_WAS_AUTOFILLED, 1); } @@ -8496,16 +8643,14 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel_FromFormEvents) { // Simulate suggestions shown twice with separate popups. { base::HistogramTester histogram_tester; - autofill_client_.set_security_level( - security_state::SecurityLevel::HTTP_SHOW_WARNING); + autofill_client_.set_security_level(security_state::SecurityLevel::WARNING); autofill_manager_->DidShowSuggestions(true, form, field); autofill_manager_->DidShowSuggestions(true, form, field); - histogram_tester.ExpectBucketCount( - "Autofill.UserHappiness.Address.HTTP_SHOW_WARNING", - AutofillMetrics::SUGGESTIONS_SHOWN, 2); - histogram_tester.ExpectBucketCount( - "Autofill.UserHappiness.Address.HTTP_SHOW_WARNING", - AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address.WARNING", + AutofillMetrics::SUGGESTIONS_SHOWN, 2); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address.WARNING", + AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, + 1); } } @@ -8751,9 +8896,9 @@ TEST_F(AutofillMetricsTest, LogSaveCardPromptMetricBySecurityLevel) { base::HistogramTester histogram_tester; AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel( AutofillMetrics::SAVE_CARD_PROMPT_END_ACCEPTED, /*is_uploading=*/true, - security_state::SecurityLevel::HTTP_SHOW_WARNING); + security_state::SecurityLevel::WARNING); histogram_tester.ExpectBucketCount( - "Autofill.SaveCreditCardPrompt.Upload.HTTP_SHOW_WARNING", + "Autofill.SaveCreditCardPrompt.Upload.WARNING", AutofillMetrics::SAVE_CARD_PROMPT_END_ACCEPTED, 1); } @@ -8914,7 +9059,7 @@ TEST_F(AutofillMetricsTest, FormEventMetrics_BySyncState) { FormData form; FormStructure form_structure(form); std::vector<FormData> forms(1, form); - autofill_manager_->OnFormsSeen(forms, TimeTicks::Now()); + autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks()); autofill_manager_->Reset(); { diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc index 9ff57ce1937..727f5b9aa82 100644 --- a/chromium/components/autofill/core/browser/autofill_test_utils.cc +++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc @@ -8,6 +8,7 @@ #include "base/guid.h" #include "base/rand_util.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" @@ -17,6 +18,7 @@ #include "components/autofill/core/browser/data_model/credit_card.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/form_data.h" @@ -118,6 +120,7 @@ void CreateTestAddressFormData(FormData* form, mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; form->url = GURL("http://myform.com/form.html"); form->action = GURL("http://myform.com/submit.html"); + form->is_action_empty = true; form->main_frame_origin = url::Origin::Create(GURL("https://myform_root.com/form.html")); types->clear(); @@ -254,8 +257,9 @@ void CreateTestCreditCardFormData(FormData* form, form->fields.push_back(field); } -inline void check_and_set( - FormGroup* profile, ServerFieldType type, const char* value) { +inline void check_and_set(FormGroup* profile, + ServerFieldType type, + const char* value) { if (value) profile->SetRawInfo(type, base::UTF8ToUTF16(value)); } @@ -278,34 +282,16 @@ AutofillProfile GetFullValidProfileForChina() { AutofillProfile GetFullProfile() { AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin); - SetProfileInfo(&profile, - "John", - "H.", - "Doe", - "johndoe@hades.com", - "Underworld", - "666 Erebus St.", - "Apt 8", - "Elysium", "CA", - "91111", - "US", - "16502111111"); + SetProfileInfo(&profile, "John", "H.", "Doe", "johndoe@hades.com", + "Underworld", "666 Erebus St.", "Apt 8", "Elysium", "CA", + "91111", "US", "16502111111"); return profile; } AutofillProfile GetFullProfile2() { AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin); - SetProfileInfo(&profile, - "Jane", - "A.", - "Smith", - "jsmith@example.com", - "ACME", - "123 Main Street", - "Unit 1", - "Greensdale", "MI", - "48838", - "US", + SetProfileInfo(&profile, "Jane", "A.", "Smith", "jsmith@example.com", "ACME", + "123 Main Street", "Unit 1", "Greensdale", "MI", "48838", "US", "13105557889"); return profile; } @@ -466,7 +452,7 @@ CreditCard GetRandomCreditCard(CreditCard::RecordType record_type) { }; constexpr size_t kNumNetworks = sizeof(kNetworks) / sizeof(kNetworks[0]); base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); + AutofillClock::Now().LocalExplode(&now); CreditCard credit_card = (record_type == CreditCard::LOCAL_CARD) @@ -541,16 +527,23 @@ void SetProfileInfo(AutofillProfile* profile, } void SetProfileInfoWithGuid(AutofillProfile* profile, - const char* guid, const char* first_name, const char* middle_name, - const char* last_name, const char* email, const char* company, - const char* address1, const char* address2, const char* city, - const char* state, const char* zipcode, const char* country, - const char* phone) { + const char* guid, + const char* first_name, + const char* middle_name, + const char* last_name, + const char* email, + const char* company, + const char* address1, + const char* address2, + const char* city, + const char* state, + const char* zipcode, + const char* country, + const char* phone) { if (guid) profile->set_guid(guid); - SetProfileInfo(profile, first_name, middle_name, last_name, email, - company, address1, address2, city, state, zipcode, country, - phone); + SetProfileInfo(profile, first_name, middle_name, last_name, email, company, + address1, address2, city, state, zipcode, country, phone); } void SetCreditCardInfo(CreditCard* credit_card, @@ -725,20 +718,25 @@ std::string ObfuscatedCardDigitsAsUTF8(const std::string& str) { internal::GetObfuscatedStringForCardDigits(base::ASCIIToUTF16(str))); } +std::string NextMonth() { + base::Time::Exploded now; + base::Time::Now().LocalExplode(&now); + return base::NumberToString(now.month % 12 + 1); +} std::string LastYear() { base::Time::Exploded now; base::Time::Now().LocalExplode(&now); - return std::to_string(now.year - 1); + return base::NumberToString(now.year - 1); } std::string NextYear() { base::Time::Exploded now; base::Time::Now().LocalExplode(&now); - return std::to_string(now.year + 1); + return base::NumberToString(now.year + 1); } std::string TenYearsFromNow() { base::Time::Exploded now; base::Time::Now().LocalExplode(&now); - return std::to_string(now.year + 10); + return base::NumberToString(now.year + 10); } } // namespace test diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.h b/chromium/components/autofill/core/browser/autofill_test_utils.h index 678a211d5d4..db80caea7a8 100644 --- a/chromium/components/autofill/core/browser/autofill_test_utils.h +++ b/chromium/components/autofill/core/browser/autofill_test_utils.h @@ -176,11 +176,19 @@ void SetProfileInfo(AutofillProfile* profile, const char* phone); void SetProfileInfoWithGuid(AutofillProfile* profile, - const char* guid, const char* first_name, const char* middle_name, - const char* last_name, const char* email, const char* company, - const char* address1, const char* address2, const char* city, - const char* state, const char* zipcode, const char* country, - const char* phone); + const char* guid, + const char* first_name, + const char* middle_name, + const char* last_name, + const char* email, + const char* company, + const char* address1, + const char* address2, + const char* city, + const char* state, + const char* zipcode, + const char* country, + const char* phone); // A unit testing utility that is common to a number of the Autofill unit // tests. |SetCreditCardInfo| provides a quick way to populate a credit card @@ -258,6 +266,7 @@ void GenerateTestAutofillPopup( std::string ObfuscatedCardDigitsAsUTF8(const std::string& str); +std::string NextMonth(); std::string LastYear(); std::string NextYear(); std::string TenYearsFromNow(); diff --git a/chromium/components/autofill/core/browser/autofill_type.cc b/chromium/components/autofill/core/browser/autofill_type.cc index d141a0dbcd3..4d0d4241c79 100644 --- a/chromium/components/autofill/core/browser/autofill_type.cc +++ b/chromium/components/autofill/core/browser/autofill_type.cc @@ -56,6 +56,10 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) { case ADDRESS_HOME_STREET_ADDRESS: case ADDRESS_HOME_SORTING_CODE: case ADDRESS_HOME_DEPENDENT_LOCALITY: + case ADDRESS_HOME_STREET: + case ADDRESS_HOME_HOUSE_NUMBER: + case ADDRESS_HOME_FLOOR: + case ADDRESS_HOME_OTHER_SUBUNIT: return ADDRESS_HOME; case ADDRESS_BILLING_LINE1: @@ -439,78 +443,6 @@ ServerFieldType AutofillType::GetStorableType() const { return UNKNOWN_TYPE; } -// static -ServerFieldType AutofillType::GetEquivalentBillingFieldType( - ServerFieldType field_type) { - switch (field_type) { - case ADDRESS_HOME_LINE1: - return ADDRESS_BILLING_LINE1; - - case ADDRESS_HOME_LINE2: - return ADDRESS_BILLING_LINE2; - - case ADDRESS_HOME_APT_NUM: - return ADDRESS_BILLING_APT_NUM; - - case ADDRESS_HOME_CITY: - return ADDRESS_BILLING_CITY; - - case ADDRESS_HOME_STATE: - return ADDRESS_BILLING_STATE; - - case ADDRESS_HOME_ZIP: - return ADDRESS_BILLING_ZIP; - - case ADDRESS_HOME_COUNTRY: - return ADDRESS_BILLING_COUNTRY; - - case ADDRESS_HOME_STREET_ADDRESS: - return ADDRESS_BILLING_STREET_ADDRESS; - - case ADDRESS_HOME_SORTING_CODE: - return ADDRESS_BILLING_SORTING_CODE; - - case ADDRESS_HOME_DEPENDENT_LOCALITY: - return ADDRESS_BILLING_DEPENDENT_LOCALITY; - - case PHONE_HOME_WHOLE_NUMBER: - return PHONE_BILLING_WHOLE_NUMBER; - - case PHONE_HOME_NUMBER: - return PHONE_BILLING_NUMBER; - - case PHONE_HOME_CITY_CODE: - return PHONE_BILLING_CITY_CODE; - - case PHONE_HOME_COUNTRY_CODE: - return PHONE_BILLING_COUNTRY_CODE; - - case PHONE_HOME_CITY_AND_NUMBER: - return PHONE_BILLING_CITY_AND_NUMBER; - - case NAME_FIRST: - return NAME_BILLING_FIRST; - - case NAME_MIDDLE: - return NAME_BILLING_MIDDLE; - - case NAME_LAST: - return NAME_BILLING_LAST; - - case NAME_MIDDLE_INITIAL: - return NAME_BILLING_MIDDLE_INITIAL; - - case NAME_FULL: - return NAME_BILLING_FULL; - - case NAME_SUFFIX: - return NAME_BILLING_SUFFIX; - - default: - return field_type; - } -} - std::string AutofillType::ToString() const { if (IsUnknown()) return "UNKNOWN_TYPE"; @@ -788,6 +720,14 @@ std::string AutofillType::ServerFieldTypeToString(ServerFieldType type) { return "NOT_USERNAME"; case UPI_VPA: return "UPI_VPA"; + case ADDRESS_HOME_STREET: + return "ADDRESS_HOME_STREET"; + case ADDRESS_HOME_HOUSE_NUMBER: + return "ADDRESS_HOME_HOUSE_NUMBER"; + case ADDRESS_HOME_FLOOR: + return "ADDRESS_HOME_FLOOR"; + case ADDRESS_HOME_OTHER_SUBUNIT: + return "ADDRESS_HOME_OTHER_SUBUNIT"; case AMBIGUOUS_TYPE: return "AMBIGUOUS_TYPE"; case MAX_VALID_FIELD_TYPE: diff --git a/chromium/components/autofill/core/browser/autofill_type.h b/chromium/components/autofill/core/browser/autofill_type.h index 893567a9214..0e65d1fa05a 100644 --- a/chromium/components/autofill/core/browser/autofill_type.h +++ b/chromium/components/autofill/core/browser/autofill_type.h @@ -24,7 +24,7 @@ FieldTypeGroup GroupTypeOfHtmlFieldType(HtmlFieldType field_type, // and for associating form fields with form values in the Web Database. class AutofillType { public: - explicit AutofillType(ServerFieldType field_type); + explicit AutofillType(ServerFieldType field_type = NO_SERVER_DATA); AutofillType(HtmlFieldType field_type, HtmlFieldMode mode); AutofillType(const AutofillType& autofill_type) = default; AutofillType& operator=(const AutofillType& autofill_type) = default; @@ -48,11 +48,6 @@ class AutofillType { // Serializes |this| type to a string. std::string ToString() const; - // Maps |field_type| to the corresponding billing field type if the field type - // is an address, name, or phone number type. - static ServerFieldType GetEquivalentBillingFieldType( - ServerFieldType field_type); - // Translates the ServerFieldType values into the corresponding strings. static std::string ServerFieldTypeToString(ServerFieldType type); diff --git a/chromium/components/autofill/core/browser/data_driven_test.cc b/chromium/components/autofill/core/browser/data_driven_test.cc index d30b91f2432..2a399402bf5 100644 --- a/chromium/components/autofill/core/browser/data_driven_test.cc +++ b/chromium/components/autofill/core/browser/data_driven_test.cc @@ -9,6 +9,7 @@ #include "base/strings/string_util.h" #include "base/threading/thread_restrictions.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/re2/src/re2/re2.h" namespace autofill { namespace { @@ -30,6 +31,24 @@ bool WriteFile(const base::FilePath& file, const std::string& content) { return write_size == static_cast<int>(content.length()); } +// Removes lines starting with (optional) whitespace and a #. +void StripComments(std::string* content) { + RE2::GlobalReplace( + content, + // Enable multi-line mode, ^ and $ match begin/end line in addition to + // begin/end text. + "(?m)" + // Search for start of lines (^), ignore spaces (\\s*), and then look for + // '#'. + "^\\s*#" + // Consume all characters (.*) until end of line ($). + ".*$" + // Consume the line wrapping so that the entire line is gone. + "[\\r\\n]*", + // Replace entire line with empty string. + ""); +} + } // namespace void DataDrivenTest::RunDataDrivenTest( @@ -81,6 +100,8 @@ void DataDrivenTest::RunOneDataDrivenTest( ASSERT_TRUE(WriteFile(output_file, output)); return; } + // Remove comment lines (lead by '#' character). + StripComments(&output_file_contents); if (is_expected_to_pass) { EXPECT_EQ(output_file_contents, output); diff --git a/chromium/components/autofill/core/browser/data_model/autofill_data_model_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_data_model_unittest.cc index b8762af5f1c..b24e914c5d2 100644 --- a/chromium/components/autofill/core/browser/data_model/autofill_data_model_unittest.cc +++ b/chromium/components/autofill/core/browser/data_model/autofill_data_model_unittest.cc @@ -11,6 +11,7 @@ #include "base/time/time.h" #include "components/autofill/core/browser/data_model/autofill_metadata.h" #include "components/autofill/core/browser/test_autofill_clock.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" #include "testing/gtest/include/gtest/gtest.h" @@ -120,7 +121,7 @@ struct HasGreaterFrecencyThanTestCase { Expectation expectation; }; -base::Time now = base::Time::Now(); +base::Time now = AutofillClock::Now(); class HasGreaterFrecencyThanTest : public testing::TestWithParam<HasGreaterFrecencyThanTestCase> {}; diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile.cc index 125a506ba17..60aeae68441 100644 --- a/chromium/components/autofill/core/browser/data_model/autofill_profile.cc +++ b/chromium/components/autofill/core/browser/data_model/autofill_profile.cc @@ -482,14 +482,6 @@ bool AutofillProfile::operator!=(const AutofillProfile& profile) const { return !operator==(profile); } -bool AutofillProfile::IsSubsetOf(const AutofillProfile& profile, - const std::string& app_locale) const { - ServerFieldTypeSet types; - GetSupportedTypes(&types); - return IsSubsetOfForFieldSet(AutofillProfileComparator(app_locale), profile, - app_locale, types); -} - bool AutofillProfile::IsSubsetOfForFieldSet( const AutofillProfileComparator& comparator, const AutofillProfile& profile, diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile.h b/chromium/components/autofill/core/browser/data_model/autofill_profile.h index 768dc5103d4..a984548e313 100644 --- a/chromium/components/autofill/core/browser/data_model/autofill_profile.h +++ b/chromium/components/autofill/core/browser/data_model/autofill_profile.h @@ -124,10 +124,6 @@ class AutofillProfile : public AutofillDataModel { bool operator==(const AutofillProfile& profile) const; virtual bool operator!=(const AutofillProfile& profile) const; - // Returns true if this AutofillProfile's data is a subset of |profile|'s. - bool IsSubsetOf(const AutofillProfile& profile, - const std::string& app_locale) const; - // Like IsSubsetOf, but considers only the given |types|. bool IsSubsetOfForFieldSet(const AutofillProfileComparator& comparator, const AutofillProfile& profile, diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc index 9b41b0b77d0..ac578d38a0f 100644 --- a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc +++ b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc @@ -16,8 +16,10 @@ #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/address_rewriter.h" #include "components/autofill/core/browser/autofill_data_util.h" +#include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/geo/autofill_country.h" #include "components/autofill/core/browser/geo/state_names.h" +#include "components/autofill/core/common/autofill_clock.h" #include "third_party/libphonenumber/phonenumber_api.h" using base::UTF16ToUTF8; @@ -829,6 +831,70 @@ bool AutofillProfileComparator::MergeAddresses(const AutofillProfile& p1, } // static +std::string AutofillProfileComparator::MergeProfile( + const AutofillProfile& new_profile, + std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles, + const std::string& app_locale, + std::vector<AutofillProfile>* merged_profiles) { + merged_profiles->clear(); + + // Sort the existing profiles in decreasing order of frecency, so the "best" + // profiles are checked first. Put the verified profiles last so the non + // verified profiles get deduped among themselves before reaching the verified + // profiles. + // TODO(crbug.com/620521): Remove the check for verified from the sort. + base::Time comparison_time = AutofillClock::Now(); + std::sort(existing_profiles->begin(), existing_profiles->end(), + [comparison_time](const std::unique_ptr<AutofillProfile>& a, + const std::unique_ptr<AutofillProfile>& b) { + if (a->IsVerified() != b->IsVerified()) + return !a->IsVerified(); + return a->HasGreaterFrecencyThan(b.get(), comparison_time); + }); + + // Set to true if |existing_profiles| already contains an equivalent profile. + bool matching_profile_found = false; + std::string guid = new_profile.guid(); + + // If we have already saved this address, merge in any missing values. + // Only merge with the first match. Merging the new profile into the existing + // one preserves the validity of credit card's billing address reference. + AutofillProfileComparator comparator(app_locale); + for (const auto& existing_profile : *existing_profiles) { + if (!matching_profile_found && + comparator.AreMergeable(new_profile, *existing_profile) && + existing_profile->SaveAdditionalInfo(new_profile, app_locale)) { + // Unverified profiles should always be updated with the newer data, + // whereas verified profiles should only ever be overwritten by verified + // data. If an automatically aggregated profile would overwrite a + // verified profile, just drop it. + matching_profile_found = true; + guid = existing_profile->guid(); + + // We set the modification date so that immediate requests for profiles + // will properly reflect the fact that this profile has been modified + // recently. After writing to the database and refreshing the local copies + // the profile will have a very slightly newer time reflecting what's + // actually stored in the database. + existing_profile->set_modification_date(AutofillClock::Now()); + } + merged_profiles->push_back(*existing_profile); + } + + // If the new profile was not merged with an existing one, add it to the list. + if (!matching_profile_found) { + merged_profiles->push_back(new_profile); + // Similar to updating merged profiles above, set the modification date on + // new profiles. + merged_profiles->back().set_modification_date(AutofillClock::Now()); + AutofillMetrics::LogProfileActionOnFormSubmitted( + AutofillMetrics::NEW_PROFILE_CREATED); + } + + return guid; +} + +// static std::set<base::StringPiece16> AutofillProfileComparator::UniqueTokens( base::StringPiece16 s) { std::vector<base::StringPiece16> tokens = base::SplitStringPiece( diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.h b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.h index 127c828743b..525bf0703a2 100644 --- a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.h +++ b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.h @@ -138,6 +138,16 @@ class AutofillProfileComparator { // App locale used when this comparator instance was created. const std::string app_locale() const { return app_locale_; } + // Merges |new_profile| into one of the |existing_profiles| if possible; + // otherwise appends |new_profile| to the end of that list. Fills + // |merged_profiles| with the result. Returns the |guid| of the new or updated + // profile. + static std::string MergeProfile( + const AutofillProfile& new_profile, + std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles, + const std::string& app_locale, + std::vector<AutofillProfile>* merged_profiles); + protected: // The result type returned by CompareTokens. enum CompareTokensResult { diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc index af44b882387..445c4cafbc3 100644 --- a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc +++ b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc @@ -12,6 +12,7 @@ #include "components/autofill/core/browser/data_model/contact_info.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/geo/country_names.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_features.h" #include "testing/gtest/include/gtest/gtest.h" @@ -41,6 +42,7 @@ using autofill::PHONE_HOME_WHOLE_NUMBER; // Classes, Functions, and other Symbols using autofill::Address; +using autofill::AutofillClock; using autofill::AutofillProfile; using autofill::AutofillType; using autofill::CompanyInfo; @@ -785,15 +787,15 @@ TEST_F(AutofillProfileComparatorTest, MergeCJKNames) { // the most recent profile if there is a conflict. The ordering is // p1 > p2 > p3 > p4 > p5, with p1 being the most recent. AutofillProfile p1 = CreateProfileWithName(name1); - p1.set_use_date(base::Time::Now()); + p1.set_use_date(AutofillClock::Now()); AutofillProfile p2 = CreateProfileWithName(name2); - p2.set_use_date(base::Time::Now() - base::TimeDelta::FromHours(1)); + p2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromHours(1)); AutofillProfile p3 = CreateProfileWithName(name3); - p3.set_use_date(base::Time::Now() - base::TimeDelta::FromHours(2)); + p3.set_use_date(AutofillClock::Now() - base::TimeDelta::FromHours(2)); AutofillProfile p4 = CreateProfileWithName(name4); - p4.set_use_date(base::Time::Now() - base::TimeDelta::FromHours(3)); + p4.set_use_date(AutofillClock::Now() - base::TimeDelta::FromHours(3)); AutofillProfile p5 = CreateProfileWithName(name5); - p5.set_use_date(base::Time::Now() - base::TimeDelta::FromHours(4)); + p5.set_use_date(AutofillClock::Now() - base::TimeDelta::FromHours(4)); AutofillProfile p6 = CreateProfileWithName(name6); AutofillProfile p7 = CreateProfileWithName(name7); @@ -831,7 +833,7 @@ TEST_F(AutofillProfileComparatorTest, MergeEmailAddresses) { EmailInfo email_a; email_a.SetRawInfo(EMAIL_ADDRESS, UTF8ToUTF16(kEmailA)); AutofillProfile profile_a = CreateProfileWithEmail(kEmailA); - profile_a.set_use_date(base::Time::Now()); + profile_a.set_use_date(AutofillClock::Now()); EmailInfo email_b; email_b.SetRawInfo(EMAIL_ADDRESS, UTF8ToUTF16(kEmailB)); @@ -859,7 +861,7 @@ TEST_F(AutofillProfileComparatorTest, MergeCompanyNames) { CompanyInfo company_a; company_a.SetRawInfo(COMPANY_NAME, UTF8ToUTF16(kCompanyA)); AutofillProfile profile_a = CreateProfileWithCompanyName(kCompanyA); - profile_a.set_use_date(base::Time::Now()); + profile_a.set_use_date(AutofillClock::Now()); // Company Name B is post_normalization identical to Company Name A. The use // date will be used to choose between them. @@ -879,7 +881,7 @@ TEST_F(AutofillProfileComparatorTest, MergeCompanyNames) { CompanyInfo company_d; company_d.SetRawInfo(COMPANY_NAME, UTF8ToUTF16(kCompanyD)); AutofillProfile profile_d = CreateProfileWithCompanyName(kCompanyD); - profile_a.set_use_date(base::Time::Now()); + profile_a.set_use_date(AutofillClock::Now()); MergeCompanyNamesAndExpect(profile_a, profile_a, company_a); MergeCompanyNamesAndExpect(profile_a, profile_b, company_b); diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc index de503b8f649..58f336978d6 100644 --- a/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc +++ b/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc @@ -22,6 +22,7 @@ #include "components/autofill/core/browser/data_model/autofill_profile_comparator.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/test_autofill_clock.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/form_field_data.h" @@ -673,31 +674,6 @@ TEST(AutofillProfileTest, CreateInferredLabelsFlattensMultiLineValues) { EXPECT_EQ(ASCIIToUTF16("88 Nowhere Ave., Apt. 42"), labels[0]); } -TEST(AutofillProfileTest, IsSubsetOfForProfiles) { - AutofillProfile profile1 = - AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); - test::SetProfileInfo(&profile1, "Genevieve", "", "Fox", - "genevieve@hotmail.com", "", "274 Main St", "", - "Northhampton", "MA", "01060", "US", ""); - - AutofillProfile profile2 = - AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); - test::SetProfileInfo(&profile2, "Genevieve", "", "Fox", - "genevieve@hotmail.com", "", "", "", "", "", "", "US", - ""); - - AutofillProfile profile3 = - AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); - test::SetProfileInfo(&profile3, "Genevieve", "", "Fuller", - "genevieve@hotmail.com", "", "", "", "", "", "", "US", - ""); - - EXPECT_FALSE(profile1.IsSubsetOf(profile2, "en-US")); - EXPECT_TRUE(profile2.IsSubsetOf(profile1, "en-US")); - EXPECT_FALSE(profile2.IsSubsetOf(profile3, "en-US")); - EXPECT_FALSE(profile3.IsSubsetOf(profile2, "en-US")); -} - TEST(AutofillProfileTest, IsSubsetOfForFieldSet_DifferentMiddleNames) { AutofillProfile profile1 = AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); @@ -2210,7 +2186,7 @@ TEST_P(HasGreaterFrescocencyTest, HasGreaterFrescocency) { test_case.server_validity_state_b, AutofillDataModel::SERVER); - const base::Time now = base::Time::Now(); + const base::Time now = AutofillClock::Now(); if (test_case.expectation == EQUAL) { EXPECT_EQ(profile_a.HasGreaterFrecencyThan(&profile_b, now), @@ -2249,7 +2225,7 @@ TEST_P(HasGreaterFrescocencyTest, PriorityCheck) { profile_invalid.set_use_count(100); profile_valid.set_use_count(10); - const base::Time now = base::Time::Now(); + const base::Time now = AutofillClock::Now(); const base::Time past = now - base::TimeDelta::FromDays(1); profile_invalid.set_use_date(now); diff --git a/chromium/components/autofill/core/browser/data_model/contact_info.cc b/chromium/components/autofill/core/browser/data_model/contact_info.cc index 895e1ed0a52..668230e72f0 100644 --- a/chromium/components/autofill/core/browser/data_model/contact_info.cc +++ b/chromium/components/autofill/core/browser/data_model/contact_info.cc @@ -47,31 +47,6 @@ bool NameInfo::operator==(const NameInfo& other) const { family_ == other.family_ && full_ == other.full_; } -bool NameInfo::ParsedNamesAreEqual(const NameInfo& info) const { - return given_ == info.given_ && middle_ == info.middle_ && - family_ == info.family_; -} - -void NameInfo::OverwriteName(const NameInfo& new_name) { - if (!new_name.given_.empty()) - given_ = new_name.given_; - - // For the middle name, don't overwrite a full middle name with an initial. - if (!new_name.middle_.empty() && - (middle_.size() <= 1 || new_name.middle_.size() > 1)) - middle_ = new_name.middle_; - - if (!new_name.family_.empty()) - family_ = new_name.family_; - - if (!new_name.full_.empty()) - full_ = new_name.full_; -} - -bool NameInfo::NamePartsAreEmpty() const { - return given_.empty() && middle_.empty() && family_.empty(); -} - base::string16 NameInfo::GetRawInfo(ServerFieldType type) const { DCHECK_EQ(NAME, AutofillType(type).group()); switch (type) { @@ -250,15 +225,26 @@ void CompanyInfo::SetRawInfo(ServerFieldType type, } bool CompanyInfo::IsValidOrVerified(const base::string16& value) const { - if (!base::FeatureList::IsEnabled( - autofill::features::kAutofillRejectCompanyBirthyear)) - return true; - - if (profile_ && profile_->IsVerified()) + if (profile_ && profile_->IsVerified()) { return true; - - // Companies that are of the format of a four digit birth year are not valid. - return !MatchesPattern(value, base::UTF8ToUTF16("^(19|20)\\d{2}$")); + } + // |value| is a birthyear: + if (base::FeatureList::IsEnabled( + autofill::features::kAutofillRejectCompanyBirthyear) && + MatchesPattern(value, base::UTF8ToUTF16("^(19|20)\\d{2}$"))) { + return false; + } + // |value| is a social title: + if (base::FeatureList::IsEnabled( + autofill::features::kAutofillRejectCompanySocialTitle) && + MatchesPattern(value, base::UTF8ToUTF16( + "^(Ms\\.?|Mrs\\.?|Mr\\.?|Miss|Mistress|Mister|" + "Frau|Herr|" + "Mlle|Mme|M\\.|" + "Dr\\.?|Prof\\.?)$"))) { + return false; + } + return true; } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/data_model/contact_info.h b/chromium/components/autofill/core/browser/data_model/contact_info.h index b838253f118..cedfe7bedcb 100644 --- a/chromium/components/autofill/core/browser/data_model/contact_info.h +++ b/chromium/components/autofill/core/browser/data_model/contact_info.h @@ -26,18 +26,6 @@ class NameInfo : public FormGroup { bool operator==(const NameInfo& other) const; bool operator!=(const NameInfo& other) const { return !operator==(other); } - // Compares |NameInfo| objects for |given_|, |middle_| and |family_| names. - // The comparison is case sensitive. - bool ParsedNamesAreEqual(const NameInfo& info) const; - - // For every non-empty NameInfo part in |new_name|, the corresponding NameInfo - // part in | this | is overwritten.Special logic so that a middle initial may - // not overwrite a full middle name. - void OverwriteName(const NameInfo& new_name); - - // Returns true if all the name parts (first, middle and last) are empty. - bool NamePartsAreEmpty() const; - // FormGroup: base::string16 GetRawInfo(ServerFieldType type) const override; void SetRawInfo(ServerFieldType type, const base::string16& value) override; diff --git a/chromium/components/autofill/core/browser/data_model/contact_info_unittest.cc b/chromium/components/autofill/core/browser/data_model/contact_info_unittest.cc index a5e64b41128..e0bcfceb9d8 100644 --- a/chromium/components/autofill/core/browser/data_model/contact_info_unittest.cc +++ b/chromium/components/autofill/core/browser/data_model/contact_info_unittest.cc @@ -183,223 +183,119 @@ TEST(NameInfoTest, GetFullName) { name.GetInfo(AutofillType(NAME_FULL), "en-US")); } -struct ParsedNamesAreEqualTestCase { - std::string starting_names[3]; - std::string additional_names[3]; - bool expected_result; -}; +TEST(CompanyTest, CompanyNameYear) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{features::kAutofillRejectCompanyBirthyear}, + /*disabled_features=*/{}); -class ParsedNamesAreEqualTest - : public testing::TestWithParam<ParsedNamesAreEqualTestCase> {}; + AutofillProfile profile; + CompanyInfo company(&profile); + ASSERT_FALSE(profile.IsVerified()); -TEST_P(ParsedNamesAreEqualTest, ParsedNamesAreEqual) { - auto test_case = GetParam(); + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Google")); + EXPECT_EQ(UTF8ToUTF16("Google"), company.GetRawInfo(COMPANY_NAME)); - // Construct the starting_profile. - NameInfo starting_profile; - starting_profile.SetRawInfo(NAME_FIRST, - UTF8ToUTF16(test_case.starting_names[0])); - starting_profile.SetRawInfo(NAME_MIDDLE, - UTF8ToUTF16(test_case.starting_names[1])); - starting_profile.SetRawInfo(NAME_LAST, - UTF8ToUTF16(test_case.starting_names[2])); - - // Construct the additional_profile. - NameInfo additional_profile; - additional_profile.SetRawInfo(NAME_FIRST, - UTF8ToUTF16(test_case.additional_names[0])); - additional_profile.SetRawInfo(NAME_MIDDLE, - UTF8ToUTF16(test_case.additional_names[1])); - additional_profile.SetRawInfo(NAME_LAST, - UTF8ToUTF16(test_case.additional_names[2])); - - // Verify the test expectations. - EXPECT_EQ(test_case.expected_result, - starting_profile.ParsedNamesAreEqual(additional_profile)); -} + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1987")); + EXPECT_EQ(UTF8ToUTF16(""), company.GetRawInfo(COMPANY_NAME)); -INSTANTIATE_TEST_SUITE_P( - ContactInfoTest, - ParsedNamesAreEqualTest, - testing::Values( - // Identical name comparison. - ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"}, - {"Marion", "Mitchell", "Morrison"}, - true}, - - // Case-sensitive comparisons. - ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"}, - {"Marion", "Mitchell", "MORRISON"}, - false}, - ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"}, - {"MARION", "Mitchell", "MORRISON"}, - false}, - ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"}, - {"MARION", "MITCHELL", "MORRISON"}, - false}, - ParsedNamesAreEqualTestCase{{"Marion", "", "Mitchell Morrison"}, - {"MARION", "", "MITCHELL MORRISON"}, - false}, - ParsedNamesAreEqualTestCase{{"Marion Mitchell", "", "Morrison"}, - {"MARION MITCHELL", "", "MORRISON"}, - false}, - - // Identical full names but different canonical forms. - ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"}, - {"Marion", "", "Mitchell Morrison"}, - false}, - ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"}, - {"Marion Mitchell", "", "MORRISON"}, - false}, - - // Different names. - ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"}, - {"Marion", "M.", "Morrison"}, - false}, - ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"}, - {"MARION", "M.", "MORRISON"}, - false}, - ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"}, - {"David", "Mitchell", "Morrison"}, - false}, - - // Non-ASCII characters. - ParsedNamesAreEqualTestCase{{"M\xc3\xa1rion Mitchell", "", "Morrison"}, - {"M\xc3\xa1rion Mitchell", "", "Morrison"}, - true})); - -struct OverwriteNameTestCase { - std::string existing_name[4]; - std::string new_name[4]; - std::string expected_name[4]; -}; + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("It was 1987.")); + EXPECT_EQ(UTF8ToUTF16("It was 1987."), company.GetRawInfo(COMPANY_NAME)); -class OverwriteNameTest : public testing::TestWithParam<OverwriteNameTestCase> { -}; + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1987 was the year.")); + EXPECT_EQ(UTF8ToUTF16("1987 was the year."), + company.GetRawInfo(COMPANY_NAME)); -TEST_P(OverwriteNameTest, OverwriteName) { - auto test_case = GetParam(); - // Construct the starting_profile. - NameInfo existing_name; - existing_name.SetRawInfo(NAME_FIRST, UTF8ToUTF16(test_case.existing_name[0])); - existing_name.SetRawInfo(NAME_MIDDLE, - UTF8ToUTF16(test_case.existing_name[1])); - existing_name.SetRawInfo(NAME_LAST, UTF8ToUTF16(test_case.existing_name[2])); - existing_name.SetRawInfo(NAME_FULL, UTF8ToUTF16(test_case.existing_name[3])); - - // Construct the additional_profile. - NameInfo new_name; - new_name.SetRawInfo(NAME_FIRST, UTF8ToUTF16(test_case.new_name[0])); - new_name.SetRawInfo(NAME_MIDDLE, UTF8ToUTF16(test_case.new_name[1])); - new_name.SetRawInfo(NAME_LAST, UTF8ToUTF16(test_case.new_name[2])); - new_name.SetRawInfo(NAME_FULL, UTF8ToUTF16(test_case.new_name[3])); - - existing_name.OverwriteName(new_name); - - // Verify the test expectations. - EXPECT_EQ(UTF8ToUTF16(test_case.expected_name[0]), - existing_name.GetRawInfo(NAME_FIRST)); - EXPECT_EQ(UTF8ToUTF16(test_case.expected_name[1]), - existing_name.GetRawInfo(NAME_MIDDLE)); - EXPECT_EQ(UTF8ToUTF16(test_case.expected_name[2]), - existing_name.GetRawInfo(NAME_LAST)); - EXPECT_EQ(UTF8ToUTF16(test_case.expected_name[3]), - existing_name.GetRawInfo(NAME_FULL)); -} + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Yes, 1987 was the year.")); + EXPECT_EQ(UTF8ToUTF16("Yes, 1987 was the year."), + company.GetRawInfo(COMPANY_NAME)); -INSTANTIATE_TEST_SUITE_P( - ContactInfoTest, - OverwriteNameTest, - testing::Values( - // Missing information in the original name gets filled with the new - // name's information. - OverwriteNameTestCase{ - {"", "", "", ""}, - {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"}, - {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"}, - }, - // The new name's values overwrite the exsiting name values if they are - // different - OverwriteNameTestCase{ - {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"}, - {"Mario", "Mitchell", "Thompson", "Mario Mitchell Morrison"}, - {"Mario", "Mitchell", "Thompson", "Mario Mitchell Morrison"}, - }, - // An existing name values do not get replaced with empty values. - OverwriteNameTestCase{ - {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"}, - {"", "", "", ""}, - {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"}, - }, - // An existing full middle not does not get replaced by a middle name - // initial. - OverwriteNameTestCase{ - {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"}, - {"Marion", "M", "Morrison", "Marion Mitchell Morrison"}, - {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"}, - }, - // An existing middle name initial is overwritten by the new profile's - // middle name value. - OverwriteNameTestCase{ - {"Marion", "M", "Morrison", "Marion Mitchell Morrison"}, - {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"}, - {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"}, - }, - // A NameInfo with only the full name set overwritten with a NameInfo - // with only the name parts set result in a NameInfo with all the name - // parts and name full set. - OverwriteNameTestCase{ - {"", "", "", "Marion Mitchell Morrison"}, - {"Marion", "Mitchell", "Morrison", ""}, - {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"}, - }, - // A NameInfo with only the name parts set overwritten with a NameInfo - // with only the full name set result in a NameInfo with all the name - // parts and name full set. - OverwriteNameTestCase{ - {"Marion", "Mitchell", "Morrison", ""}, - {"", "", "", "Marion Mitchell Morrison"}, - {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"}, - })); - -struct NamePartsAreEmptyTestCase { - std::string first; - std::string middle; - std::string last; - std::string full; - bool expected_result; -}; + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("2019")); + EXPECT_EQ(UTF8ToUTF16(""), company.GetRawInfo(COMPANY_NAME)); -class NamePartsAreEmptyTest - : public testing::TestWithParam<NamePartsAreEmptyTestCase> {}; + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1818")); + EXPECT_EQ(UTF8ToUTF16("1818"), company.GetRawInfo(COMPANY_NAME)); -TEST_P(NamePartsAreEmptyTest, NamePartsAreEmpty) { - auto test_case = GetParam(); - // Construct the NameInfo. - NameInfo name; - name.SetRawInfo(NAME_FIRST, UTF8ToUTF16(test_case.first)); - name.SetRawInfo(NAME_MIDDLE, UTF8ToUTF16(test_case.middle)); - name.SetRawInfo(NAME_LAST, UTF8ToUTF16(test_case.last)); - name.SetRawInfo(NAME_FULL, UTF8ToUTF16(test_case.full)); + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("2345")); + EXPECT_EQ(UTF8ToUTF16("2345"), company.GetRawInfo(COMPANY_NAME)); - // Verify the test expectations. - EXPECT_EQ(test_case.expected_result, name.NamePartsAreEmpty()); -} + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr")); + EXPECT_EQ(UTF8ToUTF16("Mr"), company.GetRawInfo(COMPANY_NAME)); -INSTANTIATE_TEST_SUITE_P( - ContactInfoTest, - NamePartsAreEmptyTest, - testing::Values(NamePartsAreEmptyTestCase{"", "", "", "", true}, - NamePartsAreEmptyTestCase{"", "", "", - "Marion Mitchell Morrison", true}, - NamePartsAreEmptyTestCase{"Marion", "", "", "", false}, - NamePartsAreEmptyTestCase{"", "Mitchell", "", "", false}, - NamePartsAreEmptyTestCase{"", "", "Morrison", "", false})); + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr.")); + EXPECT_EQ(UTF8ToUTF16("Mr."), company.GetRawInfo(COMPANY_NAME)); -TEST(CompanyTest, CompanyNameYear) { + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mrs")); + EXPECT_EQ(UTF8ToUTF16("Mrs"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mrs.")); + EXPECT_EQ(UTF8ToUTF16("Mrs."), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr. & Mrs.")); + EXPECT_EQ(UTF8ToUTF16("Mr. & Mrs."), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr. & Mrs. Smith")); + EXPECT_EQ(UTF8ToUTF16("Mr. & Mrs. Smith"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Frau")); + EXPECT_EQ(UTF8ToUTF16("Frau"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Frau Doktor")); + EXPECT_EQ(UTF8ToUTF16("Frau Doktor"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Herr")); + EXPECT_EQ(UTF8ToUTF16("Herr"), company.GetRawInfo(COMPANY_NAME)); + + profile.set_origin("Not empty"); + ASSERT_TRUE(profile.IsVerified()); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Google")); + EXPECT_EQ(UTF8ToUTF16("Google"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1987")); + EXPECT_EQ(UTF8ToUTF16("1987"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("2019")); + EXPECT_EQ(UTF8ToUTF16("2019"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1818")); + EXPECT_EQ(UTF8ToUTF16("1818"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("2345")); + EXPECT_EQ(UTF8ToUTF16("2345"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr")); + EXPECT_EQ(UTF8ToUTF16("Mr"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr.")); + EXPECT_EQ(UTF8ToUTF16("Mr."), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mrs")); + EXPECT_EQ(UTF8ToUTF16("Mrs"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mrs.")); + EXPECT_EQ(UTF8ToUTF16("Mrs."), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr. & Mrs.")); + EXPECT_EQ(UTF8ToUTF16("Mr. & Mrs."), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr. & Mrs. Smith")); + EXPECT_EQ(UTF8ToUTF16("Mr. & Mrs. Smith"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Frau")); + EXPECT_EQ(UTF8ToUTF16("Frau"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Frau Doktor")); + EXPECT_EQ(UTF8ToUTF16("Frau Doktor"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Herr")); + EXPECT_EQ(UTF8ToUTF16("Herr"), company.GetRawInfo(COMPANY_NAME)); +} + +TEST(CompanyTest, CompanyNameSocialTitle) { base::test::ScopedFeatureList scoped_features; scoped_features.InitWithFeatures( - /*enabled_features=*/{features::kAutofillRejectCompanyBirthyear}, + /*enabled_features=*/{features::kAutofillRejectCompanySocialTitle}, /*disabled_features=*/{}); AutofillProfile profile; @@ -410,7 +306,7 @@ TEST(CompanyTest, CompanyNameYear) { EXPECT_EQ(UTF8ToUTF16("Google"), company.GetRawInfo(COMPANY_NAME)); company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1987")); - EXPECT_EQ(UTF8ToUTF16(""), company.GetRawInfo(COMPANY_NAME)); + EXPECT_EQ(UTF8ToUTF16("1987"), company.GetRawInfo(COMPANY_NAME)); company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("It was 1987.")); EXPECT_EQ(UTF8ToUTF16("It was 1987."), company.GetRawInfo(COMPANY_NAME)); @@ -424,7 +320,7 @@ TEST(CompanyTest, CompanyNameYear) { company.GetRawInfo(COMPANY_NAME)); company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("2019")); - EXPECT_EQ(UTF8ToUTF16(""), company.GetRawInfo(COMPANY_NAME)); + EXPECT_EQ(UTF8ToUTF16("2019"), company.GetRawInfo(COMPANY_NAME)); company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1818")); EXPECT_EQ(UTF8ToUTF16("1818"), company.GetRawInfo(COMPANY_NAME)); @@ -432,6 +328,33 @@ TEST(CompanyTest, CompanyNameYear) { company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("2345")); EXPECT_EQ(UTF8ToUTF16("2345"), company.GetRawInfo(COMPANY_NAME)); + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr")); + EXPECT_EQ(UTF8ToUTF16(""), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr.")); + EXPECT_EQ(UTF8ToUTF16(""), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mrs")); + EXPECT_EQ(UTF8ToUTF16(""), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mrs.")); + EXPECT_EQ(UTF8ToUTF16(""), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr. & Mrs.")); + EXPECT_EQ(UTF8ToUTF16("Mr. & Mrs."), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr. & Mrs. Smith")); + EXPECT_EQ(UTF8ToUTF16("Mr. & Mrs. Smith"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Frau")); + EXPECT_EQ(UTF8ToUTF16(""), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Frau Doktor")); + EXPECT_EQ(UTF8ToUTF16("Frau Doktor"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Herr")); + EXPECT_EQ(UTF8ToUTF16(""), company.GetRawInfo(COMPANY_NAME)); + profile.set_origin("Not empty"); ASSERT_TRUE(profile.IsVerified()); @@ -449,6 +372,33 @@ TEST(CompanyTest, CompanyNameYear) { company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("2345")); EXPECT_EQ(UTF8ToUTF16("2345"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr")); + EXPECT_EQ(UTF8ToUTF16("Mr"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr.")); + EXPECT_EQ(UTF8ToUTF16("Mr."), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mrs")); + EXPECT_EQ(UTF8ToUTF16("Mrs"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mrs.")); + EXPECT_EQ(UTF8ToUTF16("Mrs."), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr. & Mrs.")); + EXPECT_EQ(UTF8ToUTF16("Mr. & Mrs."), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Mr. & Mrs. Smith")); + EXPECT_EQ(UTF8ToUTF16("Mr. & Mrs. Smith"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Frau")); + EXPECT_EQ(UTF8ToUTF16("Frau"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Frau Doktor")); + EXPECT_EQ(UTF8ToUTF16("Frau Doktor"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Herr")); + EXPECT_EQ(UTF8ToUTF16("Herr"), company.GetRawInfo(COMPANY_NAME)); } TEST(CompanyTest, CompanyNameYearCopy) { @@ -488,4 +438,41 @@ TEST(CompanyTest, CompanyNameYearIsEqual) { EXPECT_EQ(company_old, company_young); } +TEST(CompanyTest, CompanyNameSocialTitleCopy) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{features::kAutofillRejectCompanySocialTitle}, + /*disabled_features=*/{}); + + AutofillProfile profile; + ASSERT_FALSE(profile.IsVerified()); + + CompanyInfo company_google(&profile); + CompanyInfo company_year(&profile); + + company_google.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Google")); + company_year.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Prof.")); + + company_google = company_year; + EXPECT_EQ(UTF8ToUTF16(""), company_google.GetRawInfo(COMPANY_NAME)); +} + +TEST(CompanyTest, CompanyNameSocialTitleIsEqual) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{features::kAutofillRejectCompanySocialTitle}, + /*disabled_features=*/{}); + + AutofillProfile profile; + ASSERT_FALSE(profile.IsVerified()); + + CompanyInfo company_old(&profile); + CompanyInfo company_young(&profile); + + company_old.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Dr")); + company_young.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Prof")); + + EXPECT_EQ(company_old, company_young); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/data_model/credit_card.cc b/chromium/components/autofill/core/browser/data_model/credit_card.cc index 4235a1b05a7..32c713d40c8 100644 --- a/chromium/components/autofill/core/browser/data_model/credit_card.cc +++ b/chromium/components/autofill/core/browser/data_model/credit_card.cc @@ -539,6 +539,7 @@ void CreditCard::operator=(const CreditCard& credit_card) { bank_name_ = credit_card.bank_name_; temp_card_first_name_ = credit_card.temp_card_first_name_; temp_card_last_name_ = credit_card.temp_card_last_name_; + cloud_token_data_ = credit_card.cloud_token_data_; set_guid(credit_card.guid()); set_origin(credit_card.origin()); @@ -707,6 +708,11 @@ bool CreditCard::HasValidCardNumber() const { return IsValidCreditCardNumber(number_); } +bool CreditCard::HasValidExpirationYear() const { + return IsValidCreditCardExpirationYear(expiration_year_, + AutofillClock::Now()); +} + bool CreditCard::HasValidExpirationDate() const { return IsValidCreditCardExpirationDate(expiration_year_, expiration_month_, AutofillClock::Now()); diff --git a/chromium/components/autofill/core/browser/data_model/credit_card.h b/chromium/components/autofill/core/browser/data_model/credit_card.h index 0a4c3d65e27..bb074847459 100644 --- a/chromium/components/autofill/core/browser/data_model/credit_card.h +++ b/chromium/components/autofill/core/browser/data_model/credit_card.h @@ -16,6 +16,7 @@ #include "base/strings/string_piece_forward.h" #include "build/build_config.h" #include "components/autofill/core/browser/data_model/autofill_data_model.h" +#include "components/sync/protocol/sync.pb.h" namespace autofill { @@ -142,6 +143,13 @@ class CreditCard : public AutofillDataModel { const std::string& server_id() const { return server_id_; } void set_server_id(const std::string& server_id) { server_id_ = server_id; } + const sync_pb::CloudTokenData& cloud_token_data() const { + return cloud_token_data_; + } + void set_cloud_token_data(const sync_pb::CloudTokenData& cloud_token_data) { + cloud_token_data_ = cloud_token_data; + } + // For use in STL containers. void operator=(const CreditCard& credit_card); @@ -190,6 +198,9 @@ class CreditCard : public AutofillDataModel { // not complete. bool HasValidCardNumber() const; + // Returns true if credit card has valid expiration year. + bool HasValidExpirationYear() const; + // Returns true if credit card has valid expiration date. bool HasValidExpirationDate() const; @@ -351,6 +362,9 @@ class CreditCard : public AutofillDataModel { // since we only store the full name. base::string16 temp_card_first_name_; base::string16 temp_card_last_name_; + + // Info of tokenizized credit card if available. + sync_pb::CloudTokenData cloud_token_data_; }; // So we can compare CreditCards with EXPECT_EQ(). diff --git a/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc b/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc index beda49cdaf0..c420cd5dc54 100644 --- a/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc +++ b/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc @@ -60,7 +60,7 @@ const char* const kInvalidNumbers[] = { // Use this function to generate a year in the future. base::string16 GetYearInTheFuture() { base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); + AutofillClock::Now().LocalExplode(&now); return base::NumberToString16(now.year + 4); } @@ -1023,7 +1023,7 @@ TEST(CreditCardTest, TEST(CreditCardTest, IsValidCardNumberAndExpiryDate) { CreditCard card; // Invalid because expired - const base::Time now(base::Time::Now()); + const base::Time now(AutofillClock::Now()); base::Time::Exploded now_exploded; now.LocalExplode(&now_exploded); card.SetRawInfo(CREDIT_CARD_EXP_MONTH, @@ -1547,7 +1547,7 @@ class ShouldUpdateExpirationTest class TestingTimes { public: TestingTimes() { - now_ = base::Time::Now(); + now_ = AutofillClock::Now(); (now_ - base::TimeDelta::FromDays(365)).LocalExplode(&last_year_); (now_ - base::TimeDelta::FromDays(31)).LocalExplode(&last_month_); now_.LocalExplode(¤t_); diff --git a/chromium/components/autofill/core/browser/field_types.h b/chromium/components/autofill/core/browser/field_types.h index 3080ba16f68..e874de0c453 100644 --- a/chromium/components/autofill/core/browser/field_types.h +++ b/chromium/components/autofill/core/browser/field_types.h @@ -189,9 +189,26 @@ enum ServerFieldType { // https://en.wikipedia.org/wiki/Unified_Payments_Interface UPI_VPA = 102, + // Just the street name of an address, no house number. + // Currently not used by Chrome. + ADDRESS_HOME_STREET = 103, + + // House number of an address, may be alphanumeric. + // Currently not used by Chrome. + ADDRESS_HOME_HOUSE_NUMBER = 104, + + // Floor within in a building, may be alphanumeric. + // Currently not used by Chrome. + ADDRESS_HOME_FLOOR = 105, + + // A catch-all for other type of subunits (only used until something more + // precise is defined). + // Currently not used by Chrome. + ADDRESS_HOME_OTHER_SUBUNIT = 106, + // No new types can be added without a corresponding change to the Autofill // server. - MAX_VALID_FIELD_TYPE = 103, + MAX_VALID_FIELD_TYPE = 107, }; // The list of all HTML autocomplete field type hints supported by Chrome. diff --git a/chromium/components/autofill/core/browser/form_data_importer.cc b/chromium/components/autofill/core/browser/form_data_importer.cc index 5851f7d6358..4323f547479 100644 --- a/chromium/components/autofill/core/browser/form_data_importer.cc +++ b/chromium/components/autofill/core/browser/form_data_importer.cc @@ -103,6 +103,8 @@ FormDataImporter::FormDataImporter(AutofillClient* client, payments_client, app_locale, personal_data_manager)), + upi_vpa_save_manager_( + std::make_unique<UpiVpaSaveManager>(personal_data_manager)), local_card_migration_manager_( std::make_unique<LocalCardMigrationManager>(client, payments_client, @@ -118,6 +120,7 @@ void FormDataImporter::ImportFormData(const FormStructure& submitted_form, bool profile_autofill_enabled, bool credit_card_autofill_enabled) { std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> detected_vpa; bool is_credit_card_upstream_enabled = credit_card_save_manager_->IsCreditCardUploadEnabled(); @@ -128,7 +131,13 @@ void FormDataImporter::ImportFormData(const FormStructure& submitted_form, ImportFormData(submitted_form, profile_autofill_enabled, credit_card_autofill_enabled, /*should_return_local_card=*/is_credit_card_upstream_enabled, - &imported_credit_card); + &imported_credit_card, &detected_vpa); + + if (detected_vpa && credit_card_autofill_enabled && + base::FeatureList::IsEnabled(features::kAutofillSaveAndFillVPA)) { + upi_vpa_save_manager_->OfferLocalSave(*detected_vpa); + } + // If no card was successfully imported from the form, return. if (imported_credit_card_record_type_ == ImportedCreditCardRecordType::NO_CARD) { @@ -214,7 +223,8 @@ bool FormDataImporter::ImportFormData( bool profile_autofill_enabled, bool credit_card_autofill_enabled, bool should_return_local_card, - std::unique_ptr<CreditCard>* imported_credit_card) { + std::unique_ptr<CreditCard>* imported_credit_card, + base::Optional<std::string>* imported_vpa) { // We try the same |form| for both credit card and address import/update. // - ImportCreditCard may update an existing card, or fill // |imported_credit_card| with an extracted card. See .h for details of @@ -226,6 +236,7 @@ bool FormDataImporter::ImportFormData( if (credit_card_autofill_enabled) { cc_import = ImportCreditCard(submitted_form, should_return_local_card, imported_credit_card); + *imported_vpa = ImportVPA(submitted_form); } // - ImportAddressProfiles may eventually save or update one or more address // profiles. @@ -233,7 +244,8 @@ bool FormDataImporter::ImportFormData( if (profile_autofill_enabled) { address_import = ImportAddressProfiles(submitted_form); } - if (cc_import || address_import) + + if (cc_import || address_import || imported_vpa->has_value()) return true; personal_data_manager_->MarkObserversInsufficientFormDataForImport(); @@ -535,4 +547,13 @@ CreditCard FormDataImporter::ExtractCreditCardFromForm( return candidate_credit_card; } +base::Optional<std::string> FormDataImporter::ImportVPA( + const FormStructure& form) { + for (const auto& field : form) { + if (IsUPIVirtualPaymentAddress(field->value)) + return base::UTF16ToUTF8(field->value); + } + return base::nullopt; +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/form_data_importer.h b/chromium/components/autofill/core/browser/form_data_importer.h index 1fd598e0ba2..e81346a28bf 100644 --- a/chromium/components/autofill/core/browser/form_data_importer.h +++ b/chromium/components/autofill/core/browser/form_data_importer.h @@ -17,8 +17,11 @@ #include "components/autofill/core/browser/payments/credit_card_save_manager.h" #include "components/autofill/core/browser/payments/local_card_migration_manager.h" #include "components/autofill/core/browser/payments/payments_client.h" +#include "components/autofill/core/browser/payments/upi_vpa_save_manager.h" #include "components/autofill/core/browser/personal_data_manager.h" +class SaveCardOfferObserver; + namespace autofill { // Manages logic for importing address profiles and credit card information from @@ -87,13 +90,16 @@ class FormDataImporter { // data. If the form contains credit card data already present in a local // credit card entry *and* |should_return_local_card| is true, the data is // stored into |imported_credit_card| so that we can prompt the user whether - // to upload it. Returns |true| if sufficient address or credit card data + // to upload it. If the form contains UPI/VPA data and + // |credit_card_autofill_enabled| is true, the VPA value will be stored into + // |imported_vpa|. Returns |true| if sufficient address or credit card data // was found. Exposed for testing. bool ImportFormData(const FormStructure& form, bool profile_autofill_enabled, bool credit_card_autofill_enabled, bool should_return_local_card, - std::unique_ptr<CreditCard>* imported_credit_card); + std::unique_ptr<CreditCard>* imported_credit_card, + base::Optional<std::string>* imported_vpa); // Go through the |form| fields and attempt to extract and import valid // address profiles. Returns true on extraction success of at least one @@ -120,6 +126,10 @@ class FormDataImporter { CreditCard ExtractCreditCardFromForm(const FormStructure& form, bool* hasDuplicateFieldType); + // Go through the |form| fields and find a UPI/VPA value to import. The return + // value will be empty if no VPA was found. + base::Optional<std::string> ImportVPA(const FormStructure& form); + // Whether a dynamic change form is imported. bool from_dynamic_change_form_ = false; @@ -133,6 +143,9 @@ class FormDataImporter { // Responsible for managing credit card save flows (local or upload). std::unique_ptr<CreditCardSaveManager> credit_card_save_manager_; + // Responsible for managing UPI/VPA save flows. + std::unique_ptr<UpiVpaSaveManager> upi_vpa_save_manager_; + // Responsible for migrating locally saved credit cards to Google Pay. std::unique_ptr<LocalCardMigrationManager> local_card_migration_manager_; @@ -155,6 +168,7 @@ class FormDataImporter { friend class LocalCardMigrationBrowserTest; friend class SaveCardBubbleViewsFullFormBrowserTest; friend class SaveCardInfobarEGTestHelper; + friend class ::SaveCardOfferObserver; FRIEND_TEST_ALL_PREFIXES(AutofillMergeTest, MergeProfiles); FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, AllowDuplicateMaskedServerCardIfFlagEnabled); @@ -197,6 +211,8 @@ class FormDataImporter { ImportFormData_SecondImportResetsCreditCardRecordType); FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, ImportFormData_TwoAddressesOneCreditCard); + FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, + ImportFormData_DontSetVPAWhenOnlyCreditCardExists); FRIEND_TEST_ALL_PREFIXES( FormDataImporterTest, Metrics_SubmittedServerCardExpirationStatus_FullServerCardMatch); @@ -218,6 +234,9 @@ class FormDataImporter { FRIEND_TEST_ALL_PREFIXES( FormDataImporterTest, Metrics_SubmittedDifferentServerCardExpirationStatus_EmptyExpirationYear); + FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, ImportVPA); + FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, ImportVPADisabled); + FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, ImportVPAIgnoreNonVPA); DISALLOW_COPY_AND_ASSIGN(FormDataImporter); }; diff --git a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc index 703f2ae0d00..55ec7e1b5b8 100644 --- a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc +++ b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc @@ -223,8 +223,8 @@ class FormDataImporterTestBase { run_loop.Run(); } - base::test::TaskEnvironment task_environment_{ - base::test::TaskEnvironment::MainThreadType::UI}; + base::test::SingleThreadTaskEnvironment task_environment_{ + base::test::SingleThreadTaskEnvironment::MainThreadType::UI}; std::unique_ptr<PrefService> prefs_; scoped_refptr<AutofillWebDataService> autofill_database_service_; scoped_refptr<WebDatabaseService> web_database_; @@ -2138,10 +2138,11 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/true, &imported_credit_card)); + /*should_return_local_card=*/true, &imported_credit_card, &imported_vpa)); ASSERT_TRUE(imported_credit_card); // |imported_credit_card_record_type_| should be LOCAL_CARD because upload was // offered and the card is a local card already on the device. @@ -2163,7 +2164,8 @@ TEST_F(FormDataImporterTest, EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure2, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/true, &imported_credit_card2)); + /*should_return_local_card=*/true, &imported_credit_card2, + &imported_vpa)); ASSERT_TRUE(imported_credit_card2); // |imported_credit_card_record_type_| should be NEW_CARD because the imported // card is not already on the device. @@ -2202,7 +2204,8 @@ TEST_F(FormDataImporterTest, EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure3, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/false, - /*should_return_local_card=*/true, &imported_credit_card3)); + /*should_return_local_card=*/true, &imported_credit_card3, + &imported_vpa)); // |imported_credit_card_record_type_| should be NO_CARD because no valid card // was imported from the form. ASSERT_TRUE(form_data_importer_->imported_credit_card_record_type_ == @@ -2222,10 +2225,11 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/true, &imported_credit_card)); + /*should_return_local_card=*/true, &imported_credit_card, &imported_vpa)); ASSERT_TRUE(imported_credit_card); // |imported_credit_card_record_type_| should be NEW_CARD because the imported // card is not already on the device. @@ -2259,10 +2263,11 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/true, &imported_credit_card)); + /*should_return_local_card=*/true, &imported_credit_card, &imported_vpa)); ASSERT_TRUE(imported_credit_card); // |imported_credit_card_record_type_| should be LOCAL_CARD because upload was // offered and the card is a local card already on the device. @@ -2296,10 +2301,11 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/true, &imported_credit_card)); + /*should_return_local_card=*/true, &imported_credit_card, &imported_vpa)); ASSERT_FALSE(imported_credit_card); // |imported_credit_card_record_type_| should be SERVER_CARD. ASSERT_TRUE(form_data_importer_->imported_credit_card_record_type_ == @@ -2332,10 +2338,11 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/true, &imported_credit_card)); + /*should_return_local_card=*/true, &imported_credit_card, &imported_vpa)); ASSERT_FALSE(imported_credit_card); // |imported_credit_card_record_type_| should be SERVER_CARD. ASSERT_TRUE(form_data_importer_->imported_credit_card_record_type_ == @@ -2355,10 +2362,11 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/true, &imported_credit_card)); + /*should_return_local_card=*/true, &imported_credit_card, &imported_vpa)); ASSERT_FALSE(imported_credit_card); // |imported_credit_card_record_type_| should be NO_CARD because no valid card // was successfully imported from the form. @@ -2382,10 +2390,11 @@ TEST_F( FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/true, &imported_credit_card)); + /*should_return_local_card=*/true, &imported_credit_card, &imported_vpa)); ASSERT_FALSE(imported_credit_card); // |imported_credit_card_record_type_| should be NO_CARD because no valid card // was successfully imported from the form. @@ -2409,10 +2418,11 @@ TEST_F( FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/true, &imported_credit_card)); + /*should_return_local_card=*/true, &imported_credit_card, &imported_vpa)); ASSERT_TRUE(imported_credit_card); // |imported_credit_card_record_type_| should be NEW_CARD because card was // successfully imported from the form via the expiration date fix flow. @@ -2450,10 +2460,11 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/true, &imported_credit_card)); + /*should_return_local_card=*/true, &imported_credit_card, &imported_vpa)); ASSERT_FALSE(imported_credit_card); // |imported_credit_card_record_type_| should be NO_CARD because the form // doesn't have credit card section. @@ -2497,11 +2508,13 @@ TEST_F(FormDataImporterTest, ImportFormData_OneAddressOneCreditCard) { FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); ASSERT_TRUE(imported_credit_card); personal_data_manager_->OnAcceptedLocalCreditCardSave(*imported_credit_card); @@ -2583,11 +2596,13 @@ TEST_F(FormDataImporterTest, ImportFormData_TwoAddressesOneCreditCard) { .WillRepeatedly(QuitMessageLoop(&run_loop)); EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) .Times(testing::AnyNumber()); + base::Optional<std::string> imported_vpa; // Still returns true because the credit card import was successful. EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); run_loop.Run(); ASSERT_TRUE(imported_credit_card); @@ -2642,10 +2657,12 @@ TEST_F(FormDataImporterTest, ImportFormData_AddressesDisabledOneCreditCard) { FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/false, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); ASSERT_TRUE(imported_credit_card); personal_data_manager_->OnAcceptedLocalCreditCardSave(*imported_credit_card); @@ -2698,11 +2715,13 @@ TEST_F(FormDataImporterTest, ImportFormData_OneAddressCreditCardDisabled) { FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/false, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); ASSERT_FALSE(imported_credit_card); WaitForOnPersonalDataChanged(); @@ -2758,11 +2777,13 @@ TEST_F(FormDataImporterTest, ImportFormData_AddressCreditCardDisabled) { FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/false, /*credit_card_autofill_enabled=*/false, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); ASSERT_FALSE(imported_credit_card); // Test that addresses were not saved. @@ -2815,10 +2836,12 @@ TEST_F(FormDataImporterTest, DontDuplicateMaskedServerCard) { FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); ASSERT_FALSE(imported_credit_card); } @@ -2852,11 +2875,13 @@ TEST_F(FormDataImporterTest, ImportFormData_HiddenCreditCardFormAfterEntered) { FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; // Still returns true because the credit card import was successful. EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); ASSERT_TRUE(imported_credit_card); personal_data_manager_->OnAcceptedLocalCreditCardSave(*imported_credit_card); @@ -2872,6 +2897,27 @@ TEST_F(FormDataImporterTest, ImportFormData_HiddenCreditCardFormAfterEntered) { EXPECT_EQ(0, expected_card.Compare(*results[0])); } +// Ensures that no VPA value is returned when there's a credit card and no VPA. +TEST_F(FormDataImporterTest, + ImportFormData_DontSetVPAWhenOnlyCreditCardExists) { + // Simulate a form submission with a new credit card. + FormData form; + form.url = GURL("https://wwww.foo.com"); + + AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", + "2999"); + + FormStructure form_structure(form); + form_structure.DetermineHeuristicTypes(); + std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; + EXPECT_TRUE(form_data_importer_->ImportFormData( + form_structure, /*profile_autofill_enabled=*/true, + /*credit_card_autofill_enabled=*/true, + /*should_return_local_card=*/true, &imported_credit_card, &imported_vpa)); + ASSERT_FALSE(imported_vpa.has_value()); +} + TEST_F(FormDataImporterTest, DontDuplicateFullServerCard) { EnableWalletCardImport(); @@ -2914,11 +2960,13 @@ TEST_F(FormDataImporterTest, DontDuplicateFullServerCard) { FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); EXPECT_FALSE(imported_credit_card); } @@ -2959,11 +3007,13 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); EXPECT_FALSE(imported_credit_card); histogram_tester.ExpectUniqueSample( "Autofill.SubmittedServerCardExpirationStatus", @@ -3010,11 +3060,13 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); EXPECT_FALSE(imported_credit_card); } @@ -3058,11 +3110,13 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); EXPECT_FALSE(imported_credit_card); } @@ -3107,11 +3161,13 @@ TEST_F( FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); EXPECT_TRUE(imported_credit_card); } @@ -3153,11 +3209,13 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); EXPECT_FALSE(imported_credit_card); histogram_tester.ExpectUniqueSample( "Autofill.SubmittedServerCardExpirationStatus", @@ -3202,11 +3260,13 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); EXPECT_FALSE(imported_credit_card); histogram_tester.ExpectUniqueSample( "Autofill.SubmittedServerCardExpirationStatus", @@ -3252,14 +3312,86 @@ TEST_F(FormDataImporterTest, FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + base::Optional<std::string> imported_vpa; EXPECT_FALSE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, - /*should_return_local_card=*/false, &imported_credit_card)); + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); EXPECT_FALSE(imported_credit_card); histogram_tester.ExpectUniqueSample( "Autofill.SubmittedServerCardExpirationStatus", AutofillMetrics::MASKED_SERVER_CARD_EXPIRATION_DATE_DID_NOT_MATCH, 1); } +TEST_F(FormDataImporterTest, ImportVPA) { + FormData form; + form.url = GURL("https://wwww.foo.com"); + + FormFieldData field; + test::CreateTestFormField("VPA:", "vpa", "user@indianbank", "text", &field); + form.fields.push_back(field); + + FormStructure form_structure(form); + form_structure.DetermineHeuristicTypes(); + + std::unique_ptr<CreditCard> imported_credit_card; // Discarded. + base::Optional<std::string> imported_vpa; + + EXPECT_TRUE(form_data_importer_->ImportFormData( + form_structure, /*profile_autofill_enabled=*/false, + /*credit_card_autofill_enabled=*/true, + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); + + ASSERT_TRUE(imported_vpa.has_value()); + EXPECT_EQ(imported_vpa.value(), "user@indianbank"); +} + +TEST_F(FormDataImporterTest, ImportVPADisabled) { + FormData form; + form.url = GURL("https://wwww.foo.com"); + + FormFieldData field; + test::CreateTestFormField("VPA:", "vpa", "user@indianbank", "text", &field); + form.fields.push_back(field); + + FormStructure form_structure(form); + form_structure.DetermineHeuristicTypes(); + + std::unique_ptr<CreditCard> imported_credit_card; // Discarded. + base::Optional<std::string> imported_vpa; + + EXPECT_FALSE(form_data_importer_->ImportFormData( + form_structure, /*profile_autofill_enabled=*/false, + /*credit_card_autofill_enabled=*/false, + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); + + EXPECT_FALSE(imported_vpa.has_value()); +} + +TEST_F(FormDataImporterTest, ImportVPAIgnoreNonVPA) { + FormData form; + form.url = GURL("https://wwww.foo.com"); + + FormFieldData field; + test::CreateTestFormField("VPA:", "vpa", "user@gmail.com", "text", &field); + form.fields.push_back(field); + + FormStructure form_structure(form); + form_structure.DetermineHeuristicTypes(); + + std::unique_ptr<CreditCard> imported_credit_card; // Discarded. + base::Optional<std::string> imported_vpa; + + EXPECT_FALSE(form_data_importer_->ImportFormData( + form_structure, /*profile_autofill_enabled=*/false, + /*credit_card_autofill_enabled=*/false, + /*should_return_local_card=*/false, &imported_credit_card, + &imported_vpa)); + + EXPECT_FALSE(imported_vpa.has_value()); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/form_parsing/autofill_scanner.h b/chromium/components/autofill/core/browser/form_parsing/autofill_scanner.h index 336e5562852..5adf96d9ccd 100644 --- a/chromium/components/autofill/core/browser/form_parsing/autofill_scanner.h +++ b/chromium/components/autofill/core/browser/form_parsing/autofill_scanner.h @@ -45,9 +45,6 @@ class AutofillScanner { // |RewindTo()|. size_t SaveCursor(); - // This is only for logging purposes. - size_t CursorIndex() { return static_cast<size_t>(cursor_ - begin_); } - private: void Init(const std::vector<AutofillField*>& fields); diff --git a/chromium/components/autofill/core/browser/form_parsing/field_candidates.cc b/chromium/components/autofill/core/browser/form_parsing/field_candidates.cc index f3dc3b5b9dc..e60965ab5a8 100644 --- a/chromium/components/autofill/core/browser/form_parsing/field_candidates.cc +++ b/chromium/components/autofill/core/browser/form_parsing/field_candidates.cc @@ -45,8 +45,4 @@ ServerFieldType FieldCandidates::BestHeuristicType() const { return static_cast<ServerFieldType>(index); } -const std::vector<FieldCandidate>& FieldCandidates::field_candidates() const { - return field_candidates_; -} - } // namespace autofill diff --git a/chromium/components/autofill/core/browser/form_parsing/field_candidates.h b/chromium/components/autofill/core/browser/form_parsing/field_candidates.h index d4520921f42..f1ef7246213 100644 --- a/chromium/components/autofill/core/browser/form_parsing/field_candidates.h +++ b/chromium/components/autofill/core/browser/form_parsing/field_candidates.h @@ -44,11 +44,6 @@ class FieldCandidates { // Determines the best type based on the current possible types. ServerFieldType BestHeuristicType() const; - // Returns the underlying candidates. - // - // This reference is only valid while the FieldCandidates object is valid. - const std::vector<FieldCandidate>& field_candidates() const; - private: // Internal storage for all the possible types for a given field. std::vector<FieldCandidate> field_candidates_; diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field.cc b/chromium/components/autofill/core/browser/form_parsing/form_field.cc index 266bd688bfe..d801580967b 100644 --- a/chromium/components/autofill/core/browser/form_parsing/form_field.cc +++ b/chromium/components/autofill/core/browser/form_parsing/form_field.cc @@ -17,7 +17,6 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_field.h" -#include "components/autofill/core/browser/autofill_internals_service.h" #include "components/autofill/core/browser/form_parsing/address_field.h" #include "components/autofill/core/browser/form_parsing/autofill_scanner.h" #include "components/autofill/core/browser/form_parsing/credit_card_field.h" diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc index 22b536cd140..542afd7f8b3 100644 --- a/chromium/components/autofill/core/browser/form_structure.cc +++ b/chromium/components/autofill/core/browser/form_structure.cc @@ -35,21 +35,25 @@ #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/form_parsing/field_candidates.h" #include "components/autofill/core/browser/form_parsing/form_field.h" -#include "components/autofill/core/browser/logging/log_buffer.h" +#include "components/autofill/core/browser/logging/log_manager.h" #include "components/autofill/core/browser/proto/legacy_proto_bridge.h" #include "components/autofill/core/browser/randomized_encoder.h" #include "components/autofill/core/browser/rationalization_util.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_internals/log_message.h" +#include "components/autofill/core/common/autofill_internals/logging_scope.h" #include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_regex_constants.h" #include "components/autofill/core/common/autofill_regexes.h" +#include "components/autofill/core/common/autofill_tick_clock.h" #include "components/autofill/core/common/autofill_util.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_data_predictions.h" #include "components/autofill/core/common/form_field_data.h" #include "components/autofill/core/common/form_field_data_predictions.h" +#include "components/autofill/core/common/logging/log_buffer.h" #include "components/autofill/core/common/signatures_util.h" #include "components/security_state/core/security_state.h" #include "url/origin.h" @@ -409,13 +413,6 @@ void EncodePasswordAttributesVote( upload->set_password_has_lowercase_letter( password_attributes_vote.second); break; - case PasswordAttribute::kHasUppercaseLetter: - upload->set_password_has_uppercase_letter( - password_attributes_vote.second); - break; - case PasswordAttribute::kHasNumeric: - upload->set_password_has_numeric(password_attributes_vote.second); - break; case PasswordAttribute::kHasSpecialSymbol: upload->set_password_has_special_symbol(password_attributes_vote.second); if (password_attributes_vote.second) @@ -568,22 +565,13 @@ FormStructure::FormStructure(const FormData& form) name_attribute_(form.name_attribute), form_name_(form.name), button_titles_(form.button_titles), - submission_event_(SubmissionIndicatorEvent::NONE), source_url_(form.url), target_url_(form.action), main_frame_origin_(form.main_frame_origin), - autofill_count_(0), - active_field_count_(0), - upload_required_(USE_UPLOAD_RATES), - has_author_specified_types_(false), - has_author_specified_sections_(false), - has_author_specified_upi_vpa_hint_(false), - was_parsed_for_autocomplete_attributes_(false), - has_password_field_(false), is_form_tag_(form.is_form_tag), is_formless_checkout_(form.is_formless_checkout), all_fields_are_passwords_(!form.fields.empty()), - form_parsed_timestamp_(base::TimeTicks::Now()), + form_parsed_timestamp_(AutofillTickClock::NowTicks()), passwords_were_revealed_(false), password_symbol_vote_(0), developer_engagement_metrics_(0), @@ -613,10 +601,19 @@ FormStructure::FormStructure(const FormData& form) ProcessExtractedFields(); } -FormStructure::~FormStructure() {} +FormStructure::FormStructure( + FormSignature form_signature, + const std::vector<FieldSignature>& field_signatures) + : form_signature_(form_signature) { + for (const auto& signature : field_signatures) + fields_.push_back(AutofillField::CreateForPasswordManagerUpload(signature)); +} + +FormStructure::~FormStructure() = default; void FormStructure::DetermineHeuristicTypes(LogManager* log_manager) { - const auto determine_heuristic_types_start_time = base::TimeTicks::Now(); + const auto determine_heuristic_types_start_time = + AutofillTickClock::NowTicks(); // First, try to detect field types based on each field's |autocomplete| // attribute value. @@ -660,7 +657,7 @@ void FormStructure::DetermineHeuristicTypes(LogManager* log_manager) { RationalizeFieldTypePredictions(); AutofillMetrics::LogDetermineHeuristicTypesTiming( - base::TimeTicks::Now() - determine_heuristic_types_start_time); + AutofillTickClock::NowTicks() - determine_heuristic_types_start_time); } bool FormStructure::EncodeUploadRequest( @@ -826,6 +823,14 @@ void FormStructure::ProcessQueryResponse( if (heuristic_type != UNKNOWN_TYPE) heuristics_detected_fillable_field = true; + // Clears the server prediction for CVC-fields if the corresponding Finch + // feature is not enabled. + if (!base::FeatureList::IsEnabled( + autofill::features::kAutofillUseServerCVCPrediction) && + field_type == ServerFieldType::CREDIT_CARD_VERIFICATION_CODE) { + field_type = ServerFieldType::NO_SERVER_DATA; + } + field->set_server_type(field_type); std::vector<AutofillQueryResponseContents::Field::FieldPrediction> server_predictions; @@ -913,6 +918,14 @@ bool FormStructure::IsAutofillFieldMetadataEnabled() { return base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE); } +std::unique_ptr<FormStructure> FormStructure::CreateForPasswordManagerUpload( + FormSignature form_signature, + const std::vector<FieldSignature>& field_signatures) { + std::unique_ptr<FormStructure> form; + form.reset(new FormStructure(form_signature, field_signatures)); + return form; +} + std::string FormStructure::FormSignatureAsStr() const { return base::NumberToString(form_signature()); } @@ -951,10 +964,15 @@ void FormStructure::UpdateAutofillCount() { } } -bool FormStructure::ShouldBeParsed() const { +bool FormStructure::ShouldBeParsed(LogManager* log_manager) const { // Exclude URLs not on the web via HTTP(S). - if (!HasAllowedScheme(source_url_)) + if (!HasAllowedScheme(source_url_)) { + if (log_manager) { + log_manager->Log() << LoggingScope::kAbortParsing + << LogMessage::kAbortParsingNotAllowedScheme << *this; + } return false; + } size_t min_required_fields = std::min({MinRequiredFieldsForHeuristics(), MinRequiredFieldsForQuery(), @@ -963,6 +981,11 @@ bool FormStructure::ShouldBeParsed() const { (!all_fields_are_passwords() || active_field_count() < kRequiredFieldsForFormsWithOnlyPasswordFields) && !has_author_specified_types_) { + if (log_manager) { + log_manager->Log() << LoggingScope::kAbortParsing + << LogMessage::kAbortParsingNotEnoughFields + << active_field_count() << *this; + } return false; } @@ -971,6 +994,11 @@ bool FormStructure::ShouldBeParsed() const { base::UTF8ToUTF16(kUrlSearchActionRe); if (MatchesPattern(base::UTF8ToUTF16(target_url_.path_piece()), kUrlSearchActionPattern)) { + if (log_manager) { + log_manager->Log() << LoggingScope::kAbortParsing + << LogMessage::kAbortParsingUrlMatchesSearchRegex + << *this; + } return false; } @@ -979,6 +1007,11 @@ bool FormStructure::ShouldBeParsed() const { has_text_field |= it->form_control_type != "select-one"; } + if (!has_text_field && log_manager) { + log_manager->Log() << LoggingScope::kAbortParsing + << LogMessage::kAbortParsingFormHasNoTextfield << *this; + } + return has_text_field; } @@ -1031,9 +1064,7 @@ void FormStructure::RetrieveFromCache( bool is_credit_card_field = AutofillType(cached_field->second->Type().GetStorableType()) .group() == CREDIT_CARD; - if (should_keep_cached_value && is_credit_card_field && - base::FeatureList::IsEnabled( - features::kAutofillImportDynamicForms)) { + if (should_keep_cached_value && is_credit_card_field) { field->value = cached_field->second->value; value_from_dynamic_change_form_ = true; } else if (field->value == cached_field->second->value) { @@ -2194,6 +2225,7 @@ LogBuffer& operator<<(LogBuffer& buffer, const FormStructure& form) { base::NumberToString( HashFormSignature(form.form_signature()))}); buffer << Tr{} << "Form name:" << form.form_name(); + buffer << Tr{} << "Unique renderer Id:" << form.unique_renderer_id(); buffer << Tr{} << "Target URL:" << form.target_url(); for (size_t i = 0; i < form.field_count(); ++i) { buffer << Tag{"tr"}; diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h index 7a90138c297..4117c49e0aa 100644 --- a/chromium/components/autofill/core/browser/form_structure.h +++ b/chromium/components/autofill/core/browser/form_structure.h @@ -44,8 +44,6 @@ class LogManager; // Password attributes (whether a password has special symbols, numeric, etc.) enum class PasswordAttribute { kHasLowercaseLetter, - kHasUppercaseLetter, - kHasNumeric, kHasSpecialSymbol, kPasswordAttributesCount }; @@ -111,6 +109,13 @@ class FormStructure { // Returns whether sending autofill field metadata to the server is enabled. static bool IsAutofillFieldMetadataEnabled(); + // Creates FormStructure that has bare minimum information for uploading + // votes, namely form and field signatures. Warning: do not use for Autofill + // code, since it is likely missing some fields. + static std::unique_ptr<FormStructure> CreateForPasswordManagerUpload( + FormSignature form_signature, + const std::vector<FieldSignature>& field_signatures); + // Return the form signature as string. std::string FormSignatureAsStr() const; @@ -130,7 +135,7 @@ class FormStructure { void UpdateAutofillCount(); // Returns true if this form matches the structural requirements for Autofill. - bool ShouldBeParsed() const; + bool ShouldBeParsed(LogManager* log_manager = nullptr) const; // Returns true if heuristic autofill type detection should be attempted for // this form. @@ -237,10 +242,6 @@ class FormStructure { return has_author_specified_types_; } - bool has_author_specified_sections() const { - return has_author_specified_sections_; - } - bool has_author_specified_upi_vpa_hint() const { return has_author_specified_upi_vpa_hint_; } @@ -414,6 +415,9 @@ class FormStructure { size_t current_section_ptr = 0; }; + FormStructure(FormSignature form_signature, + const std::vector<FieldSignature>& field_signatures); + // A function to fine tune the credit cards related predictions. For example: // lone credit card fields in an otherwise non-credit-card related form is // unlikely to be correct, the function will override that prediction. @@ -526,7 +530,8 @@ class FormStructure { // The type of the event that was taken as an indication that the form has // been successfully submitted. - mojom::SubmissionIndicatorEvent submission_event_; + mojom::SubmissionIndicatorEvent submission_event_ = + mojom::SubmissionIndicatorEvent::NONE; // The source URL. GURL source_url_; @@ -538,50 +543,50 @@ class FormStructure { url::Origin main_frame_origin_; // The number of fields able to be auto-filled. - size_t autofill_count_; + size_t autofill_count_ = 0; // A vector of all the input fields in the form. std::vector<std::unique_ptr<AutofillField>> fields_; // The number of fields that are part of the form signature and that are // included in queries to the Autofill server. - size_t active_field_count_; + size_t active_field_count_ = 0; // Whether the server expects us to always upload, never upload, or default // to the stored upload rates. - UploadRequired upload_required_; + UploadRequired upload_required_ = USE_UPLOAD_RATES; // Whether the form includes any field types explicitly specified by the site // author, via the |autocompletetype| attribute. - bool has_author_specified_types_; + bool has_author_specified_types_ = false; // Whether the form includes any sections explicitly specified by the site // author, via the autocomplete attribute. - bool has_author_specified_sections_; + bool has_author_specified_sections_ = false; // Whether the form includes a field that explicitly sets it autocomplete // type to "upi-vpa". - bool has_author_specified_upi_vpa_hint_; + bool has_author_specified_upi_vpa_hint_ = false; // Whether the form was parsed for autocomplete attribute, thus assigning // the real values of |has_author_specified_types_| and // |has_author_specified_sections_|. - bool was_parsed_for_autocomplete_attributes_; + bool was_parsed_for_autocomplete_attributes_ = false; // True if the form contains at least one password field. - bool has_password_field_; + bool has_password_field_ = false; // True if the form is a <form>. - bool is_form_tag_; + bool is_form_tag_ = true; // True if the form is made of unowned fields (i.e., not within a <form> tag) // in what appears to be a checkout flow. This attribute is only calculated // and used if features::kAutofillRestrictUnownedFieldsToFormlessCheckout is // enabled, to prevent heuristics from running on formless non-checkout. - bool is_formless_checkout_; + bool is_formless_checkout_ = false; // True if all form fields are password fields. - bool all_fields_are_passwords_; + bool all_fields_are_passwords_ = false; // The unique signature for this form, composed of the target url domain, // the form name, and the form field names in a 64-bit hash. @@ -595,7 +600,7 @@ class FormStructure { // True iff the form is a password form and the user has seen the password // value before accepting the prompt to save. Used for crowdsourcing. - bool passwords_were_revealed_; + bool passwords_were_revealed_ = false; // The vote about password attributes (e.g. whether the password has a numeric // character). @@ -605,7 +610,7 @@ class FormStructure { // field contains nosified information about a special symbol in a // user-created password stored as ASCII code. The default value of 0 // indicates that no symbol was set. - int password_symbol_vote_; + int password_symbol_vote_ = 0; // Noisified password length for crowdsourcing. If |password_attributes_vote_| // has no value, |password_length_vote_| should be ignored. @@ -614,7 +619,7 @@ class FormStructure { // Used to record whether developer has used autocomplete markup or // UPI-VPA hints, This is a bitmask of DeveloperEngagementMetric and set in // DetermineHeuristicTypes(). - int developer_engagement_metrics_; + int developer_engagement_metrics_ = 0; mojom::SubmissionSource submission_source_ = mojom::SubmissionSource::NONE; @@ -634,7 +639,6 @@ class FormStructure { }; LogBuffer& operator<<(LogBuffer& buffer, const FormStructure& form); - } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_STRUCTURE_H_ diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc index 7ebf1c72000..f0b086f2d8c 100644 --- a/chromium/components/autofill/core/browser/form_structure_unittest.cc +++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc @@ -2592,7 +2592,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMatchingValidities) { form_structure = std::make_unique<FormStructure>(form); form_structure->set_password_attributes_vote( - std::make_pair(PasswordAttribute::kHasNumeric, true)); + std::make_pair(PasswordAttribute::kHasLowercaseLetter, true)); form_structure->set_password_length_vote(10u); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); @@ -2623,7 +2623,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMatchingValidities) { upload.set_autofill_used(false); upload.set_data_present("144200030e"); upload.set_passwords_revealed(false); - upload.set_password_has_numeric(true); + upload.set_password_has_lowercase_letter(true); upload.set_password_length(10u); upload.set_action_signature(15724779818122431245U); upload.set_submission_event( @@ -2685,7 +2685,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMatchingValidities) { form_structure = std::make_unique<FormStructure>(form); form_structure->set_password_attributes_vote( - std::make_pair(PasswordAttribute::kHasNumeric, true)); + std::make_pair(PasswordAttribute::kHasLowercaseLetter, true)); form_structure->set_password_length_vote(10u); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); @@ -2787,7 +2787,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithNonMatchingValidities) { form_structure = std::make_unique<FormStructure>(form); form_structure->set_password_attributes_vote( - std::make_pair(PasswordAttribute::kHasNumeric, true)); + std::make_pair(PasswordAttribute::kHasLowercaseLetter, true)); form_structure->set_password_length_vote(10u); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); @@ -2818,7 +2818,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithNonMatchingValidities) { upload.set_autofill_used(false); upload.set_data_present("144200030e"); upload.set_passwords_revealed(false); - upload.set_password_has_numeric(true); + upload.set_password_has_lowercase_letter(true); upload.set_password_length(10u); upload.set_action_signature(15724779818122431245U); @@ -2918,7 +2918,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMultipleValidities) { form_structure = std::make_unique<FormStructure>(form); form_structure->set_password_attributes_vote( - std::make_pair(PasswordAttribute::kHasNumeric, true)); + std::make_pair(PasswordAttribute::kHasLowercaseLetter, true)); form_structure->set_password_length_vote(10u); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); @@ -2949,7 +2949,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMultipleValidities) { upload.set_autofill_used(false); upload.set_data_present("144200030e"); upload.set_passwords_revealed(false); - upload.set_password_has_numeric(true); + upload.set_password_has_lowercase_letter(true); upload.set_password_length(10u); upload.set_action_signature(15724779818122431245U); upload.set_submission_event( @@ -3044,7 +3044,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest) { form_structure = std::make_unique<FormStructure>(form); form_structure->set_password_attributes_vote( - std::make_pair(PasswordAttribute::kHasNumeric, true)); + std::make_pair(PasswordAttribute::kHasLowercaseLetter, true)); form_structure->set_password_length_vote(10u); form_structure->set_submission_event( SubmissionIndicatorEvent::HTML_FORM_SUBMISSION); @@ -3078,7 +3078,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest) { upload.set_autofill_used(false); upload.set_data_present("144200030e"); upload.set_passwords_revealed(false); - upload.set_password_has_numeric(true); + upload.set_password_has_lowercase_letter(true); upload.set_password_length(10u); upload.set_action_signature(15724779818122431245U); upload.set_has_form_tag(true); @@ -3130,7 +3130,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest) { form_structure = std::make_unique<FormStructure>(form); form_structure->set_password_attributes_vote( - std::make_pair(PasswordAttribute::kHasNumeric, true)); + std::make_pair(PasswordAttribute::kHasLowercaseLetter, true)); form_structure->set_password_length_vote(10u); form_structure->set_submission_event( SubmissionIndicatorEvent::HTML_FORM_SUBMISSION); @@ -7123,4 +7123,19 @@ TEST_F(FormStructureTest, OneFieldPasswordFormShouldNotBeUpload) { EXPECT_FALSE(FormStructure(form).ShouldBeUploaded()); } +// Checks that CreateForPasswordManagerUpload builds FormStructure +// which is encodable (i.e. ready for uploading). +TEST_F(FormStructureTest, CreateForPasswordManagerUpload) { + std::unique_ptr<FormStructure> form = + FormStructure::CreateForPasswordManagerUpload( + 1234 /* form_signature */, {1, 10, 100} /* field_signatures */); + AutofillUploadContents upload; + EXPECT_EQ(1234u, form->form_signature()); + ASSERT_EQ(3u, form->field_count()); + ASSERT_EQ(100u, form->field(2)->GetFieldSignature()); + EXPECT_TRUE(form->EncodeUploadRequest( + {} /* available_field_types */, false /* form_was_autofilled */, + "" /*login_form_signature*/, true /*observed_submission*/, &upload)); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/logging/log_buffer_submitter.h b/chromium/components/autofill/core/browser/logging/log_buffer_submitter.h index 5925e842eda..ef6c411bdd0 100644 --- a/chromium/components/autofill/core/browser/logging/log_buffer_submitter.h +++ b/chromium/components/autofill/core/browser/logging/log_buffer_submitter.h @@ -6,7 +6,7 @@ #define COMPONENTS_AUTOFILL_CORE_BROWSER_LOGGING_LOG_BUFFER_SUBMITTER_H_ #include "base/macros.h" -#include "components/autofill/core/browser/logging/log_buffer.h" +#include "components/autofill/core/common/logging/log_buffer.h" namespace autofill { diff --git a/chromium/components/autofill/core/browser/logging/log_protobufs.h b/chromium/components/autofill/core/browser/logging/log_protobufs.h new file mode 100644 index 00000000000..a2008a3a2fa --- /dev/null +++ b/chromium/components/autofill/core/browser/logging/log_protobufs.h @@ -0,0 +1,31 @@ +// 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_LOGGING_LOG_PROTOBUFS_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_LOGGING_LOG_PROTOBUFS_H_ + +#include "components/autofill/core/common/logging/log_buffer.h" +#include "third_party/protobuf/src/google/protobuf/repeated_field.h" + +namespace autofill { + +// Serialize a repeated field in a protobuf. This function is not part of +// log_buffer.h because that would create a dependency of the renderer process +// to protobufs. +template <typename T> +LogBuffer& operator<<(LogBuffer& buf, + const ::google::protobuf::RepeatedField<T>& values) { + buf << "["; + for (int i = 0; i < values.size(); ++i) { + if (i) + buf << ", "; + buf << values.Get(i); + } + buf << "]"; + return buf; +} + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_LOGGING_LOG_PROTOBUFS_H_ diff --git a/chromium/components/autofill/core/browser/logging/log_router.cc b/chromium/components/autofill/core/browser/logging/log_router.cc index 3ab3a1bfabc..f31dd7cb997 100644 --- a/chromium/components/autofill/core/browser/logging/log_router.cc +++ b/chromium/components/autofill/core/browser/logging/log_router.cc @@ -6,9 +6,9 @@ #include "base/stl_util.h" #include "base/strings/string_split.h" -#include "components/autofill/core/browser/logging/log_buffer.h" #include "components/autofill/core/browser/logging/log_manager.h" #include "components/autofill/core/browser/logging/log_receiver.h" +#include "components/autofill/core/common/logging/log_buffer.h" #include "net/base/escape.h" namespace autofill { diff --git a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc index b969466c133..fcd2b80680a 100644 --- a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc +++ b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc @@ -10,9 +10,9 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "build/branding_buildflags.h" +#include "build/build_config.h" #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/data_model/credit_card.h" -#include "components/autofill/core/browser/payments/legal_message_line.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_payments_features.h" @@ -32,7 +32,7 @@ AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile( bool upload, AutofillClient::SaveCreditCardOptions options, const CreditCard& card, - std::unique_ptr<base::DictionaryValue> legal_message, + const LegalMessageLines& legal_message_lines, AutofillClient::UploadSaveCardPromptCallback upload_save_card_prompt_callback, AutofillClient::LocalSaveCardPromptCallback local_save_card_prompt_callback, @@ -51,22 +51,11 @@ AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile( card_label_(card.NetworkAndLastFourDigits()), card_sub_label_(card.AbbreviatedExpirationDateForDisplay(false)), card_last_four_digits_(card.LastFourDigits()), + legal_message_lines_(legal_message_lines), is_off_the_record_(is_off_the_record) { DCHECK_EQ(upload, !upload_save_card_prompt_callback_.is_null()); DCHECK_EQ(upload, local_save_card_prompt_callback_.is_null()); - if (legal_message) { - if (!LegalMessageLine::Parse(*legal_message, &legal_messages_, - /*escape_apostrophes=*/true)) { - AutofillMetrics::LogCreditCardInfoBarMetric( - AutofillMetrics::INFOBAR_NOT_SHOWN_INVALID_LEGAL_MESSAGE, upload_, - options_, - pref_service_->GetInteger( - prefs::kAutofillAcceptSaveCreditCardPromptState)); - return; - } - } - AutofillMetrics::LogCreditCardInfoBarMetric( AutofillMetrics::INFOBAR_SHOWN, upload_, options_, pref_service_->GetInteger( @@ -86,12 +75,6 @@ void AutofillSaveCardInfoBarDelegateMobile::OnLegalMessageLinkClicked( infobar()->owner()->OpenURL(url, WindowOpenDisposition::NEW_FOREGROUND_TAB); } -bool AutofillSaveCardInfoBarDelegateMobile::LegalMessagesParsedSuccessfully() { - // If we are uploading to the server, verify that legal lines have been parsed - // into |legal_messages_|. - return !upload_ || !legal_messages_.empty(); -} - bool AutofillSaveCardInfoBarDelegateMobile::IsGooglePayBrandingEnabled() const { #if BUILDFLAG(GOOGLE_CHROME_BRANDING) return upload_; @@ -136,10 +119,22 @@ AutofillSaveCardInfoBarDelegateMobile::GetIdentifier() const { bool AutofillSaveCardInfoBarDelegateMobile::ShouldExpire( const NavigationDetails& details) const { +#if defined(OS_IOS) + if (base::FeatureList::IsEnabled( + features::kAutofillSaveCardDismissOnNavigation)) { + // Expire the Infobar unless the navigation was triggered by the form that + // presented the Infobar, or the navigation is a redirect. + return !details.is_form_submission && !details.is_redirect; + } else { + // Use the default behavior used by Android. + return false; + } +#else // defined(OS_IOS) // The user has submitted a form, causing the page to navigate elsewhere. We // don't want the infobar to be expired at this point, because the user won't // get a chance to answer the question. return false; +#endif // defined(OS_IOS) } void AutofillSaveCardInfoBarDelegateMobile::InfoBarDismissed() { diff --git a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h index bd7e72e577c..f0dcb5f84f8 100644 --- a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h +++ b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h @@ -17,10 +17,6 @@ class PrefService; -namespace base { -class DictionaryValue; -} - namespace autofill { class CreditCard; @@ -33,7 +29,7 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate { bool upload, AutofillClient::SaveCreditCardOptions options, const CreditCard& card, - std::unique_ptr<base::DictionaryValue> legal_message, + const LegalMessageLines& legal_message_lines, AutofillClient::UploadSaveCardPromptCallback upload_save_card_prompt_callback, AutofillClient::LocalSaveCardPromptCallback @@ -47,15 +43,13 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate { int issuer_icon_id() const { return issuer_icon_id_; } const base::string16& card_label() const { return card_label_; } const base::string16& card_sub_label() const { return card_sub_label_; } - const LegalMessageLines& legal_messages() const { return legal_messages_; } + const LegalMessageLines& legal_message_lines() const { + return legal_message_lines_; + } // Called when a link in the legal message text was clicked. void OnLegalMessageLinkClicked(GURL url); - // Ensures the InfoBar is not shown if legal messages failed to parse. - // Legal messages are only specified for the upload case, not for local save. - bool LegalMessagesParsedSuccessfully(); - // Google Pay branding is enabled with a flag and only for cards upstreamed // to Google. bool IsGooglePayBrandingEnabled() const; @@ -117,8 +111,8 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate { // The last four digits of the card for which save is being offered. base::string16 card_last_four_digits_; - // The legal messages to show in the content of the infobar. - LegalMessageLines legal_messages_; + // The legal message lines to show in the content of the infobar. + const LegalMessageLines& legal_message_lines_; // Whether the save is offered while off the record bool is_off_the_record_; diff --git a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc index 787a9e3428d..263b8d89025 100644 --- a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc +++ b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc @@ -18,10 +18,11 @@ namespace browser_sync { AutofillWalletModelTypeController::AutofillWalletModelTypeController( syncer::ModelType type, - std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk, + std::unique_ptr<syncer::ModelTypeControllerDelegate> + delegate_for_full_sync_mode, PrefService* pref_service, syncer::SyncService* sync_service) - : ModelTypeController(type, std::move(delegate_on_disk)), + : ModelTypeController(type, std::move(delegate_for_full_sync_mode)), pref_service_(pref_service), sync_service_(sync_service) { DCHECK(type == syncer::AUTOFILL_WALLET_DATA || @@ -34,13 +35,15 @@ AutofillWalletModelTypeController::AutofillWalletModelTypeController( AutofillWalletModelTypeController::AutofillWalletModelTypeController( syncer::ModelType type, - std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk, - std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_in_memory, + std::unique_ptr<syncer::ModelTypeControllerDelegate> + delegate_for_full_sync_mode, + std::unique_ptr<syncer::ModelTypeControllerDelegate> + delegate_for_transport_mode, PrefService* pref_service, syncer::SyncService* sync_service) : ModelTypeController(type, - std::move(delegate_on_disk), - std::move(delegate_in_memory)), + std::move(delegate_for_full_sync_mode), + std::move(delegate_for_transport_mode)), pref_service_(pref_service), sync_service_(sync_service) { DCHECK(type == syncer::AUTOFILL_WALLET_DATA || diff --git a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h index 6cc8addad3b..03d0312c094 100644 --- a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h +++ b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h @@ -29,13 +29,16 @@ class AutofillWalletModelTypeController : public syncer::ModelTypeController, // |sync_client| must outlive this object. AutofillWalletModelTypeController( syncer::ModelType type, - std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk, + std::unique_ptr<syncer::ModelTypeControllerDelegate> + delegate_for_full_sync_mode, PrefService* pref_service, syncer::SyncService* sync_service); AutofillWalletModelTypeController( syncer::ModelType type, - std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk, - std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_in_memory, + std::unique_ptr<syncer::ModelTypeControllerDelegate> + delegate_for_full_sync_mode, + std::unique_ptr<syncer::ModelTypeControllerDelegate> + delegate_for_transport_mode, PrefService* pref_service, syncer::SyncService* sync_service); ~AutofillWalletModelTypeController() override; diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc index ab11f3c6a1b..196fd861e58 100644 --- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc +++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc @@ -25,14 +25,20 @@ #include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h" #include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" +#include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_tick_clock.h" #include "components/strings/grit/components_strings.h" #include "ui/base/l10n/l10n_util.h" +#if !defined(OS_IOS) +#include "components/autofill/core/browser/payments/fido_authentication_strike_database.h" +#endif + namespace autofill { namespace { // Timeout to wait for unmask details from Google Payments in milliseconds. -constexpr int64_t kUnmaskDetailsResponseTimeout = 1000; +constexpr int64_t kUnmaskDetailsResponseTimeoutMs = 1000; // Time to wait between multiple calls to GetUnmaskDetails(). constexpr int64_t kDelayForGetUnmaskDetails = 3 * 60 * 1000; // 3 min @@ -40,7 +46,7 @@ constexpr int64_t kDelayForGetUnmaskDetails = 3 * 60 * 1000; // 3 min bool WaitForEvent(base::WaitableEvent* event) { event->declare_only_used_while_idle(); return event->TimedWait( - base::TimeDelta::FromMilliseconds(kUnmaskDetailsResponseTimeout)); + base::TimeDelta::FromMilliseconds(kUnmaskDetailsResponseTimeoutMs)); } // Used with PostTaskWithDelay() to signal event after a timeout. @@ -71,7 +77,13 @@ CreditCardAccessManager::CreditCardAccessManager( base::WaitableEvent::ResetPolicy::AUTOMATIC, base::WaitableEvent::InitialState::NOT_SIGNALED), can_fetch_unmask_details_(base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::SIGNALED) {} + base::WaitableEvent::InitialState::SIGNALED) { +#if !defined(OS_IOS) + // This is to initialize StrikeDatabase is if it hasn't been already, so that + // its cache would be loaded and ready to use when the first CCAM is created. + client_->GetStrikeDatabase(); +#endif +} CreditCardAccessManager::~CreditCardAccessManager() {} @@ -199,20 +211,28 @@ void CreditCardAccessManager::GetUnmaskDetailsIfUserIsVerifiable( // If user is verifiable, then make preflight call to payments to fetch unmask // details, otherwise the only option is to perform CVC Auth, which does not // require any. Do nothing if request is already in progress. - if (is_user_verifiable_ && !unmask_details_request_in_progress_) { + if (is_user_verifiable_.value_or(false) && + !unmask_details_request_in_progress_) { unmask_details_request_in_progress_ = true; payments_client_->GetUnmaskDetails( base::BindOnce(&CreditCardAccessManager::OnDidGetUnmaskDetails, weak_ptr_factory_.GetWeakPtr()), personal_data_manager_->app_locale()); + preflight_call_timestamp_ = AutofillTickClock::NowTicks(); + AutofillMetrics::LogCardUnmaskPreflightCalled(); } } void CreditCardAccessManager::OnDidGetUnmaskDetails( AutofillClient::PaymentsRpcResult result, AutofillClient::UnmaskDetails& unmask_details) { + // Log latency for preflight call. + AutofillMetrics::LogCardUnmaskPreflightDuration( + AutofillTickClock::NowTicks() - preflight_call_timestamp_); + unmask_details_request_in_progress_ = false; - unmask_details_.offer_fido_opt_in = unmask_details.offer_fido_opt_in; + unmask_details_.offer_fido_opt_in = unmask_details.offer_fido_opt_in && + !payments_client_->is_off_the_record(); unmask_details_.unmask_auth_method = unmask_details.unmask_auth_method; unmask_details_.fido_request_options = std::move(unmask_details.fido_request_options); @@ -243,13 +263,28 @@ void CreditCardAccessManager::FetchCreditCard( const CreditCard* card, base::WeakPtr<Accessor> accessor, const base::TimeTicks& form_parsed_timestamp) { + // Return error if authentication is already in progress or card is nullptr. if (is_authentication_in_progress_ || !card) { accessor->OnCreditCardFetched(/*did_succeed=*/false, nullptr); return; } + // Latency metrics should only be logged if the user is verifiable and the + // flag is turned on. If flag is turned off, then |is_user_verifiable_| is not + // set. +#if !defined(OS_IOS) + bool should_log_latency_metrics = is_user_verifiable_.value_or(false); +#endif + // Return immediately if local card and log that unmask details were ignored. if (card->record_type() != CreditCard::MASKED_SERVER_CARD) { accessor->OnCreditCardFetched(/*did_succeed=*/true, card); +#if !defined(OS_IOS) + if (should_log_latency_metrics) { + AutofillMetrics::LogUserPerceivedLatencyOnCardSelection( + AutofillMetrics::PreflightCallEvent::kDidNotChooseMaskedCard, + GetOrCreateFIDOAuthenticator()->IsUserOptedIn()); + } +#endif return; } @@ -258,7 +293,32 @@ void CreditCardAccessManager::FetchCreditCard( form_parsed_timestamp_ = form_parsed_timestamp; is_authentication_in_progress_ = true; - if (AuthenticationRequiresUnmaskDetails()) { + bool get_unmask_details_returned = + ready_to_start_authentication_.IsSignaled(); + bool user_is_opted_in = AuthenticationRequiresUnmaskDetails(); + bool should_wait_to_authenticate = + user_is_opted_in && !get_unmask_details_returned; + + // Logging metrics. +#if !defined(OS_IOS) + if (should_log_latency_metrics) { + AutofillMetrics::LogUserPerceivedLatencyOnCardSelection( + get_unmask_details_returned + ? AutofillMetrics::PreflightCallEvent:: + kPreflightCallReturnedBeforeCardChosen + : AutofillMetrics::PreflightCallEvent:: + kCardChosenBeforePreflightCallReturned, + GetOrCreateFIDOAuthenticator()->IsUserOptedIn()); + } +#endif + +#if !defined(OS_ANDROID) && !defined(OS_IOS) + // On desktop, show the verify pending dialog for opted-in user. + if (user_is_opted_in) + ShowVerifyPendingDialog(); +#endif + + if (should_wait_to_authenticate) { // Wait for |ready_to_start_authentication_| to be signaled by // OnDidGetUnmaskDetails() or until timeout before calling Authenticate(). base::PostTaskAndReplyWithResult( @@ -267,37 +327,69 @@ void CreditCardAccessManager::FetchCreditCard( base::BindOnce(&CreditCardAccessManager::Authenticate, weak_ptr_factory_.GetWeakPtr())); } else { - Authenticate(); + Authenticate(get_unmask_details_returned); } } -void CreditCardAccessManager::FIDOAuthOptChange(bool opt_in, - base::Value creation_options) { +void CreditCardAccessManager::FIDOAuthOptChange(bool opt_in) { #if defined(OS_IOS) return; #else if (opt_in) { - GetOrCreateFIDOAuthenticator()->Register(std::move(creation_options)); + GetOrCreateFIDOAuthenticator()->ShowWebauthnOfferDialog( + /*card_authorization_token=*/std::string()); } else { GetOrCreateFIDOAuthenticator()->OptOut(); + GetOrCreateFIDOAuthenticator() + ->GetOrCreateFidoAuthenticationStrikeDatabase() + ->AddStrikes( + FidoAuthenticationStrikeDatabase::kStrikesToAddWhenUserOptsOut); } #endif } -void CreditCardAccessManager::Authenticate(bool did_get_unmask_details) { +void CreditCardAccessManager::OnSettingsPageFIDOAuthToggled(bool opt_in) { +#if defined(OS_IOS) + return; +#else + // TODO(crbug/949269): Add a rate limiter to counter spam clicking. + FIDOAuthOptChange(opt_in); +#endif +} + +void CreditCardAccessManager::Authenticate(bool get_unmask_details_returned) { // Reset now that we have started authentication. ready_to_start_authentication_.Reset(); unmask_details_request_in_progress_ = false; - // Do not use FIDO if card is not listed in unmask details, as each Card must - // be CVC authed at least once per device. - bool card_is_eligible_for_fido = - did_get_unmask_details && - unmask_details_.unmask_auth_method == - AutofillClient::UnmaskAuthMethod::FIDO && + bool fido_auth_suggested = + get_unmask_details_returned && unmask_details_.unmask_auth_method == + AutofillClient::UnmaskAuthMethod::FIDO; + + bool card_is_authorized_for_fido = + fido_auth_suggested && unmask_details_.fido_eligible_card_ids.find(card_->server_id()) != unmask_details_.fido_eligible_card_ids.end(); + // If FIDO authentication was suggested, but card is not in authorized list, + // must authenticate with CVC followed by FIDO in order to authorize this card + // for future FIDO use. + should_follow_up_cvc_with_fido_auth_ = + fido_auth_suggested && !card_is_authorized_for_fido; + + // Only use FIDO if card is authorized and not expired. + bool card_is_eligible_for_fido = + card_is_authorized_for_fido && !card_->IsExpired(AutofillClock::Now()); + + // If FIDO auth was suggested, logging which authentication method was + // actually used. + if (fido_auth_suggested && !card_->IsExpired(AutofillClock::Now())) { + AutofillMetrics::LogCardUnmaskTypeDecision( + card_is_eligible_for_fido + ? AutofillMetrics::CardUnmaskTypeDecisionMetric::kFidoOnly + : AutofillMetrics::CardUnmaskTypeDecisionMetric::kCvcThenFido); + } + if (card_is_eligible_for_fido) { #if defined(OS_IOS) NOTREACHED(); @@ -308,6 +400,11 @@ void CreditCardAccessManager::Authenticate(bool did_get_unmask_details) { std::move(unmask_details_.fido_request_options)); #endif } else { +#if !defined(OS_ANDROID) && !defined(OS_IOS) + // Close the verify pending dialog if it enters CVC authentication flow + // since the card unmask prompt will pop up. + client_->CloseVerifyPendingDialog(); +#endif GetOrCreateCVCAuthenticator()->Authenticate( card_, weak_ptr_factory_.GetWeakPtr(), personal_data_manager_, form_parsed_timestamp_); @@ -338,23 +435,48 @@ void CreditCardAccessManager::OnCVCAuthenticationComplete( response.cvc); can_fetch_unmask_details_.Signal(); - if (!response.did_succeed) + if (!response.did_succeed || response.card_authorization_token.empty()) return; #if defined(OS_ANDROID) - // Now that unmask flow is complete, on Android, if GetRealPan includes - // |creation_options|, completely hand over registration flow to - // CreditCardFIDOAuthenticator. + // Opt-in was already offered at this point for Android. + bool should_offer_fido_auth = false; +#elif !defined(OS_IOS) + bool should_offer_fido_auth = + unmask_details_.offer_fido_opt_in && + !GetOrCreateFIDOAuthenticator() + ->GetOrCreateFidoAuthenticationStrikeDatabase() + ->IsMaxStrikesLimitReached(); +#endif + +#if !defined(OS_IOS) + // Now that unmask flow is complete and form is filled, the remaining flows + // will be completely handed over to CreditCardFIDOAuthenticator. + // If the GetRealPan response includes |creation_options| or + // |request_options|, that means the user showed intention to opt-in while + // unmasking (this can only happen on Android) and must complete the challenge + // before successfully opting-in. If UnmaskDetails contained + // |request_options|, that means the user is already opted-into FIDO auth, and + // this is the first time use of a new card, and must complete the challenge + // to successfully authorize the card. Otherwise, if on desktop and eligible, + // show the dialog that offers opting-in to FIDO authentication in the future. if (response.creation_options.has_value()) { DCHECK(response.creation_options->is_dict()); GetOrCreateFIDOAuthenticator()->Register( - response.creation_options->Clone()); + response.card_authorization_token, response.creation_options->Clone()); + } else if (response.request_options.has_value()) { + DCHECK(response.request_options->is_dict()); + GetOrCreateFIDOAuthenticator()->Authorize( + response.card_authorization_token, response.request_options->Clone()); + } else if (should_offer_fido_auth) { + GetOrCreateFIDOAuthenticator()->ShowWebauthnOfferDialog( + response.card_authorization_token); + } else if (should_follow_up_cvc_with_fido_auth_) { + DCHECK(unmask_details_.fido_request_options.is_dict()); + GetOrCreateFIDOAuthenticator()->Authorize( + response.card_authorization_token, + std::move(unmask_details_.fido_request_options)); } -#elif !defined(OS_IOS) - // CreditCardFIDOAuthenticator does not exist on iOS. - // On desktop, prompts dialog to show the authentication offer. - if (unmask_details_.offer_fido_opt_in) - GetOrCreateFIDOAuthenticator()->ShowWebauthnOfferDialog(); #endif } @@ -362,6 +484,13 @@ void CreditCardAccessManager::OnCVCAuthenticationComplete( void CreditCardAccessManager::OnFIDOAuthenticationComplete( bool did_succeed, const CreditCard* card) { +#if !defined(OS_ANDROID) + // Close the verify pending dialog. If FIDO authentication succeeded, card is + // filled to the form, otherwise fall back to CVC authentication which does + // not need the verify pending dialog either. + client_->CloseVerifyPendingDialog(); +#endif + if (did_succeed) { is_authentication_in_progress_ = false; accessor_->OnCreditCardFetched(did_succeed, card); @@ -376,6 +505,10 @@ void CreditCardAccessManager::OnFIDOAuthenticationComplete( } #endif +bool CreditCardAccessManager::IsLocalCard(const CreditCard* card) { + return card && card->record_type() == CreditCard::LOCAL_CARD; +} + bool CreditCardAccessManager::AuthenticationRequiresUnmaskDetails() { #if defined(OS_IOS) return false; @@ -385,8 +518,18 @@ bool CreditCardAccessManager::AuthenticationRequiresUnmaskDetails() { #endif } -bool CreditCardAccessManager::IsLocalCard(const CreditCard* card) { - return card && card->record_type() == CreditCard::LOCAL_CARD; +#if !defined(OS_ANDROID) && !defined(OS_IOS) +void CreditCardAccessManager::ShowVerifyPendingDialog() { + client_->ShowVerifyPendingDialog( + base::BindOnce(&CreditCardAccessManager::OnDidCancelCardVerification, + weak_ptr_factory_.GetWeakPtr())); +} + +void CreditCardAccessManager::OnDidCancelCardVerification() { + payments_client_->CancelRequest(); + unmask_details_request_in_progress_ = false; + is_authentication_in_progress_ = false; } +#endif } // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.h b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.h index 0307279777c..7c6868a2761 100644 --- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.h +++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.h @@ -91,8 +91,11 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester, // If |opt_in| = true, opts the user into using FIDO authentication for card // unmasking. Otherwise, opts the user out. If |creation_options| is set, // WebAuthn registration prompt will be invoked to create a new credential. - void FIDOAuthOptChange(bool opt_in, - base::Value creation_options = base::Value()); + void FIDOAuthOptChange(bool opt_in); + + // Makes a call to FIDOAuthOptChange() with |opt_in|. + // TODO(crbug/949269): Add a rate limiter to counter spam clicking. + void OnSettingsPageFIDOAuthToggled(bool opt_in); CreditCardCVCAuthenticator* GetOrCreateCVCAuthenticator(); @@ -128,10 +131,12 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester, void OnDidGetUnmaskDetails(AutofillClient::PaymentsRpcResult result, AutofillClient::UnmaskDetails& unmask_details); - // Calls either CreditCardFIDOAuthenticator::Authenticate() or - // CreditCardCVCAuthenticator::Authenticate() depending on the response - // contained in |unmask_details_|. - void Authenticate(bool did_get_unmask_details = false); + // If OnDidGetUnmaskDetails() was invoked by PaymentsClient, then + // |get_unmask_details_returned| should be set to true. Based on the + // contents of |unmask_details_|, either FIDO authentication or CVC + // authentication will be prompted. If |get_unmask_details_returned| is false, + // then only CVC authentication will be prompted. + void Authenticate(bool get_unmask_details_returned = false); // CreditCardCVCAuthenticator::Requester: void OnCVCAuthenticationComplete( @@ -156,10 +161,25 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester, // immediately. bool AuthenticationRequiresUnmaskDetails(); +#if !defined(OS_ANDROID) && !defined(OS_IOS) + // After card verification starts, shows the verify pending dialog if WebAuthn + // is enabled, indicating some verification steps are in progress. + void ShowVerifyPendingDialog(); + + // The callback function invoked when the cancel button in the verify pending + // dialog is clicked. Will cancel the attempt to fetch unmask details. + void OnDidCancelCardVerification(); +#endif + // Is set to true only when waiting for the callback to // OnCVCAuthenticationComplete() to be executed. bool is_authentication_in_progress_ = false; + // Set to true if the card selected needs to be authenticated through CVC + // first, and then FIDO. This happens when a user is opted-in but has not + // previously authenticated this card with CVC on this device. + bool should_follow_up_cvc_with_fido_auth_ = false; + // The associated autofill driver. Weak reference. AutofillDriver* const driver_; @@ -178,6 +198,9 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester, // For logging metrics. May be NULL for tests. CreditCardFormEventLogger* form_event_logger_; + // Timestamp used for metrics. + base::TimeTicks preflight_call_timestamp_; + // Meant for histograms recorded in FullCardRequest. base::TimeTicks form_parsed_timestamp_; diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc index f45ea4e58c5..c149dee68a7 100644 --- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc @@ -69,6 +69,7 @@ #include "url/gurl.h" #if !defined(OS_IOS) +#include "components/autofill/core/browser/payments/fido_authentication_strike_database.h" #include "components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h" #endif @@ -126,13 +127,13 @@ class TestAccessor : public CreditCardAccessManager::Accessor { std::string NextYear() { base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); + AutofillClock::Now().LocalExplode(&now); return base::NumberToString(now.year + 1); } std::string NextMonth() { base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); + AutofillClock::Now().LocalExplode(&now); return base::NumberToString(now.month % 12 + 1); } @@ -165,6 +166,8 @@ class CreditCardAccessManagerTest : public testing::Test { autofill_client_.GetIdentityManager(), &personal_data_manager_); autofill_client_.set_test_payments_client( std::unique_ptr<payments::TestPaymentsClient>(payments_client_)); + autofill_client_.set_test_strike_database( + std::make_unique<TestStrikeDatabase>()); credit_card_access_manager_ = std::make_unique<CreditCardAccessManager>( autofill_driver_.get(), &autofill_client_, &personal_data_manager_, nullptr); @@ -188,6 +191,15 @@ class CreditCardAccessManagerTest : public testing::Test { return credit_card_access_manager_->is_authentication_in_progress(); } + void ResetFetchCreditCard() { + // Resets all variables related to credit card fetching. + credit_card_access_manager_->is_authentication_in_progress_ = false; + credit_card_access_manager_->can_fetch_unmask_details_.Signal(); + credit_card_access_manager_->is_user_verifiable_ = base::nullopt; + } + + void ClearCards() { personal_data_manager_.ClearCreditCards(); } + void CreateLocalCard(std::string guid, std::string number = std::string()) { CreditCard local_card = CreditCard(); test::SetCreditCardInfo(&local_card, "Elvis Presley", number.c_str(), @@ -195,7 +207,6 @@ class CreditCardAccessManagerTest : public testing::Test { local_card.set_guid(guid); local_card.set_record_type(CreditCard::LOCAL_CARD); - personal_data_manager_.ClearCreditCards(); personal_data_manager_.AddCreditCard(local_card); } @@ -207,7 +218,6 @@ class CreditCardAccessManagerTest : public testing::Test { masked_server_card.set_guid(guid); masked_server_card.set_record_type(CreditCard::MASKED_SERVER_CARD); - personal_data_manager_.ClearCreditCards(); personal_data_manager_.AddServerCreditCard(masked_server_card); } @@ -218,22 +228,27 @@ class CreditCardAccessManagerTest : public testing::Test { // Returns true if full card request was sent from CVC auth. bool GetRealPanForCVCAuth(AutofillClient::PaymentsRpcResult result, const std::string& real_pan, - bool fido_opt_in = false) { + bool fido_opt_in = false, + bool follow_with_fido_auth = false) { payments::FullCardRequest* full_card_request = GetCVCAuthenticator()->full_card_request_.get(); if (!full_card_request) return false; + // Mock user response. + payments::FullCardRequest::UserProvidedUnmaskDetails details; + details.cvc = base::ASCIIToUTF16("123"); + full_card_request->OnUnmaskPromptAccepted(details); + payments::PaymentsClient::UnmaskResponseDetails response; #if !defined(OS_IOS) + response.card_authorization_token = "dummy_card_authorization_token"; if (fido_opt_in) { - response.fido_creation_options = - base::Value(base::Value::Type::DICTIONARY); - response.fido_creation_options->SetKey("relying_party_id", - base::Value(kGooglePaymentsRpid)); - response.fido_creation_options->SetKey("challenge", - base::Value(kTestChallenge)); + response.fido_creation_options = GetTestCreationOptions(); + } + if (follow_with_fido_auth) { + response.fido_request_options = GetTestRequestOptions(); } #endif full_card_request->OnDidGetRealPan(result, @@ -242,7 +257,43 @@ class CreditCardAccessManagerTest : public testing::Test { } #if !defined(OS_IOS) + void ClearStrikes() { + return GetFIDOAuthenticator() + ->GetOrCreateFidoAuthenticationStrikeDatabase() + ->ClearAllStrikes(); + } + + int GetStrikes() { + return GetFIDOAuthenticator() + ->GetOrCreateFidoAuthenticationStrikeDatabase() + ->GetStrikes(); + } + + base::Value GetTestRequestOptions() { + base::Value request_options = base::Value(base::Value::Type::DICTIONARY); + request_options.SetKey("challenge", base::Value(kTestChallenge)); + request_options.SetKey("relying_party_id", + base::Value(kGooglePaymentsRpid)); + + base::Value key_info(base::Value::Type::DICTIONARY); + key_info.SetKey("credential_id", base::Value(kCredentialId)); + request_options.SetKey("key_info", base::Value(base::Value::Type::LIST)); + request_options.FindKeyOfType("key_info", base::Value::Type::LIST) + ->GetList() + .push_back(std::move(key_info)); + return request_options; + } + + base::Value GetTestCreationOptions() { + base::Value creation_options = base::Value(base::Value::Type::DICTIONARY); + creation_options.SetKey("challenge", base::Value(kTestChallenge)); + creation_options.SetKey("relying_party_id", + base::Value(kGooglePaymentsRpid)); + return creation_options; + } + void SetUserOptedIn(bool user_is_opted_in) { + scoped_feature_list_.Reset(); scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardAuthentication); ::autofill::prefs::SetCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs(), @@ -267,9 +318,22 @@ class CreditCardAccessManagerTest : public testing::Test { // Mocks an OptChange response from Payments Client. void OptChange(AutofillClient::PaymentsRpcResult result, bool user_is_opted_in, - base::Value creation_options = base::Value()) { - GetFIDOAuthenticator()->OnDidGetOptChangeResult( - result, user_is_opted_in, std::move(creation_options)); + bool include_creation_options = false, + bool include_request_options = false) { + payments::PaymentsClient::OptChangeResponseDetails response; + response.user_is_opted_in = user_is_opted_in; + if (include_creation_options) { + response.fido_creation_options = GetTestCreationOptions(); + } + if (include_request_options) { + response.fido_request_options = GetTestRequestOptions(); + } + GetFIDOAuthenticator()->OnDidGetOptChangeResult(result, response); + } + + // Mocks user response for the offer dialog. + void AcceptWebauthnOfferDialog(bool did_accept) { + GetFIDOAuthenticator()->OnWebauthnOfferDialogUserResponse(did_accept); } TestCreditCardFIDOAuthenticator* GetFIDOAuthenticator() { @@ -456,10 +520,87 @@ TEST_F(CreditCardAccessManagerTest, FetchServerCardCVCTryAgainFailure) { EXPECT_EQ(ASCIIToUTF16(kTestNumber), accessor_->number()); } +// Ensures that CardUnmaskPreflightCalled metrics are logged correctly. +TEST_F(CreditCardAccessManagerTest, CardUnmaskPreflightCalledMetric) { + std::string preflight_call_metric = + "Autofill.BetterAuth.CardUnmaskPreflightCalled"; + std::string preflight_latency_metric = + "Autofill.BetterAuth.CardUnmaskPreflightDuration"; + + { + // Create local card and set user as eligible for FIDO auth. + base::HistogramTester histogram_tester; + ClearCards(); + CreateLocalCard(kTestGUID, kTestNumber); +#if !defined(OS_IOS) + GetFIDOAuthenticator()->SetUserVerifiable(true); +#endif + ResetFetchCreditCard(); + + credit_card_access_manager_->PrepareToFetchCreditCard(); + InvokeUnmaskDetailsTimeout(); + WaitForCallbacks(); + + // If only local cards are available, then no preflight call is made. + histogram_tester.ExpectTotalCount(preflight_call_metric, 0); + histogram_tester.ExpectTotalCount(preflight_latency_metric, 0); + } + + { + // Create server card and set user as ineligible for FIDO auth. + base::HistogramTester histogram_tester; + ClearCards(); + CreateServerCard(kTestGUID, kTestNumber); +#if !defined(OS_IOS) + GetFIDOAuthenticator()->SetUserVerifiable(false); +#endif + ResetFetchCreditCard(); + + credit_card_access_manager_->PrepareToFetchCreditCard(); + InvokeUnmaskDetailsTimeout(); + WaitForCallbacks(); + + // If user is not verifiable, then no preflight call is made. + histogram_tester.ExpectTotalCount(preflight_call_metric, 0); + histogram_tester.ExpectTotalCount(preflight_latency_metric, 0); + } + + { + // Create server card and set user as eligible for FIDO auth. + base::HistogramTester histogram_tester; + ClearCards(); + CreateServerCard(kTestGUID, kTestNumber); +#if !defined(OS_IOS) + GetFIDOAuthenticator()->SetUserVerifiable(true); +#endif + ResetFetchCreditCard(); + + credit_card_access_manager_->PrepareToFetchCreditCard(); + InvokeUnmaskDetailsTimeout(); + WaitForCallbacks(); + + // Preflight call is made only if a server card is available and the user is + // eligible for FIDO authentication, except on iOS. +#if defined(OS_IOS) + histogram_tester.ExpectTotalCount(preflight_call_metric, 0); + histogram_tester.ExpectTotalCount(preflight_latency_metric, 0); +#else + histogram_tester.ExpectTotalCount(preflight_call_metric, 1); + histogram_tester.ExpectTotalCount(preflight_latency_metric, 1); +#endif + } +} + #if !defined(OS_IOS) // Ensures that FetchCreditCard() returns the full PAN upon a successful // WebAuthn verification and response from payments. TEST_F(CreditCardAccessManagerTest, FetchServerCardFIDOSuccess) { + base::HistogramTester histogram_tester; + std::string unmask_decision_histogram_name = + "Autofill.BetterAuth.CardUnmaskTypeDecision"; + std::string webauthn_result_histogram_name = + "Autofill.BetterAuth.WebauthnResult.ImmediateAuthentication"; + CreateServerCard(kTestGUID, kTestNumber); CreditCard* card = credit_card_access_manager_->GetCreditCard(kTestGUID); GetFIDOAuthenticator()->SetUserVerifiable(true); @@ -484,10 +625,26 @@ TEST_F(CreditCardAccessManagerTest, FetchServerCardFIDOSuccess) { EXPECT_EQ(kCredentialId, BytesToBase64(GetFIDOAuthenticator()->GetCredentialId())); EXPECT_EQ(ASCIIToUTF16(kTestNumber), accessor_->number()); + + histogram_tester.ExpectUniqueSample( + unmask_decision_histogram_name, + AutofillMetrics::CardUnmaskTypeDecisionMetric::kFidoOnly, 1); + histogram_tester.ExpectUniqueSample( + webauthn_result_histogram_name, + AutofillMetrics::WebauthnResultMetric::kSuccess, 1); + histogram_tester.ExpectTotalCount( + "Autofill.BetterAuth.CardUnmaskDuration.Fido", 1); + histogram_tester.ExpectTotalCount( + "Autofill.BetterAuth.CardUnmaskDuration.Fido.Success", 1); } // Ensures that CVC prompt is invoked after WebAuthn fails. -TEST_F(CreditCardAccessManagerTest, FetchServerCardFIDOFailureCVCFallback) { +TEST_F(CreditCardAccessManagerTest, + FetchServerCardFIDOVerificationFailureCVCFallback) { + base::HistogramTester histogram_tester; + std::string histogram_name = + "Autofill.BetterAuth.WebauthnResult.ImmediateAuthentication"; + CreateServerCard(kTestGUID, kTestNumber); CreditCard* card = credit_card_access_manager_->GetCreditCard(kTestGUID); GetFIDOAuthenticator()->SetUserVerifiable(true); @@ -515,6 +672,55 @@ TEST_F(CreditCardAccessManagerTest, FetchServerCardFIDOFailureCVCFallback) { EXPECT_TRUE(GetRealPanForCVCAuth(AutofillClient::SUCCESS, kTestNumber)); EXPECT_TRUE(accessor_->did_succeed()); EXPECT_EQ(ASCIIToUTF16(kTestNumber), accessor_->number()); + + histogram_tester.ExpectUniqueSample( + histogram_name, AutofillMetrics::WebauthnResultMetric::kNotAllowedError, + 1); +} + +// Ensures that CVC prompt is invoked after payments returns an error from +// GetRealPan via FIDO. +TEST_F(CreditCardAccessManagerTest, + FetchServerCardFIDOServerFailureCVCFallback) { + base::HistogramTester histogram_tester; + std::string histogram_name = + "Autofill.BetterAuth.WebauthnResult.ImmediateAuthentication"; + + CreateServerCard(kTestGUID, kTestNumber); + CreditCard* card = credit_card_access_manager_->GetCreditCard(kTestGUID); + GetFIDOAuthenticator()->SetUserVerifiable(true); + SetUserOptedIn(true); + payments_client_->AddFidoEligibleCard(card->server_id(), kCredentialId, + kGooglePaymentsRpid); + + credit_card_access_manager_->PrepareToFetchCreditCard(); + WaitForCallbacks(); + + credit_card_access_manager_->FetchCreditCard(card, accessor_->GetWeakPtr()); + WaitForCallbacks(); + + // FIDO Failure. + EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::AUTHENTICATION_FLOW, + GetFIDOAuthenticator()->current_flow()); + TestCreditCardFIDOAuthenticator::GetAssertion(GetFIDOAuthenticator(), + /*did_succeed=*/true); + EXPECT_TRUE( + GetRealPanForFIDOAuth(AutofillClient::PERMANENT_FAILURE, kTestNumber)); + EXPECT_FALSE(accessor_->did_succeed()); + + // Followed by a fallback to CVC. + EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::NONE_FLOW, + GetFIDOAuthenticator()->current_flow()); + EXPECT_TRUE(GetRealPanForCVCAuth(AutofillClient::SUCCESS, kTestNumber)); + EXPECT_TRUE(accessor_->did_succeed()); + EXPECT_EQ(ASCIIToUTF16(kTestNumber), accessor_->number()); + + histogram_tester.ExpectUniqueSample( + histogram_name, AutofillMetrics::WebauthnResultMetric::kSuccess, 1); + histogram_tester.ExpectTotalCount( + "Autofill.BetterAuth.CardUnmaskDuration.Fido", 1); + histogram_tester.ExpectTotalCount( + "Autofill.BetterAuth.CardUnmaskDuration.Fido.Failure", 1); } // Ensures WebAuthn call is not made if Request Options is missing a Credential @@ -561,14 +767,161 @@ TEST_F(CreditCardAccessManagerTest, FetchServerCardFIDOTimeoutCVCFallback) { EXPECT_TRUE(accessor_->did_succeed()); EXPECT_EQ(ASCIIToUTF16(kTestNumber), accessor_->number()); } -#endif -// TODO(crbug.com/991037): Add tests for desktop separately after the -// WebauthnOfferDelegate functions are implemented since the flows are different -// on desktop and Android. +// Ensures that FetchCreditCard() returns the full PAN upon a successful +// WebAuthn verification and response from payments. +TEST_F(CreditCardAccessManagerTest, + Metrics_LoggingExistenceOfUserPerceivedLatency) { + // Setting up a FIDO-enabled user with a local card and a server card. + std::string server_guid = "00000000-0000-0000-0000-000000000001"; + std::string local_guid = "00000000-0000-0000-0000-000000000003"; + CreateServerCard(server_guid, "4594299181086168"); + CreateLocalCard(local_guid, "4409763681177079"); + CreditCard* server_card = + credit_card_access_manager_->GetCreditCard(server_guid); + CreditCard* local_card = + credit_card_access_manager_->GetCreditCard(local_guid); + GetFIDOAuthenticator()->SetUserVerifiable(true); + + for (bool user_is_opted_in : {true, false}) { + std::string histogram_name = + "Autofill.BetterAuth.UserPerceivedLatencyOnCardSelection."; + histogram_name += user_is_opted_in ? "OptedIn" : "OptedOut"; + SetUserOptedIn(user_is_opted_in); + + { + // Preflight call ignored because local card was chosen. + base::HistogramTester histogram_tester; + + ResetFetchCreditCard(); + credit_card_access_manager_->PrepareToFetchCreditCard(); + WaitForCallbacks(); + + credit_card_access_manager_->FetchCreditCard(local_card, + accessor_->GetWeakPtr()); + WaitForCallbacks(); + + histogram_tester.ExpectUniqueSample( + histogram_name, + AutofillMetrics::PreflightCallEvent::kDidNotChooseMaskedCard, 1); + } + + { + // Preflight call returned after card was chosen. + base::HistogramTester histogram_tester; + payments_client_->ShouldReturnUnmaskDetailsImmediately(false); + + ResetFetchCreditCard(); + credit_card_access_manager_->PrepareToFetchCreditCard(); + credit_card_access_manager_->FetchCreditCard(server_card, + accessor_->GetWeakPtr()); + WaitForCallbacks(); + + histogram_tester.ExpectUniqueSample( + histogram_name, + AutofillMetrics::PreflightCallEvent:: + kCardChosenBeforePreflightCallReturned, + 1); + } + + { + // Preflight call returned before card was chosen. + base::HistogramTester histogram_tester; + // This is important because CreditCardFIDOAuthenticator will update the + // opted-in pref according to GetDetailsForGetRealPan response. + payments_client_->AllowFidoRegistration(!user_is_opted_in); + + ResetFetchCreditCard(); + credit_card_access_manager_->PrepareToFetchCreditCard(); + WaitForCallbacks(); + + credit_card_access_manager_->FetchCreditCard(server_card, + accessor_->GetWeakPtr()); + WaitForCallbacks(); + + histogram_tester.ExpectUniqueSample( + histogram_name, + AutofillMetrics::PreflightCallEvent:: + kPreflightCallReturnedBeforeCardChosen, + 1); + } + } +} + +// Ensures that use of new card invokes authorization flow when user is +// opted-in. +TEST_F(CreditCardAccessManagerTest, FIDONewCardAuthorization) { + base::HistogramTester histogram_tester; + std::string unmask_decision_histogram_name = + "Autofill.BetterAuth.CardUnmaskTypeDecision"; + std::string webauthn_result_histogram_name = + "Autofill.BetterAuth.WebauthnResult.AuthenticationAfterCVC"; + + CreateServerCard(kTestGUID, kTestNumber); + CreditCard* card = credit_card_access_manager_->GetCreditCard(kTestGUID); + // Opt the user in, but don't include the card above. + std::string other_server_id = "00000000-0000-0000-0000-000000000034"; + payments_client_->AddFidoEligibleCard(other_server_id, kCredentialId, + kGooglePaymentsRpid); + GetFIDOAuthenticator()->SetUserVerifiable(true); + SetUserOptedIn(true); + + credit_card_access_manager_->PrepareToFetchCreditCard(); + WaitForCallbacks(); + + credit_card_access_manager_->FetchCreditCard(card, accessor_->GetWeakPtr()); + InvokeUnmaskDetailsTimeout(); + WaitForCallbacks(); + + EXPECT_TRUE(GetRealPanForCVCAuth(AutofillClient::SUCCESS, kTestNumber, + /*fido_opt_in=*/false, + /*follow_with_fido_auth=*/true)); + + // Mock user response and OptChange payments call. + EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::FOLLOWUP_AFTER_CVC_AUTH_FLOW, + GetFIDOAuthenticator()->current_flow()); + TestCreditCardFIDOAuthenticator::GetAssertion(GetFIDOAuthenticator(), + /*did_succeed=*/true); + OptChange(AutofillClient::SUCCESS, true); + + histogram_tester.ExpectUniqueSample( + unmask_decision_histogram_name, + AutofillMetrics::CardUnmaskTypeDecisionMetric::kCvcThenFido, 1); + histogram_tester.ExpectUniqueSample( + webauthn_result_histogram_name, + AutofillMetrics::WebauthnResultMetric::kSuccess, 1); +} + +// Ensures expired cards always invoke a CVC prompt instead of WebAuthn. +TEST_F(CreditCardAccessManagerTest, FetchExpiredServerCardInvokesCvcPrompt) { + // Creating an expired server card and opting the user in with authorized + // card. + CreateServerCard(kTestGUID, kTestNumber); + CreditCard* card = credit_card_access_manager_->GetCreditCard(kTestGUID); + card->SetExpirationYearFromString(base::UTF8ToUTF16("2010")); + GetFIDOAuthenticator()->SetUserVerifiable(true); + SetUserOptedIn(true); + payments_client_->AddFidoEligibleCard(card->server_id(), kCredentialId, + kGooglePaymentsRpid); + + credit_card_access_manager_->PrepareToFetchCreditCard(); + WaitForCallbacks(); + + credit_card_access_manager_->FetchCreditCard(card, accessor_->GetWeakPtr()); + WaitForCallbacks(); + + // Expect CVC prompt to be invoked. + EXPECT_TRUE(GetRealPanForCVCAuth(AutofillClient::SUCCESS, kTestNumber)); + EXPECT_EQ(ASCIIToUTF16(kTestNumber), accessor_->number()); +} + #if defined(OS_ANDROID) // Ensures that the WebAuthn enrollment prompt is invoked after user opts in. -TEST_F(CreditCardAccessManagerTest, FIDOEnrollmentSuccess) { +TEST_F(CreditCardAccessManagerTest, FIDOEnrollmentSuccess_Android) { + base::HistogramTester histogram_tester; + std::string histogram_name = + "Autofill.BetterAuth.WebauthnResult.CheckoutOptIn"; + CreateServerCard(kTestGUID, kTestNumber); CreditCard* card = credit_card_access_manager_->GetCreditCard(kTestGUID); GetFIDOAuthenticator()->SetUserVerifiable(true); @@ -593,10 +946,17 @@ TEST_F(CreditCardAccessManagerTest, FIDOEnrollmentSuccess) { EXPECT_EQ(kTestChallenge, BytesToBase64(GetFIDOAuthenticator()->GetChallenge())); EXPECT_TRUE(GetFIDOAuthenticator()->IsUserOptedIn()); + + histogram_tester.ExpectUniqueSample( + histogram_name, AutofillMetrics::WebauthnResultMetric::kSuccess, 1); } // Ensures that the failed user verification disallows enrollment. TEST_F(CreditCardAccessManagerTest, FIDOEnrollmentUserVerificationFailure) { + base::HistogramTester histogram_tester; + std::string histogram_name = + "Autofill.BetterAuth.WebauthnResult.CheckoutOptIn"; + CreateServerCard(kTestGUID, kTestNumber); CreditCard* card = credit_card_access_manager_->GetCreditCard(kTestGUID); GetFIDOAuthenticator()->SetUserVerifiable(true); @@ -614,6 +974,10 @@ TEST_F(CreditCardAccessManagerTest, FIDOEnrollmentUserVerificationFailure) { /*did_succeed=*/false); EXPECT_FALSE(GetFIDOAuthenticator()->IsUserOptedIn()); + + histogram_tester.ExpectUniqueSample( + histogram_name, AutofillMetrics::WebauthnResultMetric::kNotAllowedError, + 1); } // Ensures that enrollment does not happen if the server returns a failure. @@ -637,7 +1001,304 @@ TEST_F(CreditCardAccessManagerTest, FIDOEnrollmentServerFailure) { EXPECT_FALSE(GetFIDOAuthenticator()->IsUserOptedIn()); } -#endif + +#else // defined(OS_ANDROID) +// Ensures that the WebAuthn enrollment prompt is invoked after user opts in. In +// this case, the user is not yet enrolled server-side, and thus receives +// |creation_options|. +TEST_F(CreditCardAccessManagerTest, + FIDOEnrollmentSuccess_CreationOptions_Desktop) { + base::HistogramTester histogram_tester; + std::string webauthn_result_histogram_name = + "Autofill.BetterAuth.WebauthnResult.CheckoutOptIn"; + std::string opt_in_histogram_name = + "Autofill.BetterAuth.OptInCalled.FromCheckoutFlow"; + std::string promo_shown_histogram_name = + "Autofill.BetterAuth.OptInPromoShown.FromCheckoutFlow"; + std::string promo_user_decision_histogram_name = + "Autofill.BetterAuth.OptInPromoUserDecision.FromCheckoutFlow"; + + ClearStrikes(); + CreateServerCard(kTestGUID, kTestNumber); + CreditCard* card = credit_card_access_manager_->GetCreditCard(kTestGUID); + GetFIDOAuthenticator()->SetUserVerifiable(true); + SetUserOptedIn(false); + payments_client_->AllowFidoRegistration(true); + + credit_card_access_manager_->PrepareToFetchCreditCard(); + credit_card_access_manager_->FetchCreditCard(card, accessor_->GetWeakPtr()); + WaitForCallbacks(); + + // Mock user and payments response. + EXPECT_TRUE(GetRealPanForCVCAuth(AutofillClient::SUCCESS, kTestNumber, + /*fido_opt_in=*/false)); + AcceptWebauthnOfferDialog(/*did_accept=*/true); + + OptChange(AutofillClient::SUCCESS, /*user_is_opted_in=*/false, + /*include_creation_options=*/true); + + // Mock user response and OptChange payments call. + EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITH_CHALLENGE_FLOW, + GetFIDOAuthenticator()->current_flow()); + TestCreditCardFIDOAuthenticator::MakeCredential(GetFIDOAuthenticator(), + /*did_succeed=*/true); + OptChange(AutofillClient::SUCCESS, /*user_is_opted_in=*/true); + + EXPECT_EQ(kGooglePaymentsRpid, GetFIDOAuthenticator()->GetRelyingPartyId()); + EXPECT_EQ(kTestChallenge, + BytesToBase64(GetFIDOAuthenticator()->GetChallenge())); + EXPECT_TRUE(GetFIDOAuthenticator()->IsUserOptedIn()); + EXPECT_EQ(0, GetStrikes()); + histogram_tester.ExpectUniqueSample( + webauthn_result_histogram_name, + AutofillMetrics::WebauthnResultMetric::kSuccess, 1); + histogram_tester.ExpectTotalCount(opt_in_histogram_name, 2); + histogram_tester.ExpectBucketCount( + opt_in_histogram_name, + AutofillMetrics::WebauthnOptInParameters::kFetchingChallenge, 1); + histogram_tester.ExpectBucketCount( + opt_in_histogram_name, + AutofillMetrics::WebauthnOptInParameters::kWithCreationChallenge, 1); + histogram_tester.ExpectTotalCount(promo_shown_histogram_name, 1); + histogram_tester.ExpectUniqueSample( + promo_user_decision_histogram_name, + AutofillMetrics::WebauthnOptInPromoUserDecisionMetric::kAccepted, 1); +} + +// Ensures that the correct number of strikes are added when the user declines +// the WebAuthn offer. +TEST_F(CreditCardAccessManagerTest, FIDOEnrollment_OfferDeclined_Desktop) { + base::HistogramTester histogram_tester; + std::string promo_shown_histogram_name = + "Autofill.BetterAuth.OptInPromoShown.FromCheckoutFlow"; + std::string promo_user_decision_histogram_name = + "Autofill.BetterAuth.OptInPromoUserDecision.FromCheckoutFlow"; + + ClearStrikes(); + CreateServerCard(kTestGUID, kTestNumber); + CreditCard* card = credit_card_access_manager_->GetCreditCard(kTestGUID); + GetFIDOAuthenticator()->SetUserVerifiable(true); + SetUserOptedIn(false); + payments_client_->AllowFidoRegistration(true); + + credit_card_access_manager_->PrepareToFetchCreditCard(); + credit_card_access_manager_->FetchCreditCard(card, accessor_->GetWeakPtr()); + WaitForCallbacks(); + + // Mock user and payments response. + EXPECT_TRUE(GetRealPanForCVCAuth(AutofillClient::SUCCESS, kTestNumber, + /*fido_opt_in=*/false)); + AcceptWebauthnOfferDialog(/*did_accept=*/false); + EXPECT_EQ( + FidoAuthenticationStrikeDatabase::kStrikesToAddWhenOptInOfferDeclined, + GetStrikes()); + histogram_tester.ExpectTotalCount(promo_shown_histogram_name, 1); + histogram_tester.ExpectUniqueSample( + promo_user_decision_histogram_name, + AutofillMetrics::WebauthnOptInPromoUserDecisionMetric:: + kDeclinedImmediately, + 1); +} + +// Ensures that the correct number of strikes are added when the user declines +// the WebAuthn offer. +TEST_F(CreditCardAccessManagerTest, + FIDOEnrollment_OfferDeclinedAfterAccepting_Desktop) { + base::HistogramTester histogram_tester; + std::string promo_shown_histogram_name = + "Autofill.BetterAuth.OptInPromoShown.FromCheckoutFlow"; + std::string promo_user_decision_histogram_name = + "Autofill.BetterAuth.OptInPromoUserDecision.FromCheckoutFlow"; + + ClearStrikes(); + CreateServerCard(kTestGUID, kTestNumber); + CreditCard* card = credit_card_access_manager_->GetCreditCard(kTestGUID); + GetFIDOAuthenticator()->SetUserVerifiable(true); + SetUserOptedIn(false); + payments_client_->AllowFidoRegistration(true); + + credit_card_access_manager_->PrepareToFetchCreditCard(); + credit_card_access_manager_->FetchCreditCard(card, accessor_->GetWeakPtr()); + WaitForCallbacks(); + + // Mock user and payments response. + EXPECT_TRUE(GetRealPanForCVCAuth(AutofillClient::SUCCESS, kTestNumber, + /*fido_opt_in=*/false)); + AcceptWebauthnOfferDialog(/*did_accept=*/true); + AcceptWebauthnOfferDialog(/*did_accept=*/false); + EXPECT_EQ( + FidoAuthenticationStrikeDatabase::kStrikesToAddWhenOptInOfferDeclined, + GetStrikes()); + histogram_tester.ExpectTotalCount(promo_shown_histogram_name, 1); + histogram_tester.ExpectUniqueSample( + promo_user_decision_histogram_name, + AutofillMetrics::WebauthnOptInPromoUserDecisionMetric:: + kDeclinedAfterAccepting, + 1); +} + +// Ensures that the correct number of strikes are added when the user fails to +// complete user-verification for an opt-in attempt. +TEST_F(CreditCardAccessManagerTest, + FIDOEnrollment_UserVerificationFailed_Desktop) { + base::HistogramTester histogram_tester; + std::string webauthn_result_histogram_name = + "Autofill.BetterAuth.WebauthnResult.CheckoutOptIn"; + std::string opt_in_histogram_name = + "Autofill.BetterAuth.OptInCalled.FromCheckoutFlow"; + + ClearStrikes(); + CreateServerCard(kTestGUID, kTestNumber); + CreditCard* card = credit_card_access_manager_->GetCreditCard(kTestGUID); + GetFIDOAuthenticator()->SetUserVerifiable(true); + SetUserOptedIn(false); + payments_client_->AllowFidoRegistration(true); + + credit_card_access_manager_->PrepareToFetchCreditCard(); + credit_card_access_manager_->FetchCreditCard(card, accessor_->GetWeakPtr()); + InvokeUnmaskDetailsTimeout(); + WaitForCallbacks(); + + // Mock user and payments response. + EXPECT_TRUE(GetRealPanForCVCAuth(AutofillClient::SUCCESS, kTestNumber, + /*fido_opt_in=*/false)); + WaitForCallbacks(); + AcceptWebauthnOfferDialog(/*did_accept=*/true); + + OptChange(AutofillClient::SUCCESS, /*user_is_opted_in=*/false, + /*include_creation_options=*/true); + + // Mock user response. + TestCreditCardFIDOAuthenticator::MakeCredential(GetFIDOAuthenticator(), + /*did_succeed=*/false); + EXPECT_EQ(FidoAuthenticationStrikeDatabase:: + kStrikesToAddWhenUserVerificationFailsOnOptInAttempt, + GetStrikes()); + histogram_tester.ExpectUniqueSample( + webauthn_result_histogram_name, + AutofillMetrics::WebauthnResultMetric::kNotAllowedError, 1); + histogram_tester.ExpectUniqueSample( + opt_in_histogram_name, + AutofillMetrics::WebauthnOptInParameters::kFetchingChallenge, 1); +} + +// Ensures that the WebAuthn enrollment prompt is invoked after user opts in. In +// this case, the user is already enrolled server-side, and thus receives +// |request_options|. +TEST_F(CreditCardAccessManagerTest, + FIDOEnrollmentSuccess_RequestOptions_Desktop) { + base::HistogramTester histogram_tester; + std::string webauthn_result_histogram_name = + "Autofill.BetterAuth.WebauthnResult.CheckoutOptIn"; + std::string opt_in_histogram_name = + "Autofill.BetterAuth.OptInCalled.FromCheckoutFlow"; + + CreateServerCard(kTestGUID, kTestNumber); + CreditCard* card = credit_card_access_manager_->GetCreditCard(kTestGUID); + GetFIDOAuthenticator()->SetUserVerifiable(true); + SetUserOptedIn(false); + payments_client_->AllowFidoRegistration(true); + + credit_card_access_manager_->PrepareToFetchCreditCard(); + credit_card_access_manager_->FetchCreditCard(card, accessor_->GetWeakPtr()); + WaitForCallbacks(); + + // Mock user and payments response. + EXPECT_TRUE(GetRealPanForCVCAuth(AutofillClient::SUCCESS, kTestNumber, + /*fido_opt_in=*/false)); + WaitForCallbacks(); + AcceptWebauthnOfferDialog(/*did_accept=*/true); + + OptChange(AutofillClient::SUCCESS, /*user_is_opted_in=*/false, + /*include_creation_options=*/false, + /*include_request_options=*/true); + + // Mock user response and OptChange payments call. + EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITH_CHALLENGE_FLOW, + GetFIDOAuthenticator()->current_flow()); + TestCreditCardFIDOAuthenticator::GetAssertion(GetFIDOAuthenticator(), + /*did_succeed=*/true); + OptChange(AutofillClient::SUCCESS, /*user_is_opted_in=*/true); + + EXPECT_EQ(kGooglePaymentsRpid, GetFIDOAuthenticator()->GetRelyingPartyId()); + EXPECT_EQ(kTestChallenge, + BytesToBase64(GetFIDOAuthenticator()->GetChallenge())); + EXPECT_TRUE(GetFIDOAuthenticator()->IsUserOptedIn()); + + histogram_tester.ExpectUniqueSample( + webauthn_result_histogram_name, + AutofillMetrics::WebauthnResultMetric::kSuccess, 1); + histogram_tester.ExpectTotalCount(opt_in_histogram_name, 2); + histogram_tester.ExpectBucketCount( + opt_in_histogram_name, + AutofillMetrics::WebauthnOptInParameters::kFetchingChallenge, 1); + histogram_tester.ExpectBucketCount( + opt_in_histogram_name, + AutofillMetrics::WebauthnOptInParameters::kWithRequestChallenge, 1); +} + +// Ensures WebAuthn result is logged correctly for a settings page opt-in. +TEST_F(CreditCardAccessManagerTest, SettingsPage_FIDOEnrollment) { + base::HistogramTester histogram_tester; + std::string webauthn_histogram_name = + "Autofill.BetterAuth.WebauthnResult.SettingsPageOptIn"; + std::string opt_in_histogram_name = + "Autofill.BetterAuth.OptInCalled.FromSettingsPage"; + std::string promo_shown_histogram_name = + "Autofill.BetterAuth.OptInPromoShown.FromSettingsPage"; + std::string promo_user_decision_histogram_name = + "Autofill.BetterAuth.OptInPromoUserDecision.FromSettingsPage"; + + GetFIDOAuthenticator()->SetUserVerifiable(true); + + for (bool did_succeed : {false, true}) { + SetUserOptedIn(false); + credit_card_access_manager_->OnSettingsPageFIDOAuthToggled(true); + + // Mock user and payments response. + AcceptWebauthnOfferDialog(/*did_accept=*/true); + OptChange(AutofillClient::SUCCESS, /*user_is_opted_in=*/false, + /*include_creation_options=*/true); + // Mock user response and payments response. + TestCreditCardFIDOAuthenticator::MakeCredential(GetFIDOAuthenticator(), + did_succeed); + + histogram_tester.ExpectBucketCount( + webauthn_histogram_name, + did_succeed ? AutofillMetrics::WebauthnResultMetric::kSuccess + : AutofillMetrics::WebauthnResultMetric::kNotAllowedError, + 1); + } + + histogram_tester.ExpectTotalCount(webauthn_histogram_name, 2); + histogram_tester.ExpectTotalCount(opt_in_histogram_name, 3); + histogram_tester.ExpectBucketCount( + opt_in_histogram_name, + AutofillMetrics::WebauthnOptInParameters::kFetchingChallenge, 2); + histogram_tester.ExpectBucketCount( + opt_in_histogram_name, + AutofillMetrics::WebauthnOptInParameters::kWithCreationChallenge, 1); + histogram_tester.ExpectTotalCount(promo_shown_histogram_name, 2); + histogram_tester.ExpectUniqueSample( + promo_user_decision_histogram_name, + AutofillMetrics::WebauthnOptInPromoUserDecisionMetric::kAccepted, 2); +} + +// Ensure proper metrics are logged when user opts-out from settings page. +TEST_F(CreditCardAccessManagerTest, SettingsPage_OptOut) { + base::HistogramTester histogram_tester; + std::string histogram_name = + "Autofill.BetterAuth.OptOutCalled.FromSettingsPage"; + GetFIDOAuthenticator()->SetUserVerifiable(true); + SetUserOptedIn(false); + + credit_card_access_manager_->OnSettingsPageFIDOAuthToggled(false); + OptChange(AutofillClient::SUCCESS, /*user_is_opted_in=*/false); + + histogram_tester.ExpectTotalCount(histogram_name, 1); +} +#endif // defined(OS_ANDROID) +#endif // !defined(OS_IOS) // Ensures that |is_authentication_in_progress_| is set correctly. TEST_F(CreditCardAccessManagerTest, AuthenticationInProgress) { diff --git a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc index 7a021d8d032..d8f1cb1c685 100644 --- a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc +++ b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc @@ -41,14 +41,16 @@ void CreditCardCVCAuthenticator::OnFullCardRequestSucceeded( const payments::FullCardRequest& full_card_request, const CreditCard& card, const base::string16& cvc) { + payments::PaymentsClient::UnmaskResponseDetails response = + full_card_request.unmask_response_details(); requester_->OnCVCAuthenticationComplete( CVCAuthenticationResponse() .with_did_succeed(true) .with_card(&card) .with_cvc(cvc) - .with_creation_options( - std::move(full_card_request.unmask_response_details() - .fido_creation_options))); + .with_creation_options(std::move(response.fido_creation_options)) + .with_request_options(std::move(response.fido_request_options)) + .with_card_authorization_token(response.card_authorization_token)); } void CreditCardCVCAuthenticator::OnFullCardRequestFailed() { diff --git a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h index 05ad5b7f02e..a470eb83e10 100644 --- a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h +++ b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h @@ -42,10 +42,21 @@ class CreditCardCVCAuthenticator creation_options = std::move(v); return *this; } + CVCAuthenticationResponse& with_request_options( + base::Optional<base::Value> v) { + request_options = std::move(v); + return *this; + } + CVCAuthenticationResponse& with_card_authorization_token(std::string s) { + card_authorization_token = s; + return *this; + } bool did_succeed = false; const CreditCard* card = nullptr; base::string16 cvc = base::string16(); base::Optional<base::Value> creation_options = base::nullopt; + base::Optional<base::Value> request_options = base::nullopt; + std::string card_authorization_token = std::string(); }; class Requester { public: diff --git a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc index 58a13a370b8..d036800e783 100644 --- a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc @@ -51,6 +51,7 @@ #include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" +#include "components/autofill/core/common/autofill_tick_clock.h" #include "components/autofill/core/common/autofill_util.h" #include "components/prefs/pref_service.h" #include "components/security_state/core/security_state.h" @@ -75,13 +76,13 @@ const char kTestNumber[] = "4234567890123456"; // Visa std::string NextYear() { base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); + AutofillClock::Now().LocalExplode(&now); return base::NumberToString(now.year + 1); } std::string NextMonth() { base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); + AutofillClock::Now().LocalExplode(&now); return base::NumberToString(now.month % 12 + 1); } @@ -144,6 +145,13 @@ class CreditCardCVCAuthenticatorTest : public testing::Test { payments::FullCardRequest* full_card_request = cvc_authenticator_->full_card_request_.get(); DCHECK(full_card_request); + + // Mock user response. + payments::FullCardRequest::UserProvidedUnmaskDetails details; + details.cvc = base::ASCIIToUTF16("123"); + full_card_request->OnUnmaskPromptAccepted(details); + + // Mock payments response. payments::PaymentsClient::UnmaskResponseDetails response; full_card_request->OnDidGetRealPan(result, response.with_real_pan(real_pan)); @@ -165,7 +173,7 @@ TEST_F(CreditCardCVCAuthenticatorTest, AuthenticateServerCardSuccess) { cvc_authenticator_->Authenticate(&card, requester_->GetWeakPtr(), &personal_data_manager_, - base::TimeTicks::Now()); + AutofillTickClock::NowTicks()); OnDidGetRealPan(AutofillClient::SUCCESS, kTestNumber); EXPECT_TRUE(requester_->did_succeed()); @@ -177,7 +185,7 @@ TEST_F(CreditCardCVCAuthenticatorTest, AuthenticateServerCardNetworkError) { cvc_authenticator_->Authenticate(&card, requester_->GetWeakPtr(), &personal_data_manager_, - base::TimeTicks::Now()); + AutofillTickClock::NowTicks()); OnDidGetRealPan(AutofillClient::NETWORK_ERROR, std::string()); EXPECT_FALSE(requester_->did_succeed()); @@ -188,7 +196,7 @@ TEST_F(CreditCardCVCAuthenticatorTest, AuthenticateServerCardPermanentFailure) { cvc_authenticator_->Authenticate(&card, requester_->GetWeakPtr(), &personal_data_manager_, - base::TimeTicks::Now()); + AutofillTickClock::NowTicks()); OnDidGetRealPan(AutofillClient::PERMANENT_FAILURE, std::string()); EXPECT_FALSE(requester_->did_succeed()); @@ -199,7 +207,7 @@ TEST_F(CreditCardCVCAuthenticatorTest, AuthenticateServerCardTryAgainFailure) { cvc_authenticator_->Authenticate(&card, requester_->GetWeakPtr(), &personal_data_manager_, - base::TimeTicks::Now()); + AutofillTickClock::NowTicks()); OnDidGetRealPan(AutofillClient::TRY_AGAIN_FAILURE, std::string()); EXPECT_FALSE(requester_->did_succeed()); diff --git a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc index e6c15670b42..6cb340e60d9 100644 --- a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc +++ b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc @@ -12,8 +12,11 @@ #include "base/containers/flat_set.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" +#include "build/build_config.h" #include "components/autofill/core/browser/autofill_client.h" +#include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/data_model/credit_card.h" +#include "components/autofill/core/browser/payments/fido_authentication_strike_database.h" #include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/common/autofill_payments_features.h" @@ -28,8 +31,6 @@ namespace autofill { namespace { // Default timeout for user to respond to WebAuthn prompt. constexpr int kWebAuthnTimeoutMs = 3 * 60 * 1000; // 3 minutes -// Timeout to wait for synchronous version of IsUserVerifiable(). -constexpr int kIsUserVerifiableTimeoutMs = 1000; constexpr char kGooglePaymentsRpid[] = "google.com"; constexpr char kGooglePaymentsRpName[] = "Google Payments"; @@ -60,10 +61,14 @@ CreditCardFIDOAuthenticator::CreditCardFIDOAuthenticator(AutofillDriver* driver, CreditCardFIDOAuthenticator::~CreditCardFIDOAuthenticator() {} -void CreditCardFIDOAuthenticator::ShowWebauthnOfferDialog() { +void CreditCardFIDOAuthenticator::ShowWebauthnOfferDialog( + std::string card_authorization_token) { + card_authorization_token_ = card_authorization_token; autofill_client_->ShowWebauthnOfferDialog(base::BindRepeating( &CreditCardFIDOAuthenticator::OnWebauthnOfferDialogUserResponse, weak_ptr_factory_.GetWeakPtr())); + AutofillMetrics::LogWebauthnOptInPromoShown( + /*is_checkout_flow=*/!card_authorization_token_.empty()); } void CreditCardFIDOAuthenticator::Authenticate( @@ -83,31 +88,50 @@ void CreditCardFIDOAuthenticator::Authenticate( } } -void CreditCardFIDOAuthenticator::Register(base::Value creation_options) { +void CreditCardFIDOAuthenticator::Register(std::string card_authorization_token, + base::Value creation_options) { // If |creation_options| is set, then must enroll a new credential. Otherwise // directly send request to payments for opting in. + card_authorization_token_ = card_authorization_token; if (creation_options.is_dict()) { if (IsValidCreationOptions(creation_options)) { current_flow_ = OPT_IN_WITH_CHALLENGE_FLOW; MakeCredential(ParseCreationOptions(creation_options)); } } else { - current_flow_ = OPT_IN_WITHOUT_CHALLENGE_FLOW; - OptChange(/*opt_in=*/true); + current_flow_ = OPT_IN_FETCH_CHALLENGE_FLOW; + OptChange(); + } +} + +void CreditCardFIDOAuthenticator::Authorize( + std::string card_authorization_token, + base::Value request_options) { + card_authorization_token_ = card_authorization_token; + if (IsValidRequestOptions(request_options)) { + // If user is already opted-in, then a new card is trying to be + // authorized. Otherwise, a user with a credential on file is trying to + // opt-in. + current_flow_ = IsUserOptedIn() ? FOLLOWUP_AFTER_CVC_AUTH_FLOW + : OPT_IN_WITH_CHALLENGE_FLOW; + GetAssertion(ParseRequestOptions(std::move(request_options))); } } void CreditCardFIDOAuthenticator::OptOut() { current_flow_ = OPT_OUT_FLOW; - OptChange(/*opt_in=*/false); + card_authorization_token_ = std::string(); + OptChange(); } void CreditCardFIDOAuthenticator::IsUserVerifiable( base::OnceCallback<void(bool)> callback) { if (base::FeatureList::IsEnabled( features::kAutofillCreditCardAuthentication)) { - autofill_driver_->ConnectToAuthenticator( - authenticator_.BindNewPipeAndPassReceiver()); + if (!authenticator_.is_bound()) { + autofill_driver_->ConnectToAuthenticator( + authenticator_.BindNewPipeAndPassReceiver()); + } authenticator_->IsUserVerifyingPlatformAuthenticatorAvailable( std::move(callback)); } else { @@ -115,21 +139,6 @@ void CreditCardFIDOAuthenticator::IsUserVerifiable( } } -bool CreditCardFIDOAuthenticator::IsUserVerifiable() { - if (user_is_verifiable_.has_value()) - return user_is_verifiable_.value(); - - IsUserVerifiable( - base::BindOnce(&CreditCardFIDOAuthenticator::SetUserIsVerifiable, - weak_ptr_factory_.GetWeakPtr())); - - user_is_verifiable_callback_received_.declare_only_used_while_idle(); - user_is_verifiable_callback_received_.TimedWait( - base::TimeDelta::FromMilliseconds(kIsUserVerifiableTimeoutMs)); - - return user_is_verifiable_.value_or(false); -} - bool CreditCardFIDOAuthenticator::IsUserOptedIn() { return base::FeatureList::IsEnabled( features::kAutofillCreditCardAuthentication) && @@ -157,10 +166,41 @@ void CreditCardFIDOAuthenticator::SyncUserOptIn( is_user_opted_in); } +FidoAuthenticationStrikeDatabase* +CreditCardFIDOAuthenticator::GetOrCreateFidoAuthenticationStrikeDatabase() { + if (!fido_authentication_strike_database_) { + fido_authentication_strike_database_ = + std::make_unique<FidoAuthenticationStrikeDatabase>( + FidoAuthenticationStrikeDatabase( + autofill_client_->GetStrikeDatabase())); + } + return fido_authentication_strike_database_.get(); +} + void CreditCardFIDOAuthenticator::GetAssertion( PublicKeyCredentialRequestOptionsPtr request_options) { - autofill_driver_->ConnectToAuthenticator( - authenticator_.BindNewPipeAndPassReceiver()); + if (!authenticator_.is_bound()) { + autofill_driver_->ConnectToAuthenticator( + authenticator_.BindNewPipeAndPassReceiver()); + } +#if !defined(OS_ANDROID) + // On desktop, during an opt-in flow, close the WebAuthn offer dialog and get + // ready to show the OS level authentication dialog. If dialog is already + // closed, then the offer was declined during the fetching challenge process, + // and thus returned early. + if (current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW) { + if (autofill_client_->CloseWebauthnOfferDialog()) { + // Now that the dialog has closed and will proceed to a WebAuthn prompt, + // the user must have accepted the dialog without cancelling. + AutofillMetrics::LogWebauthnOptInPromoUserDecision( + /*is_checkout_flow=*/!card_authorization_token_.empty(), + AutofillMetrics::WebauthnOptInPromoUserDecisionMetric::kAccepted); + } else { + current_flow_ = NONE_FLOW; + return; + } + } +#endif authenticator_->GetAssertion( std::move(request_options), base::BindOnce(&CreditCardFIDOAuthenticator::OnDidGetAssertion, @@ -169,92 +209,222 @@ void CreditCardFIDOAuthenticator::GetAssertion( void CreditCardFIDOAuthenticator::MakeCredential( PublicKeyCredentialCreationOptionsPtr creation_options) { - autofill_driver_->ConnectToAuthenticator( - authenticator_.BindNewPipeAndPassReceiver()); + if (!authenticator_.is_bound()) { + autofill_driver_->ConnectToAuthenticator( + authenticator_.BindNewPipeAndPassReceiver()); + } +#if !defined(OS_ANDROID) + // On desktop, close the WebAuthn offer dialog and get ready to show the OS + // level authentication dialog. If dialog is already closed, then the offer + // was declined during the fetching challenge process, and thus returned + // early. + if (autofill_client_->CloseWebauthnOfferDialog()) { + // Now that the dialog has closed and will proceed to a WebAuthn prompt, + // the user must have accepted the dialog without cancelling. + AutofillMetrics::LogWebauthnOptInPromoUserDecision( + /*is_checkout_flow=*/!card_authorization_token_.empty(), + AutofillMetrics::WebauthnOptInPromoUserDecisionMetric::kAccepted); + } else { + current_flow_ = NONE_FLOW; + return; + } +#endif authenticator_->MakeCredential( std::move(creation_options), base::BindOnce(&CreditCardFIDOAuthenticator::OnDidMakeCredential, weak_ptr_factory_.GetWeakPtr())); } -void CreditCardFIDOAuthenticator::OptChange(bool opt_in, - base::Value attestation_response) { +void CreditCardFIDOAuthenticator::OptChange( + base::Value authenticator_response) { payments::PaymentsClient::OptChangeRequestDetails request_details; request_details.app_locale = autofill_client_->GetPersonalDataManager()->app_locale(); - request_details.opt_in = opt_in; - if (attestation_response.is_dict()) { + + switch (current_flow_) { + case OPT_IN_WITH_CHALLENGE_FLOW: + case OPT_IN_FETCH_CHALLENGE_FLOW: + request_details.reason = + payments::PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH; + break; + case OPT_OUT_FLOW: + request_details.reason = + payments::PaymentsClient::OptChangeRequestDetails::DISABLE_FIDO_AUTH; + break; + case FOLLOWUP_AFTER_CVC_AUTH_FLOW: + request_details.reason = payments::PaymentsClient:: + OptChangeRequestDetails::ADD_CARD_FOR_FIDO_AUTH; + break; + default: + NOTREACHED(); + break; + } + + // If |authenticator_response| is set, that means the user just signed a + // challenge. In which case, if |card_authorization_token_| is not empty, then + // that will be required to bind a previous CVC check with this signature. + // This will opt the user in and authorize the card corresponding to + // |card_authorization_token_|. + // If |authenticator_response| is not set, that means the user was fetching a + // challenge, in which case |card_authorization_token_| will be required for + // the subsequent OptChange call. + AutofillMetrics::WebauthnOptInParameters opt_change_metric; + bool is_checkout_flow = !card_authorization_token_.empty(); + if (authenticator_response.is_dict()) { request_details.fido_authenticator_response = - std::move(attestation_response); + std::move(authenticator_response); + opt_change_metric = + request_details.fido_authenticator_response.FindKey( + "fido_assertion_info") + ? AutofillMetrics::WebauthnOptInParameters::kWithRequestChallenge + : AutofillMetrics::WebauthnOptInParameters::kWithCreationChallenge; + if (!card_authorization_token_.empty()) { + request_details.card_authorization_token = card_authorization_token_; + card_authorization_token_ = std::string(); + } + } else { + opt_change_metric = + AutofillMetrics::WebauthnOptInParameters::kFetchingChallenge; } payments_client_->OptChange( request_details, base::BindOnce(&CreditCardFIDOAuthenticator::OnDidGetOptChangeResult, weak_ptr_factory_.GetWeakPtr())); + + // Logging call if user was attempting to change their opt-in state. + if (current_flow_ != FOLLOWUP_AFTER_CVC_AUTH_FLOW) { + bool request_to_opt_in = (current_flow_ != OPT_OUT_FLOW); + AutofillMetrics::LogWebauthnOptChangeCalled( + request_to_opt_in, is_checkout_flow, opt_change_metric); + } } void CreditCardFIDOAuthenticator::OnDidGetAssertion( AuthenticatorStatus status, GetAssertionAuthenticatorResponsePtr assertion_response) { + LogWebauthnResult(status); + // End the flow if there was an authentication error. if (status != AuthenticatorStatus::SUCCESS) { + // Report failure to |requester_| if card unmasking was requested. + if (current_flow_ == AUTHENTICATION_FLOW) + requester_->OnFIDOAuthenticationComplete(/*did_succeed=*/false); + + // Treat failure to perform user verification as a strong signal not to + // offer opt-in in the future. + if (current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW) { + GetOrCreateFidoAuthenticationStrikeDatabase()->AddStrikes( + FidoAuthenticationStrikeDatabase:: + kStrikesToAddWhenUserVerificationFailsOnOptInAttempt); + } + current_flow_ = NONE_FLOW; - requester_->OnFIDOAuthenticationComplete(/*did_succeed=*/false); return; } - base::Value response = ParseAssertionResponse(std::move(assertion_response)); - full_card_request_.reset(new payments::FullCardRequest( - autofill_client_, autofill_client_->GetPaymentsClient(), - autofill_client_->GetPersonalDataManager(), form_parsed_timestamp_)); - full_card_request_->GetFullCardViaFIDO( - *card_, AutofillClient::UNMASK_FOR_AUTOFILL, - weak_ptr_factory_.GetWeakPtr(), std::move(response)); + if (current_flow_ == AUTHENTICATION_FLOW) { + base::Value response = + ParseAssertionResponse(std::move(assertion_response)); + full_card_request_.reset(new payments::FullCardRequest( + autofill_client_, autofill_client_->GetPaymentsClient(), + autofill_client_->GetPersonalDataManager(), form_parsed_timestamp_)); + full_card_request_->GetFullCardViaFIDO( + *card_, AutofillClient::UNMASK_FOR_AUTOFILL, + weak_ptr_factory_.GetWeakPtr(), std::move(response)); + } else { + DCHECK(current_flow_ == FOLLOWUP_AFTER_CVC_AUTH_FLOW || + current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW); + base::Value response = base::Value(base::Value::Type::DICTIONARY); + response.SetKey("fido_assertion_info", + ParseAssertionResponse(std::move(assertion_response))); + OptChange(std::move(response)); + } } void CreditCardFIDOAuthenticator::OnDidMakeCredential( AuthenticatorStatus status, MakeCredentialAuthenticatorResponsePtr attestation_response) { + LogWebauthnResult(status); + // End the flow if there was an authentication error. if (status != AuthenticatorStatus::SUCCESS) { + // Treat failure to perform user verification as a strong signal not to + // offer opt-in in the future. + if (current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW) { + GetOrCreateFidoAuthenticationStrikeDatabase()->AddStrikes( + FidoAuthenticationStrikeDatabase:: + kStrikesToAddWhenUserVerificationFailsOnOptInAttempt); + } + current_flow_ = NONE_FLOW; return; } - OptChange(/*opt_in=*/true, - ParseAttestationResponse(std::move(attestation_response))); + OptChange(ParseAttestationResponse(std::move(attestation_response))); } void CreditCardFIDOAuthenticator::OnDidGetOptChangeResult( AutofillClient::PaymentsRpcResult result, - bool user_is_opted_in, - base::Value creation_options) { - DCHECK(current_flow_ == OPT_IN_WITHOUT_CHALLENGE_FLOW || + payments::PaymentsClient::OptChangeResponseDetails& response) { + DCHECK(current_flow_ == OPT_IN_FETCH_CHALLENGE_FLOW || current_flow_ == OPT_OUT_FLOW || - current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW); + current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW || + current_flow_ == FOLLOWUP_AFTER_CVC_AUTH_FLOW); + + // Update user preference to keep in sync with server. + ::autofill::prefs::SetCreditCardFIDOAuthEnabled( + autofill_client_->GetPrefs(), + response.user_is_opted_in.value_or(IsUserOptedIn())); + // End the flow if the server responded with an error. if (result != AutofillClient::PaymentsRpcResult::SUCCESS) { + if (current_flow_ == OPT_IN_FETCH_CHALLENGE_FLOW) + autofill_client_->UpdateWebauthnOfferDialogWithError(); current_flow_ = NONE_FLOW; return; } - // If response contains |creation_options| and the last opt-in attempt did not - // include a challenge, then invoke WebAuthn registration prompt. Otherwise, - // set pref to enable FIDO Authentication for card unmask and end the flow. - if (creation_options.is_dict() && - current_flow_ == OPT_IN_WITHOUT_CHALLENGE_FLOW) { - Register(std::move(creation_options)); + // If response contains |creation_options| or |request_options| and the last + // opt-in attempt did not include a challenge, then invoke WebAuthn + // registration/verification prompt. Otherwise end the flow. + if (current_flow_ == OPT_IN_FETCH_CHALLENGE_FLOW) { + if (response.fido_creation_options.has_value()) { + Register(card_authorization_token_, + std::move(response.fido_creation_options.value())); + } else if (response.fido_request_options.has_value()) { + Authorize(card_authorization_token_, + std::move(response.fido_request_options.value())); + } } else { - ::autofill::prefs::SetCreditCardFIDOAuthEnabled( - autofill_client_->GetPrefs(), user_is_opted_in); current_flow_ = NONE_FLOW; } } void CreditCardFIDOAuthenticator::OnWebauthnOfferDialogUserResponse( bool did_accept) { - // TODO(crbug.com/): Register and start fetching authentication challenge if - // |did_accept|, otherwise cancel any ongoing request. + if (did_accept) { + // Wait until GetAssertion()/MakeCredential() to log user acceptance, since + // user still has the option to cancel the dialog while the challenge is + // being fetched. + Register(card_authorization_token_); + } else { + // If user declined, log user decision. User may have initially accepted the + // dialog, but then chose to cancel while the challenge was being fetched. + AutofillMetrics::LogWebauthnOptInPromoUserDecision( + /*is_checkout_flow=*/!card_authorization_token_.empty(), + current_flow_ == OPT_IN_FETCH_CHALLENGE_FLOW + ? AutofillMetrics::WebauthnOptInPromoUserDecisionMetric:: + kDeclinedAfterAccepting + : AutofillMetrics::WebauthnOptInPromoUserDecisionMetric:: + kDeclinedImmediately); + payments_client_->CancelRequest(); + card_authorization_token_ = std::string(); + current_flow_ = NONE_FLOW; + GetOrCreateFidoAuthenticationStrikeDatabase()->AddStrikes( + FidoAuthenticationStrikeDatabase::kStrikesToAddWhenOptInOfferDeclined); + ::autofill::prefs::SetCreditCardFIDOAuthEnabled( + autofill_client_->GetPrefs(), false); + } } void CreditCardFIDOAuthenticator::OnFullCardRequestSucceeded( @@ -356,6 +526,23 @@ CreditCardFIDOAuthenticator::ParseCreationOptions( options->adjusted_timeout = base::TimeDelta::FromMilliseconds( timeout ? timeout->GetInt() : kWebAuthnTimeoutMs); + const auto* attestation = + creation_options.FindStringKey("attestation_conveyance_preference"); + if (!attestation || base::EqualsCaseInsensitiveASCII(*attestation, "NONE")) { + options->attestation = AttestationConveyancePreference::kNone; + } else if (base::EqualsCaseInsensitiveASCII(*attestation, "INDIRECT")) { + options->attestation = AttestationConveyancePreference::kIndirect; + } else if (base::EqualsCaseInsensitiveASCII(*attestation, "DIRECT")) { + options->attestation = AttestationConveyancePreference::kDirect; + } else { + NOTREACHED(); + } + + // Only allow user-verifying platform authenticators. + options->authenticator_selection = AuthenticatorSelectionCriteria( + AuthenticatorAttachment::kPlatform, /*require_resident_key=*/false, + UserVerificationRequirement::kRequired); + // List of keys that Payments already knows about, and so should not make a // new credential. const auto* excluded_keys_list = @@ -398,7 +585,8 @@ CreditCardFIDOAuthenticator::ParseCredentialDescriptor( base::Value CreditCardFIDOAuthenticator::ParseAssertionResponse( GetAssertionAuthenticatorResponsePtr assertion_response) { base::Value response = base::Value(base::Value::Type::DICTIONARY); - response.SetKey("credential_id", base::Value(assertion_response->info->id)); + response.SetKey("credential_id", + BytesToBase64(assertion_response->info->raw_id)); response.SetKey("authenticator_data", BytesToBase64(assertion_response->authenticator_data)); response.SetKey("client_data", @@ -423,7 +611,7 @@ base::Value CreditCardFIDOAuthenticator::ParseAttestationResponse( base::Value authenticator_transport_list = base::Value(base::Value::Type::LIST); for (FidoTransportProtocol protocol : attestation_response->transports) { - authenticator_transport_list.GetList().push_back( + authenticator_transport_list.Append( base::Value(base::ToUpperASCII(device::ToString(protocol)))); } @@ -462,9 +650,38 @@ bool CreditCardFIDOAuthenticator::IsValidCreationOptions( creation_options.FindStringKey("challenge"); } -void CreditCardFIDOAuthenticator::SetUserIsVerifiable(bool user_is_verifiable) { - user_is_verifiable_ = user_is_verifiable; - user_is_verifiable_callback_received_.Signal(); -} +void CreditCardFIDOAuthenticator::LogWebauthnResult( + AuthenticatorStatus status) { + AutofillMetrics::WebauthnFlowEvent event; + switch (current_flow_) { + case AUTHENTICATION_FLOW: + event = AutofillMetrics::WebauthnFlowEvent::kImmediateAuthentication; + break; + case FOLLOWUP_AFTER_CVC_AUTH_FLOW: + event = AutofillMetrics::WebauthnFlowEvent::kAuthenticationAfterCvc; + break; + case OPT_IN_WITH_CHALLENGE_FLOW: + event = card_authorization_token_.empty() + ? AutofillMetrics::WebauthnFlowEvent::kSettingsPageOptIn + : AutofillMetrics::WebauthnFlowEvent::kCheckoutOptIn; + break; + default: + NOTREACHED(); + return; + } + AutofillMetrics::WebauthnResultMetric metric; + switch (status) { + case AuthenticatorStatus::SUCCESS: + metric = AutofillMetrics::WebauthnResultMetric::kSuccess; + break; + case AuthenticatorStatus::NOT_ALLOWED_ERROR: + metric = AutofillMetrics::WebauthnResultMetric::kNotAllowedError; + break; + default: + metric = AutofillMetrics::WebauthnResultMetric::kOtherError; + break; + } + AutofillMetrics::LogWebauthnResult(event, metric); +} } // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h index 01aef853526..e7d89ad1950 100644 --- a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h +++ b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h @@ -11,6 +11,7 @@ #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_driver.h" #include "components/autofill/core/browser/data_model/credit_card.h" +#include "components/autofill/core/browser/payments/fido_authentication_strike_database.h" #include "components/autofill/core/browser/payments/full_card_request.h" #include "components/autofill/core/browser/payments/payments_client.h" #include "device/fido/fido_constants.h" @@ -29,6 +30,9 @@ using blink::mojom::PublicKeyCredentialCreationOptions; using blink::mojom::PublicKeyCredentialCreationOptionsPtr; using blink::mojom::PublicKeyCredentialRequestOptions; using blink::mojom::PublicKeyCredentialRequestOptionsPtr; +using device::AttestationConveyancePreference; +using device::AuthenticatorAttachment; +using device::AuthenticatorSelectionCriteria; using device::CredentialType; using device::FidoTransportProtocol; using device::PublicKeyCredentialDescriptor; @@ -53,9 +57,11 @@ class CreditCardFIDOAuthenticator // Registration flow, including a challenge to sign. OPT_IN_WITH_CHALLENGE_FLOW, // Opt-in attempt flow, no challenge to sign. - OPT_IN_WITHOUT_CHALLENGE_FLOW, + OPT_IN_FETCH_CHALLENGE_FLOW, // Opt-out flow. OPT_OUT_FLOW, + // Authorization of a new card. + FOLLOWUP_AFTER_CVC_AUTH_FLOW, }; class Requester { public: @@ -68,16 +74,25 @@ class CreditCardFIDOAuthenticator ~CreditCardFIDOAuthenticator() override; // Offer the option to use WebAuthn for authenticating future card unmasking. - void ShowWebauthnOfferDialog(); + void ShowWebauthnOfferDialog(std::string card_authorization_token); - // Authentication + // Invokes Authentication flow. Responds to |accessor_| with full pan. void Authenticate(const CreditCard* card, base::WeakPtr<Requester> requester, base::TimeTicks form_parsed_timestamp, base::Value request_options); - // Registration - void Register(base::Value creation_options = base::Value()); + // Invokes Registration flow. Sends credentials created from + // |creation_options| along with the |card_authorization_token| to Payments in + // order to enroll the user and authorize the corresponding card. + void Register(std::string card_authorization_token = std::string(), + base::Value creation_options = base::Value()); + + // Invokes an Authorization flow. Sends signature created from + // |request_options| along with the |card_authorization_token| to Payments in + // order to authorize the corresponding card. + void Authorize(std::string card_authorization_token, + base::Value request_options); // Opts the user out. void OptOut(); @@ -87,15 +102,16 @@ class CreditCardFIDOAuthenticator // and enabled. Otherwise invokes callback with false. virtual void IsUserVerifiable(base::OnceCallback<void(bool)> callback); - // The synchronous version of IsUserVerifiable. Used on settings page load. - bool IsUserVerifiable(); - // Returns true only if the user has opted-in to use WebAuthn for autofill. virtual bool IsUserOptedIn(); // Ensures that local user opt-in pref is in-sync with payments server. void SyncUserOptIn(AutofillClient::UnmaskDetails& unmask_details); + // Retrieves the strike database for offering FIDO authentication. + FidoAuthenticationStrikeDatabase* + GetOrCreateFidoAuthenticationStrikeDatabase(); + // Returns the current flow. Flow current_flow() { return current_flow_; } @@ -124,7 +140,7 @@ class CreditCardFIDOAuthenticator PublicKeyCredentialCreationOptionsPtr creation_options); // Makes a request to payments to either opt-in or opt-out the user. - void OptChange(bool opt_in, base::Value attestation_response = base::Value()); + void OptChange(base::Value authenticator_response = base::Value()); // The callback invoked from the WebAuthn prompt including the // |assertion_response|, which will be sent to Google Payments to retrieve @@ -141,9 +157,9 @@ class CreditCardFIDOAuthenticator MakeCredentialAuthenticatorResponsePtr attestation_response); // Sets prefstore to enable credit card authentication if rpc was successful. - void OnDidGetOptChangeResult(AutofillClient::PaymentsRpcResult result, - bool user_is_opted_in, - base::Value creation_options = base::Value()); + void OnDidGetOptChangeResult( + AutofillClient::PaymentsRpcResult result, + payments::PaymentsClient::OptChangeResponseDetails& response); // The callback invoked from the WebAuthn offer dialog when it is accepted or // declined/cancelled. @@ -184,8 +200,8 @@ class CreditCardFIDOAuthenticator // Returns true if |request_options| contains a challenge. bool IsValidCreationOptions(const base::Value& creation_options); - // Sets the value for |user_is_verifiable_|. - void SetUserIsVerifiable(bool user_is_verifiable); + // Logs the result of a WebAuthn prompt. + void LogWebauthnResult(AuthenticatorStatus status); // Card being unmasked. const CreditCard* card_; @@ -193,6 +209,10 @@ class CreditCardFIDOAuthenticator // The current flow in progress. Flow current_flow_ = NONE_FLOW; + // Token used for authorizing new cards. Helps tie CVC auth and FIDO calls + // together in order to support FIDO-only unmasking on future attempts. + std::string card_authorization_token_; + // Meant for histograms recorded in FullCardRequest. base::TimeTicks form_parsed_timestamp_; @@ -215,8 +235,10 @@ class CreditCardFIDOAuthenticator // Weak pointer to object that is requesting authentication. base::WeakPtr<Requester> requester_; - // Set when callback for IsUserVerifiable() is invoked with passed value. - base::Optional<bool> user_is_verifiable_ = base::nullopt; + // Strike database to ensure we limit the number of times we offer fido + // authentication. + std::unique_ptr<FidoAuthenticationStrikeDatabase> + fido_authentication_strike_database_; // Signaled when callback for IsUserVerifiable() is invoked. base::WaitableEvent user_is_verifiable_callback_received_; diff --git a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc index 3ec70dc08e8..1146593947d 100644 --- a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc @@ -53,6 +53,7 @@ #include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" +#include "components/autofill/core/common/autofill_tick_clock.h" #include "components/autofill/core/common/autofill_util.h" #include "components/prefs/pref_service.h" #include "components/security_state/core/security_state.h" @@ -85,10 +86,11 @@ constexpr char kTestChallenge[] = "VGhpcyBpcyBhIHRlc3QgY2hhbGxlbmdl"; const char kTestCredentialId[] = "VGhpcyBpcyBhIHRlc3QgQ3JlZGVudGlhbCBJRC4="; // Base64 encoding of "This is a test signature". const char kTestSignature[] = "VGhpcyBpcyBhIHRlc3Qgc2lnbmF0dXJl"; +const char kTestAuthToken[] = "dummy_card_authorization_token"; std::string NextMonth() { base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); + AutofillClock::Now().LocalExplode(&now); return base::NumberToString(now.month % 12 + 1); } @@ -133,6 +135,8 @@ class CreditCardFIDOAuthenticatorTest : public testing::Test { autofill_client_.GetIdentityManager(), &personal_data_manager_); autofill_client_.set_test_payments_client( std::unique_ptr<payments::TestPaymentsClient>(payments_client)); + autofill_client_.set_test_strike_database( + std::make_unique<TestStrikeDatabase>()); fido_authenticator_ = std::make_unique<CreditCardFIDOAuthenticator>( autofill_driver_.get(), &autofill_client_); } @@ -218,9 +222,19 @@ class CreditCardFIDOAuthenticatorTest : public testing::Test { // Mocks an OptChange response from Payments Client. void OptChange(AutofillClient::PaymentsRpcResult result, bool user_is_opted_in, - base::Value creation_options = base::Value()) { - fido_authenticator_->OnDidGetOptChangeResult(result, user_is_opted_in, - std::move(creation_options)); + bool include_creation_options = false, + bool include_request_options = false) { + payments::PaymentsClient::OptChangeResponseDetails response; + response.user_is_opted_in = user_is_opted_in; + if (include_creation_options) { + response.fido_creation_options = + GetTestCreationOptions(kTestChallenge, kTestRelyingPartyId); + } + if (include_request_options) { + response.fido_request_options = GetTestRequestOptions( + kTestChallenge, kTestRelyingPartyId, kTestCredentialId); + } + fido_authenticator_->OnDidGetOptChangeResult(result, response); } protected: @@ -291,10 +305,6 @@ TEST_F(CreditCardFIDOAuthenticatorTest, IsUserVerifiable_False) { EXPECT_FALSE(requester_->is_user_verifiable().value()); } -TEST_F(CreditCardFIDOAuthenticatorTest, Sync_IsUserVerifiable_False) { - EXPECT_FALSE(fido_authenticator_->IsUserVerifiable()); -} - TEST_F(CreditCardFIDOAuthenticatorTest, ParseRequestOptions) { base::Value request_options_json = GetTestRequestOptions( kTestChallenge, kTestRelyingPartyId, kTestCredentialId); @@ -311,7 +321,7 @@ TEST_F(CreditCardFIDOAuthenticatorTest, ParseAssertionResponse) { GetAssertionAuthenticatorResponsePtr assertion_response_ptr = GetAssertionAuthenticatorResponse::New(); assertion_response_ptr->info = blink::mojom::CommonCredentialInfo::New(); - assertion_response_ptr->info->id = kTestCredentialId; + assertion_response_ptr->info->raw_id = Base64ToBytes(kTestCredentialId); assertion_response_ptr->signature = Base64ToBytes(kTestSignature); base::Value assertion_response_json = @@ -332,6 +342,14 @@ TEST_F(CreditCardFIDOAuthenticatorTest, ParseCreationOptions) { std::move(creation_options_json)); EXPECT_EQ(kTestChallenge, BytesToBase64(creation_options_ptr->challenge)); EXPECT_EQ(kTestRelyingPartyId, creation_options_ptr->relying_party.id); + + // Ensure only platform authenticators are allowed. + EXPECT_EQ(AuthenticatorAttachment::kPlatform, + creation_options_ptr->authenticator_selection + ->authenticator_attachment()); + EXPECT_EQ(UserVerificationRequirement::kRequired, + creation_options_ptr->authenticator_selection + ->user_verification_requirement()); } TEST_F(CreditCardFIDOAuthenticatorTest, ParseAttestationResponse) { @@ -351,7 +369,7 @@ TEST_F(CreditCardFIDOAuthenticatorTest, AuthenticateCard_BadRequestOptions) { CreditCard card = CreateServerCard(kTestGUID, kTestNumber); fido_authenticator_->Authenticate(&card, requester_->GetWeakPtr(), - base::TimeTicks::Now(), + AutofillTickClock::NowTicks(), base::Value(base::Value::Type::DICTIONARY)); EXPECT_FALSE(requester_->did_succeed()); } @@ -360,9 +378,10 @@ TEST_F(CreditCardFIDOAuthenticatorTest, AuthenticateCard_UserVerificationFailed) { CreditCard card = CreateServerCard(kTestGUID, kTestNumber); - fido_authenticator_->Authenticate(&card, requester_->GetWeakPtr(), - base::TimeTicks::Now(), - base::Value(base::Value::Type::DICTIONARY)); + fido_authenticator_->Authenticate( + &card, requester_->GetWeakPtr(), AutofillTickClock::NowTicks(), + GetTestRequestOptions(kTestChallenge, kTestRelyingPartyId, + kTestCredentialId)); TestCreditCardFIDOAuthenticator::GetAssertion(fido_authenticator_.get(), /*did_succeed=*/false); @@ -374,7 +393,7 @@ TEST_F(CreditCardFIDOAuthenticatorTest, CreditCard card = CreateServerCard(kTestGUID, kTestNumber); fido_authenticator_->Authenticate( - &card, requester_->GetWeakPtr(), base::TimeTicks::Now(), + &card, requester_->GetWeakPtr(), AutofillTickClock::NowTicks(), GetTestRequestOptions(kTestChallenge, kTestRelyingPartyId, kTestCredentialId)); EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::AUTHENTICATION_FLOW, @@ -392,7 +411,7 @@ TEST_F(CreditCardFIDOAuthenticatorTest, AuthenticateCard_Success) { CreditCard card = CreateServerCard(kTestGUID, kTestNumber); fido_authenticator_->Authenticate( - &card, requester_->GetWeakPtr(), base::TimeTicks::Now(), + &card, requester_->GetWeakPtr(), AutofillTickClock::NowTicks(), GetTestRequestOptions(kTestChallenge, kTestRelyingPartyId, kTestCredentialId)); EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::AUTHENTICATION_FLOW, @@ -410,31 +429,45 @@ TEST_F(CreditCardFIDOAuthenticatorTest, AuthenticateCard_Success) { TEST_F(CreditCardFIDOAuthenticatorTest, OptIn_PaymentsResponseError) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardAuthentication); + base::HistogramTester histogram_tester; + std::string histogram_name = + "Autofill.BetterAuth.OptInCalled.FromCheckoutFlow"; + EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); - fido_authenticator_->Register(); - EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITHOUT_CHALLENGE_FLOW, + fido_authenticator_->Register(kTestAuthToken); + EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_FETCH_CHALLENGE_FLOW, fido_authenticator_->current_flow()); // Mock payments response. OptChange(AutofillClient::PaymentsRpcResult::NETWORK_ERROR, /*user_is_opted_in=*/false); EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); + histogram_tester.ExpectUniqueSample( + histogram_name, + AutofillMetrics::WebauthnOptInParameters::kFetchingChallenge, 1); } TEST_F(CreditCardFIDOAuthenticatorTest, OptIn_Success) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardAuthentication); + base::HistogramTester histogram_tester; + std::string histogram_name = + "Autofill.BetterAuth.OptInCalled.FromCheckoutFlow"; + EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); - fido_authenticator_->Register(); - EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITHOUT_CHALLENGE_FLOW, + fido_authenticator_->Register(kTestAuthToken); + EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_FETCH_CHALLENGE_FLOW, fido_authenticator_->current_flow()); // Mock payments response. OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, /*user_is_opted_in=*/true); EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); + histogram_tester.ExpectUniqueSample( + histogram_name, + AutofillMetrics::WebauthnOptInParameters::kFetchingChallenge, 1); } TEST_F(CreditCardFIDOAuthenticatorTest, Register_BadCreationOptions) { @@ -443,6 +476,7 @@ TEST_F(CreditCardFIDOAuthenticatorTest, Register_BadCreationOptions) { EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); fido_authenticator_->Register( + kTestAuthToken, GetTestCreationOptions(/*challenge=*/"", kTestRelyingPartyId)); EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); @@ -454,6 +488,7 @@ TEST_F(CreditCardFIDOAuthenticatorTest, Register_UserResponseFailure) { EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); fido_authenticator_->Register( + kTestAuthToken, GetTestCreationOptions(kTestChallenge, kTestRelyingPartyId)); EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITH_CHALLENGE_FLOW, fido_authenticator_->current_flow()); @@ -467,9 +502,14 @@ TEST_F(CreditCardFIDOAuthenticatorTest, Register_UserResponseFailure) { TEST_F(CreditCardFIDOAuthenticatorTest, Register_Success) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardAuthentication); + base::HistogramTester histogram_tester; + std::string histogram_name = + "Autofill.BetterAuth.OptInCalled.FromCheckoutFlow"; + EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); fido_authenticator_->Register( + kTestAuthToken, GetTestCreationOptions(kTestChallenge, kTestRelyingPartyId)); EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITH_CHALLENGE_FLOW, fido_authenticator_->current_flow()); @@ -480,22 +520,29 @@ TEST_F(CreditCardFIDOAuthenticatorTest, Register_Success) { OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, /*user_is_opted_in=*/true); EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); + + histogram_tester.ExpectUniqueSample( + histogram_name, + AutofillMetrics::WebauthnOptInParameters::kWithCreationChallenge, 1); } TEST_F(CreditCardFIDOAuthenticatorTest, Register_EnrollAttemptReturnsCreationOptions) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardAuthentication); + base::HistogramTester histogram_tester; + std::string histogram_name = + "Autofill.BetterAuth.OptInCalled.FromCheckoutFlow"; + EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); - fido_authenticator_->Register(); - EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITHOUT_CHALLENGE_FLOW, + fido_authenticator_->Register(kTestAuthToken); + EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_FETCH_CHALLENGE_FLOW, fido_authenticator_->current_flow()); // Mock payments response with challenge to invoke enrollment flow. OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, - /*user_is_opted_in=*/false, - GetTestCreationOptions(kTestChallenge, kTestRelyingPartyId)); + /*user_is_opted_in=*/false, /*include_creation_options=*/true); EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITH_CHALLENGE_FLOW, fido_authenticator_->current_flow()); EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); @@ -506,11 +553,67 @@ TEST_F(CreditCardFIDOAuthenticatorTest, OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, /*user_is_opted_in=*/true); EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); + + histogram_tester.ExpectTotalCount(histogram_name, 2); + histogram_tester.ExpectBucketCount( + histogram_name, + AutofillMetrics::WebauthnOptInParameters::kFetchingChallenge, 1); + histogram_tester.ExpectBucketCount( + histogram_name, + AutofillMetrics::WebauthnOptInParameters::kWithCreationChallenge, 1); +} + +TEST_F(CreditCardFIDOAuthenticatorTest, + Register_OptInAttemptReturnsRequestOptions) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillCreditCardAuthentication); + EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); + + fido_authenticator_->Register(kTestAuthToken); + EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_FETCH_CHALLENGE_FLOW, + fido_authenticator_->current_flow()); + + // Mock payments response with challenge to invoke opt-in flow. + OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, + /*user_is_opted_in=*/false, /*include_creation_options=*/false, + /*include_request_options=*/true); + EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITH_CHALLENGE_FLOW, + fido_authenticator_->current_flow()); + EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); + + // Mock user response and second payments response. + TestCreditCardFIDOAuthenticator::GetAssertion(fido_authenticator_.get(), + /*did_succeed=*/true); + OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, + /*user_is_opted_in=*/true); + EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); +} + +TEST_F(CreditCardFIDOAuthenticatorTest, Register_NewCardAuthorization) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillCreditCardAuthentication); + ::autofill::prefs::SetCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs(), + true); + EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); + + fido_authenticator_->Authorize( + kTestAuthToken, GetTestRequestOptions(kTestChallenge, kTestRelyingPartyId, + kTestCredentialId)); + EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::FOLLOWUP_AFTER_CVC_AUTH_FLOW, + fido_authenticator_->current_flow()); + + // Mock user response and second payments response. + TestCreditCardFIDOAuthenticator::GetAssertion(fido_authenticator_.get(), + /*did_succeed=*/true); + OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, + /*user_is_opted_in=*/true); + EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); } TEST_F(CreditCardFIDOAuthenticatorTest, OptOut_Success) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardAuthentication); + base::HistogramTester histogram_tester; ::autofill::prefs::SetCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs(), true); @@ -524,6 +627,8 @@ TEST_F(CreditCardFIDOAuthenticatorTest, OptOut_Success) { OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, /*user_is_opted_in=*/false); EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); + histogram_tester.ExpectTotalCount( + "Autofill.BetterAuth.OptOutCalled.FromSettingsPage", 1); } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc index 05b70b7d8dc..111a45e9567 100644 --- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc +++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc @@ -41,7 +41,9 @@ #include "components/autofill/core/common/autofill_constants.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_util.h" +#include "components/prefs/pref_service.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "url/gurl.h" @@ -311,6 +313,11 @@ void CreditCardSaveManager::OnDidUploadCard( // removed. GetCreditCardSaveStrikeDatabase()->ClearStrikes( base::UTF16ToUTF8(upload_request_.card.LastFourDigits())); + + // After a card is successfully saved to server, notifies the + // |personal_data_manager_|. PDM uses this information to update the avatar + // button UI. + personal_data_manager_->OnCreditCardSaved(/*is_local_card=*/false); } else if (show_save_prompt_.has_value() && show_save_prompt_.value()) { // If the upload failed and the bubble was actually shown (NOT just the // icon), count that as a strike against offering upload in the future. @@ -322,6 +329,9 @@ void CreditCardSaveManager::OnDidUploadCard( // Show credit card upload feedback. client_->CreditCardUploadCompleted(result == AutofillClient::SUCCESS); + + if (observer_for_testing_) + observer_for_testing_->OnShowCardSavedFeedback(); } CreditCardSaveStrikeDatabase* @@ -352,6 +362,23 @@ void CreditCardSaveManager::OnDidGetUploadDetails( if (observer_for_testing_) observer_for_testing_->OnReceivedGetUploadDetailsResponse(); if (result == AutofillClient::SUCCESS) { + LegalMessageLine::Parse(*legal_message, &legal_message_lines_, + /*escape_apostrophes=*/true); + + if (legal_message_lines_.empty()) { + // Parsing legal messages failed, so upload should not be offered. + // Offer local card save if card is not already saved locally. + if (!uploading_local_card_) { + AttemptToOfferCardLocalSave(from_dynamic_change_form_, + has_non_focusable_field_, + upload_request_.card); + } + upload_decision_metrics_ |= + AutofillMetrics::UPLOAD_NOT_OFFERED_INVALID_LEGAL_MESSAGE; + LogCardUploadDecisions(upload_decision_metrics_); + return; + } + // Do *not* call payments_client_->Prepare() here. We shouldn't send // credentials until the user has explicitly accepted a prompt to upload. if (!supported_card_bin_ranges.empty() && @@ -369,7 +396,6 @@ void CreditCardSaveManager::OnDidGetUploadDetails( return; } upload_request_.context_token = context_token; - legal_message_ = base::DictionaryValue::From(std::move(legal_message)); OfferCardUploadSave(); } else { // If the upload details request failed and we *know* we have all possible @@ -449,7 +475,7 @@ void CreditCardSaveManager::OfferCardUploadSave() { if (!is_mobile_build || show_save_prompt_.value_or(true)) { user_did_accept_upload_prompt_ = false; client_->ConfirmSaveCreditCardToCloud( - upload_request_.card, std::move(legal_message_), + upload_request_.card, legal_message_lines_, AutofillClient::SaveCreditCardOptions() .with_from_dynamic_change_form(from_dynamic_change_form_) .with_has_non_focusable_field(has_non_focusable_field_) @@ -750,25 +776,27 @@ void CreditCardSaveManager::OnUserDidDecideOnUploadSave( const AutofillClient::UserProvidedCardDetails& user_provided_card_details) { switch (user_decision) { case AutofillClient::ACCEPTED: -// On Android, requesting cardholder name or expiration date is a two step -// flow. -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_IOS) + // On Android and iOS, requesting cardholder name is a two step flow. if (should_request_name_from_user_) { client_->ConfirmAccountNameFixFlow(base::BindOnce( &CreditCardSaveManager::OnUserDidAcceptAccountNameFixFlow, weak_ptr_factory_.GetWeakPtr())); +#if defined(OS_ANDROID) + // On Android, requesting expiration date is a two step flow. } else if (should_request_expiration_date_from_user_) { client_->ConfirmExpirationDateFixFlow( upload_request_.card, base::BindOnce( &CreditCardSaveManager::OnUserDidAcceptExpirationDateFixFlow, weak_ptr_factory_.GetWeakPtr())); +#endif // defined(OS_ANDROID) } else { OnUserDidAcceptUploadHelper(user_provided_card_details); } #else OnUserDidAcceptUploadHelper(user_provided_card_details); -#endif +#endif // defined(OS_ANDROID) || defined(OS_IOS) break; case AutofillClient::DECLINED: @@ -780,7 +808,7 @@ void CreditCardSaveManager::OnUserDidDecideOnUploadSave( personal_data_manager_->OnUserAcceptedUpstreamOffer(); } -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_IOS) void CreditCardSaveManager::OnUserDidAcceptAccountNameFixFlow( const base::string16& cardholder_name) { DCHECK(should_request_name_from_user_); @@ -789,7 +817,9 @@ void CreditCardSaveManager::OnUserDidAcceptAccountNameFixFlow( /*expiration_date_month=*/base::string16(), /*expiration_date_year=*/base::string16()}); } +#endif +#if defined(OS_ANDROID) void CreditCardSaveManager::OnUserDidAcceptExpirationDateFixFlow( const base::string16& month, const base::string16& year) { diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h index 0fe7b67101f..941d7c0f7ba 100644 --- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h +++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h @@ -19,11 +19,14 @@ #include "components/autofill/core/browser/data_model/credit_card.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/payments/credit_card_save_strike_database.h" +#include "components/autofill/core/browser/payments/legal_message_line.h" #include "components/autofill/core/browser/payments/local_card_migration_strike_database.h" #include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "url/origin.h" +class SaveCardOfferObserver; + namespace autofill { // Manages logic for determining whether upload credit card save to Google @@ -79,12 +82,14 @@ class CreditCardSaveManager { // particular actions occur. class ObserverForTest { public: - virtual void OnOfferLocalSave() = 0; - virtual void OnDecideToRequestUploadSave() = 0; - virtual void OnReceivedGetUploadDetailsResponse() = 0; - virtual void OnSentUploadCardRequest() = 0; - virtual void OnReceivedUploadCardResponse() = 0; - virtual void OnStrikeChangeComplete() = 0; + virtual ~ObserverForTest() {} + virtual void OnOfferLocalSave() {} + virtual void OnDecideToRequestUploadSave() {} + virtual void OnReceivedGetUploadDetailsResponse() {} + virtual void OnSentUploadCardRequest() {} + virtual void OnReceivedUploadCardResponse() {} + virtual void OnShowCardSavedFeedback() {} + virtual void OnStrikeChangeComplete() {} }; // The parameters should outlive the CreditCardSaveManager. @@ -138,10 +143,14 @@ class CreditCardSaveManager { friend class TestCreditCardSaveManager; friend class SaveCardBubbleViewsFullFormBrowserTest; friend class SaveCardInfobarEGTestHelper; + friend class ::SaveCardOfferObserver; + FRIEND_TEST_ALL_PREFIXES( + SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, + StrikeDatabase_Upload_FullFlowTest); FRIEND_TEST_ALL_PREFIXES(SaveCardBubbleViewsFullFormBrowserTest, StrikeDatabase_Local_FullFlowTest); - FRIEND_TEST_ALL_PREFIXES(SaveCardBubbleViewsFullFormBrowserTest, - StrikeDatabase_Upload_FullFlowTest); + FRIEND_TEST_ALL_PREFIXES(SaveCardBubbleViewsFullFormBrowserTestForStatusChip, + Feedback_CardSavingAnimation); // Returns the CreditCardSaveStrikeDatabase for |client_|. CreditCardSaveStrikeDatabase* GetCreditCardSaveStrikeDatabase(); @@ -210,12 +219,14 @@ class CreditCardSaveManager { const AutofillClient::UserProvidedCardDetails& user_provided_card_details); -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_IOS) // Upload the card details with the user provided cardholder_name. // Only relevant for mobile as fix flow is two steps on mobile compared to // one step on desktop. void OnUserDidAcceptAccountNameFixFlow(const base::string16& cardholder_name); +#endif // defined(OS_ANDROID) || defined(OS_IOS) +#if defined(OS_ANDROID) // Upload the card details with the user provided expiration date month and // year. Only relevant for mobile as fix flow is two steps on mobile compared // to one step on desktop. @@ -332,8 +343,8 @@ class CreditCardSaveManager { // The origin of the top level frame from which a form is uploaded. url::Origin pending_upload_request_origin_; - // The returned legal message from a GetUploadDetails call to Google Payments. - std::unique_ptr<base::DictionaryValue> legal_message_; + // The parsed lines from the legal message returned from GetUploadDetails. + LegalMessageLines legal_message_lines_; std::unique_ptr<CreditCardSaveStrikeDatabase> credit_card_save_strike_database_; diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc index 721fab518e0..bf87aceff4b 100644 --- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc @@ -17,6 +17,7 @@ #include "base/guid.h" #include "base/metrics/metrics_hashes.h" #include "base/strings/string16.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" @@ -75,18 +76,6 @@ using UkmDeveloperEngagementType = ukm::builders::Autofill_DeveloperEngagement; const base::Time kArbitraryTime = base::Time::FromDoubleT(25); const base::Time kMuchLaterTime = base::Time::FromDoubleT(5000); -std::string NextYear() { - base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); - return std::to_string(now.year + 1); -} - -std::string NextMonth() { - base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); - return std::to_string(now.month % 12 + 1); -} - // Used to configure form for |CreateTestCreditCardFormData|. struct CreditCardFormOptions { CreditCardFormOptions& with_is_https(bool b) { @@ -281,8 +270,8 @@ class CreditCardSaveManagerTest : public testing::Test { // Edit the data, and submit. form.fields[1].value = ASCIIToUTF16("4111111111111111"); - form.fields[2].value = ASCIIToUTF16(NextMonth()); - form.fields[3].value = ASCIIToUTF16(NextYear()); + form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + form.fields[3].value = ASCIIToUTF16(test::NextYear()); FormSubmitted(form); EXPECT_TRUE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); } @@ -426,8 +415,8 @@ TEST_F(CreditCardSaveManagerTest, MAYBE_CreditCardSavedWhenAutocompleteOff) { // Edit the data, and submit. form.fields[1].value = ASCIIToUTF16("4111111111111111"); - form.fields[2].value = ASCIIToUTF16(NextMonth()); - form.fields[3].value = ASCIIToUTF16(NextYear()); + form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + form.fields[3].value = ASCIIToUTF16(test::NextYear()); FormSubmitted(form); EXPECT_TRUE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); } @@ -445,8 +434,8 @@ TEST_F(CreditCardSaveManagerTest, InvalidCreditCardNumberIsNotSaved) { std::string card("4408041234567890"); ASSERT_FALSE(autofill::IsValidCreditCardNumber(ASCIIToUTF16(card))); form.fields[1].value = ASCIIToUTF16(card); - form.fields[2].value = ASCIIToUTF16(NextMonth()); - form.fields[3].value = ASCIIToUTF16(NextYear()); + form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + form.fields[3].value = ASCIIToUTF16(test::NextYear()); FormSubmitted(form); EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); } @@ -470,8 +459,8 @@ TEST_F(CreditCardSaveManagerTest, CreditCardDisabledDoesNotSave) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -505,8 +494,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_OnlyCountryInAddresses) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -570,8 +559,8 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_FirstAndLastName) { credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -636,8 +625,8 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_LastAndFirstName) { credit_card_form.fields[0].value = ASCIIToUTF16("Master"); credit_card_form.fields[1].value = ASCIIToUTF16("Flo"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -709,8 +698,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_WithNonFocusableField) { credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -755,8 +744,8 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_WithNonFocusableField) { credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -782,8 +771,8 @@ TEST_F(CreditCardSaveManagerTest, credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -815,8 +804,8 @@ TEST_F(CreditCardSaveManagerTest, credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -858,8 +847,8 @@ TEST_F( credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -897,8 +886,8 @@ TEST_F(CreditCardSaveManagerTest, credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -923,8 +912,8 @@ TEST_F(CreditCardSaveManagerTest, credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -951,8 +940,8 @@ TEST_F(CreditCardSaveManagerTest, credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -983,8 +972,8 @@ TEST_F(CreditCardSaveManagerTest, credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -1025,8 +1014,8 @@ TEST_F( credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -1063,8 +1052,8 @@ TEST_F(CreditCardSaveManagerTest, credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -1090,8 +1079,8 @@ TEST_F(CreditCardSaveManagerTest, SaveCreditCardOptions_WithoutDynamicForms) { credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -1125,8 +1114,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FirstAndLastName) { credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -1199,8 +1188,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_LastAndFirstName) { credit_card_form.fields[0].value = ASCIIToUTF16("Master"); credit_card_form.fields[1].value = ASCIIToUTF16("Flo"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -1251,8 +1240,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCardAndSaveCopy) { const char* const card_number = "4111111111111111"; credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16(card_number); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -1268,8 +1257,12 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCardAndSaveCopy) { EXPECT_EQ(CreditCard::OK, saved_card->GetServerStatus()); EXPECT_EQ(base::ASCIIToUTF16("1111"), saved_card->LastFourDigits()); EXPECT_EQ(kVisaCard, saved_card->network()); - EXPECT_EQ(std::stoi(NextMonth()), saved_card->expiration_month()); - EXPECT_EQ(std::stoi(NextYear()), saved_card->expiration_year()); + int month; + EXPECT_TRUE(base::StringToInt(test::NextMonth(), &month)); + EXPECT_EQ(month, saved_card->expiration_month()); + int year; + EXPECT_TRUE(base::StringToInt(test::NextYear(), &year)); + EXPECT_EQ(year, saved_card->expiration_year()); EXPECT_EQ(server_id, saved_card->server_id()); EXPECT_EQ(CreditCard::FULL_SERVER_CARD, saved_card->record_type()); EXPECT_EQ(base::ASCIIToUTF16(card_number), saved_card->number()); @@ -1305,8 +1298,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_DisableLocalSave) { const char* const card_number = "4111111111111111"; credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16(card_number); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -1335,8 +1328,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FeatureNotEnabled) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -1370,8 +1363,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcUnavailable) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // CVC MISSING base::HistogramTester histogram_tester; @@ -1408,8 +1401,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcInvalidLength) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("1234"); base::HistogramTester histogram_tester; @@ -1465,8 +1458,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MultipleCvcFields) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // CVC MISSING credit_card_form.fields[5].value = ASCIIToUTF16("123"); @@ -1516,8 +1509,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); base::HistogramTester histogram_tester; @@ -1571,8 +1564,8 @@ TEST_F(CreditCardSaveManagerTest, // Enter an invalid cvc in "Random Field" and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("1234"); base::HistogramTester histogram_tester; @@ -1627,8 +1620,8 @@ TEST_F(CreditCardSaveManagerTest, // Enter a valid cvc in "Random Field" and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -1685,8 +1678,8 @@ TEST_F(CreditCardSaveManagerTest, // Enter a valid cvc in "Random Field" and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -1717,8 +1710,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoProfileAvailable) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Bob Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -1763,8 +1756,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoRecentlyUsedProfile) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -1798,8 +1791,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // CVC MISSING base::HistogramTester histogram_tester; @@ -1839,8 +1832,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoNameAvailable) { // Edit the data, but don't include a name, and submit. credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -1878,8 +1871,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, but don't include a name, and submit. credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -1936,8 +1929,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesConflict) { // Edit the data and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -1984,8 +1977,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2031,8 +2024,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesHavePrefixMatch) { // Edit the data and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2073,8 +2066,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoZipCodeAvailable) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2118,8 +2111,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasMiddleInitial) { // submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo W. Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2157,8 +2150,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoMiddleInitialInCCForm) { // Edit the data, but do not use middle initial. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2192,8 +2185,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the name by adding a middle name. credit_card_form.fields[0].value = ASCIIToUTF16("John Quincy Adams"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2236,8 +2229,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasAddressMiddleName) { // Edit the name by removing middle name. credit_card_form.fields[0].value = ASCIIToUTF16("John Adams"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2289,8 +2282,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NamesCanMismatch) { // Edit the data, but use yet another name, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Bob Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2346,8 +2339,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_IgnoreOldProfiles) { // Edit the data, but use yet another name, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Master Blaster"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2386,8 +2379,8 @@ TEST_F( // Edit the data, but don't include a name, and submit. credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2429,8 +2422,8 @@ TEST_F( // Edit the data, but include a conflicting name, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Jane Doe"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2468,8 +2461,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2504,8 +2497,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2538,8 +2531,8 @@ TEST_F( // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2584,8 +2577,8 @@ TEST_F( // Edit the data, but don't include a name, and submit. credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2632,8 +2625,8 @@ TEST_F( // Edit the data, but include a conflicting name, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Jane Doe"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2675,8 +2668,8 @@ TEST_F( // Edit the data, but don't include a name, and submit. credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2718,8 +2711,8 @@ TEST_F( // Edit the data, but include a conflicting name, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Jane Doe"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -2763,8 +2756,8 @@ TEST_F( // Edit the data, but don't include a name, and submit. credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); // With the offer-to-save decision deferred to Google Payments, Payments can @@ -2832,8 +2825,8 @@ TEST_F( // Edit the data, include a expiration date, and submit this time. credit_card_form.fields[0].value = ASCIIToUTF16("Jane Doe"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -3053,7 +3046,7 @@ TEST_F(CreditCardSaveManagerTest, credit_card_form.fields[0].value = ASCIIToUTF16("John Smith"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); credit_card_form.fields[2].value = ASCIIToUTF16(""); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -3095,7 +3088,7 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("John Smith"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); credit_card_form.fields[3].value = ASCIIToUTF16(""); credit_card_form.fields[4].value = ASCIIToUTF16("123"); @@ -3226,8 +3219,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -3269,8 +3262,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadDetailsFails) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -3302,7 +3295,8 @@ TEST_F(CreditCardSaveManagerTest, DuplicateMaskedCreditCard_NoUpload) { // enter below. CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123"); test::SetCreditCardInfo(&credit_card, "Flo Master", "1111", - NextMonth().c_str(), NextYear().c_str(), "1"); + test::NextMonth().c_str(), test::NextYear().c_str(), + "1"); credit_card.SetNetworkForMaskedCard(kVisaCard); personal_data_.AddServerCreditCard(credit_card); @@ -3314,8 +3308,8 @@ TEST_F(CreditCardSaveManagerTest, DuplicateMaskedCreditCard_NoUpload) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); // Local save prompt should not be shown as there is alredy masked @@ -3334,8 +3328,8 @@ TEST_F(CreditCardSaveManagerTest, NothingIfNothingFound) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name set credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and check what detected_values for an upload save would be. @@ -3364,8 +3358,8 @@ TEST_F(CreditCardSaveManagerTest, DetectCvc) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name set credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); // Submit the form and ensure the detected_values for an upload save contained @@ -3386,8 +3380,8 @@ TEST_F(CreditCardSaveManagerTest, DetectCardholderName) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("John Smith"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and ensure the detected_values for an upload save contained @@ -3415,8 +3409,8 @@ TEST_F(CreditCardSaveManagerTest, DetectAddressName) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name set credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and ensure the detected_values for an upload save contained @@ -3444,8 +3438,8 @@ TEST_F(CreditCardSaveManagerTest, DetectCardholderAndAddressNameIfMatching) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("John Smith"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and ensure the detected_values for an upload save contained @@ -3474,8 +3468,8 @@ TEST_F(CreditCardSaveManagerTest, DetectNoUniqueNameIfNamesConflict) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Miles Prower"); // Conflict! credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and check what detected_values for an upload save would be. @@ -3502,8 +3496,8 @@ TEST_F(CreditCardSaveManagerTest, DetectPostalCode) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name set credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and ensure the detected_values for an upload save contained @@ -3535,8 +3529,8 @@ TEST_F(CreditCardSaveManagerTest, DetectNoUniquePostalCodeIfZipsConflict) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name set credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and check what detected_values for an upload save would be. @@ -3560,8 +3554,8 @@ TEST_F(CreditCardSaveManagerTest, DetectAddressLine) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name set credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and ensure the detected_values for an upload save contained @@ -3589,8 +3583,8 @@ TEST_F(CreditCardSaveManagerTest, DetectLocality) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name set credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and ensure the detected_values for an upload save contained @@ -3617,8 +3611,8 @@ TEST_F(CreditCardSaveManagerTest, DetectAdministrativeArea) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name set credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and ensure the detected_values for an upload save contained @@ -3646,8 +3640,8 @@ TEST_F(CreditCardSaveManagerTest, DetectCountryCode) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name set credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and ensure the detected_values for an upload save contained @@ -3674,8 +3668,8 @@ TEST_F(CreditCardSaveManagerTest, DetectHasGooglePaymentAccount) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name set credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and ensure the detected_values for an upload save contained @@ -3708,8 +3702,8 @@ TEST_F(CreditCardSaveManagerTest, DetectEverythingAtOnce) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("John Smith"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); // Submit the form and ensure the detected_values for an upload save contained @@ -3747,8 +3741,8 @@ TEST_F(CreditCardSaveManagerTest, DetectSubsetOfPossibleFields) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Miles Prower"); // Conflict! credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); // Submit the form and ensure the detected_values for an upload save contained @@ -3795,8 +3789,8 @@ TEST_F(CreditCardSaveManagerTest, DetectAddressComponentsAcrossProfiles) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name set credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set // Submit the form and ensure the detected_values for an upload save contained @@ -3835,8 +3829,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name! credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC! base::HistogramTester histogram_tester; @@ -3895,8 +3889,8 @@ TEST_F( // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("John Smith"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -3938,8 +3932,8 @@ TEST_F( credit_card_form.fields[0].value = ASCIIToUTF16("John"); credit_card_form.fields[1].value = ASCIIToUTF16("Smith"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -3983,8 +3977,8 @@ TEST_F( // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name! credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC! base::HistogramTester histogram_tester; @@ -4014,8 +4008,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC! base::HistogramTester histogram_tester; @@ -4057,8 +4051,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name! credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4106,8 +4100,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Miles Prower"); // Conflict! credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4157,8 +4151,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4213,8 +4207,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4256,8 +4250,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name! credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC! base::HistogramTester histogram_tester; @@ -4297,7 +4291,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfLocalCard) { // enter below. CreditCard local_card; test::SetCreditCardInfo(&local_card, "Flo Master", "4111111111111111", - NextMonth().c_str(), NextYear().c_str(), "1"); + test::NextMonth().c_str(), test::NextYear().c_str(), + "1"); local_card.set_record_type(CreditCard::LOCAL_CARD); personal_data_.AddCreditCard(local_card); @@ -4320,8 +4315,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfLocalCard) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4360,8 +4355,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfNewCard) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4392,7 +4387,8 @@ TEST_F(CreditCardSaveManagerTest, // enter below. CreditCard local_card; test::SetCreditCardInfo(&local_card, "Flo Master", "4111111111111111", - NextMonth().c_str(), NextYear().c_str(), "1"); + test::NextMonth().c_str(), test::NextYear().c_str(), + "1"); local_card.set_record_type(CreditCard::LOCAL_CARD); personal_data_.AddCreditCard(local_card); @@ -4415,8 +4411,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4450,8 +4446,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); // Confirm that upload happened and that no experiment flag state was sent in @@ -4480,8 +4476,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); // Confirm that the preflight request contained @@ -4509,8 +4505,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); // Confirm that the preflight request contained the correct UploadCardSource. @@ -4540,8 +4536,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4589,8 +4585,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4631,8 +4627,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4678,8 +4674,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesDisallowsSave) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4725,8 +4721,8 @@ TEST_F(CreditCardSaveManagerTest, // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4776,8 +4772,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesStillAllowsSave) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4817,8 +4813,8 @@ TEST_F(CreditCardSaveManagerTest, LocallySaveCreditCard_ClearStrikesOnAdd) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -4858,8 +4854,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ClearStrikesOnAdd) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); FormSubmitted(credit_card_form); @@ -4891,8 +4887,8 @@ TEST_F(CreditCardSaveManagerTest, LocallySaveCreditCard_NumStrikesLoggedOnAdd) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -4936,8 +4932,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NumStrikesLoggedOnAdd) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -5018,8 +5014,8 @@ TEST_F(CreditCardSaveManagerTest, credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -5069,8 +5065,8 @@ TEST_F(CreditCardSaveManagerTest, credit_card_form.fields[0].value = ASCIIToUTF16("Flo"); credit_card_form.fields[1].value = ASCIIToUTF16("Master"); credit_card_form.fields[2].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[4].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[5].value = ASCIIToUTF16("123"); base::HistogramTester histogram_tester; @@ -5098,8 +5094,8 @@ TEST_F(CreditCardSaveManagerTest, UploadSaveNotOfferedForUnsupportedCard) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("5454545454545454"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); // Since card isn't in any of the supported ranges, local save should be @@ -5125,15 +5121,16 @@ TEST_F(CreditCardSaveManagerTest, LocalSaveNotOfferedForSavedUnsupportedCard) { // enter below. CreditCard local_card; test::SetCreditCardInfo(&local_card, "Flo Master", "5454545454545454", - NextMonth().c_str(), NextYear().c_str(), "1"); + test::NextMonth().c_str(), test::NextYear().c_str(), + "1"); local_card.set_record_type(CreditCard::LOCAL_CARD); personal_data_.AddCreditCard(local_card); // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("5454545454545454"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); // Since card is already saved, local save should not be offered. @@ -5157,8 +5154,8 @@ TEST_F(CreditCardSaveManagerTest, UploadSaveOfferedForSupportedCard) { // Edit the data, and submit. credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); credit_card_form.fields[4].value = ASCIIToUTF16("123"); // Since card is in one of the supported ranges(4111-4113), upload save should @@ -5168,4 +5165,40 @@ TEST_F(CreditCardSaveManagerTest, UploadSaveOfferedForSupportedCard) { EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded()); } +// Tests that if payment client returns an invalid legal message upload should +// not be offered. +TEST_F(CreditCardSaveManagerTest, InvalidLegalMessageInOnDidGetUploadDetails) { + payments_client_->SetUseInvalidLegalMessageInGetUploadDetails(true); + + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, CreditCardFormOptions()); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + const char* const card_number = "4111111111111111"; + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16(card_number); + credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + FormSubmitted(credit_card_form); + + // Verify that the correct histogram entries were logged. + ExpectCardUploadDecision( + histogram_tester, + AutofillMetrics::UPLOAD_NOT_OFFERED_INVALID_LEGAL_MESSAGE); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.cc b/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.cc new file mode 100644 index 00000000000..2a1125b55b0 --- /dev/null +++ b/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.cc @@ -0,0 +1,42 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/payments/fido_authentication_strike_database.h" + +#include "components/autofill/core/browser/proto/strike_data.pb.h" + +namespace autofill { + +const int + FidoAuthenticationStrikeDatabase::kStrikesToAddWhenOptInOfferDeclined = 1; +const int FidoAuthenticationStrikeDatabase:: + kStrikesToAddWhenUserVerificationFailsOnOptInAttempt = 2; +const int FidoAuthenticationStrikeDatabase::kStrikesToAddWhenUserOptsOut = 3; + +FidoAuthenticationStrikeDatabase::FidoAuthenticationStrikeDatabase( + StrikeDatabase* strike_database) + : StrikeDatabaseIntegratorBase(strike_database) { + RemoveExpiredStrikes(); +} + +FidoAuthenticationStrikeDatabase::~FidoAuthenticationStrikeDatabase() {} + +std::string FidoAuthenticationStrikeDatabase::GetProjectPrefix() { + return "FidoAuthentication"; +} + +int FidoAuthenticationStrikeDatabase::GetMaxStrikesLimit() { + return 3; +} + +long long FidoAuthenticationStrikeDatabase::GetExpiryTimeMicros() { + // Expiry time is six months. + return 1000000LL * 60 * 60 * 24 * 30 * 6; +} + +bool FidoAuthenticationStrikeDatabase::UniqueIdsRequired() { + return false; +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.h b/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.h new file mode 100644 index 00000000000..f06f9fc5ebe --- /dev/null +++ b/chromium/components/autofill/core/browser/payments/fido_authentication_strike_database.h @@ -0,0 +1,38 @@ +// 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_FIDO_AUTHENTICATION_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_FIDO_AUTHENTICATION_STRIKE_DATABASE_H_ + +#include <string> + +#include "components/autofill/core/browser/payments/strike_database.h" +#include "components/autofill/core/browser/payments/strike_database_integrator_base.h" + +namespace autofill { + +// Implementation of StrikeDatabaseIntegratorBase for offering FIDO +// authentication for card unmasking. +class FidoAuthenticationStrikeDatabase : public StrikeDatabaseIntegratorBase { + public: + FidoAuthenticationStrikeDatabase(StrikeDatabase* strike_database); + ~FidoAuthenticationStrikeDatabase() override; + + // Strikes to add when user declines opt-in offer. + static const int kStrikesToAddWhenOptInOfferDeclined; + // Strikes to add when user fails to complete user-verification for an opt-in + // attempt. + static const int kStrikesToAddWhenUserVerificationFailsOnOptInAttempt; + // Strikes to add when user opts-out from settings page. + static const int kStrikesToAddWhenUserOptsOut; + + std::string GetProjectPrefix() override; + int GetMaxStrikesLimit() override; + long long GetExpiryTimeMicros() override; + bool UniqueIdsRequired() override; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_FIDO_AUTHENTICATION_STRIKE_DATABASE_H_ diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.cc b/chromium/components/autofill/core/browser/payments/full_card_request.cc index 2d8be66ebc5..2c87a60b6df 100644 --- a/chromium/components/autofill/core/browser/payments/full_card_request.cc +++ b/chromium/components/autofill/core/browser/payments/full_card_request.cc @@ -13,6 +13,8 @@ #include "components/autofill/core/browser/payments/payments_util.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_payments_features.h" +#include "components/autofill/core/common/autofill_tick_clock.h" namespace autofill { namespace payments { @@ -110,10 +112,6 @@ void FullCardRequest::GetFullCard(const CreditCard& card, } } -bool FullCardRequest::IsGettingFullCard() const { - return !!request_; -} - void FullCardRequest::OnUnmaskPromptAccepted( const UserProvidedUnmaskDetails& user_response) { if (!user_response.exp_month.empty()) @@ -155,12 +153,13 @@ void FullCardRequest::OnUnmaskPromptClosed() { void FullCardRequest::OnDidGetUnmaskRiskData(const std::string& risk_data) { request_->risk_data = risk_data; if (!request_->user_response.cvc.empty() || - !request_->fido_assertion_info.is_none()) + !request_->fido_assertion_info.is_none()) { SendUnmaskCardRequest(); + } } void FullCardRequest::SendUnmaskCardRequest() { - real_pan_request_timestamp_ = AutofillClock::Now(); + real_pan_request_timestamp_ = AutofillTickClock::NowTicks(); payments_client_->UnmaskCard(*request_, base::BindOnce(&FullCardRequest::OnDidGetRealPan, weak_ptr_factory_.GetWeakPtr())); @@ -169,8 +168,18 @@ void FullCardRequest::SendUnmaskCardRequest() { void FullCardRequest::OnDidGetRealPan( AutofillClient::PaymentsRpcResult result, payments::PaymentsClient::UnmaskResponseDetails& response_details) { - AutofillMetrics::LogRealPanDuration( - AutofillClock::Now() - real_pan_request_timestamp_, result); + // If the CVC field is populated, that means the user performed a CVC check. + // If FIDO AssertionInfo is populated, then the user must have performed FIDO + // authentication. Exactly one of these fields must be populated. + DCHECK_NE(request_->user_response.cvc.empty(), + request_->fido_assertion_info.is_none()); + if (!request_->user_response.cvc.empty()) { + AutofillMetrics::LogRealPanDuration( + AutofillTickClock::NowTicks() - real_pan_request_timestamp_, result); + } else if (!request_->fido_assertion_info.is_none()) { + AutofillMetrics::LogCardUnmaskDurationAfterWebauthn( + AutofillTickClock::NowTicks() - real_pan_request_timestamp_, result); + } if (ui_delegate_) ui_delegate_->OnUnmaskVerificationResult(result); @@ -204,9 +213,16 @@ void FullCardRequest::OnDidGetRealPan( // |response_details_| if |user_response.fido_opt_in| was not set to true // to avoid an unwanted registration prompt. unmask_response_details_ = response_details; + + const base::string16 cvc = + base::FeatureList::IsEnabled( + features::kAutofillAlwaysReturnCloudTokenizedCard) && + !response_details.dcvv.empty() + ? base::UTF8ToUTF16(response_details.dcvv) + : request_->user_response.cvc; if (result_delegate_) - result_delegate_->OnFullCardRequestSucceeded( - *this, request_->card, request_->user_response.cvc); + result_delegate_->OnFullCardRequestSucceeded(*this, request_->card, + cvc); Reset(); break; } diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.h b/chromium/components/autofill/core/browser/payments/full_card_request.h index 9d5338b3c3d..c8608085877 100644 --- a/chromium/components/autofill/core/browser/payments/full_card_request.h +++ b/chromium/components/autofill/core/browser/payments/full_card_request.h @@ -18,6 +18,10 @@ namespace autofill { +class AutofillManagerTest; +class AutofillMetricsTest; +class CreditCardAccessManagerTest; +class CreditCardCVCAuthenticatorTest; class CreditCard; class PersonalDataManager; @@ -85,9 +89,6 @@ class FullCardRequest final : public CardUnmaskDelegate { base::WeakPtr<ResultDelegate> result_delegate, base::Value fido_assertion_info); - // Returns true if there's a pending request to get the full card. - bool IsGettingFullCard() const; - // Called by the payments client when a card has been unmasked. void OnDidGetRealPan( AutofillClient::PaymentsRpcResult result, @@ -103,6 +104,11 @@ class FullCardRequest final : public CardUnmaskDelegate { } private: + friend class autofill::AutofillManagerTest; + friend class autofill::AutofillMetricsTest; + friend class autofill::CreditCardAccessManagerTest; + friend class autofill::CreditCardCVCAuthenticatorTest; + // Retrieves the pan for |card| and invokes // Delegate::OnFullCardRequestSucceeded() or // Delegate::OnFullCardRequestFailed(). Only one request should be active at a @@ -158,7 +164,7 @@ class FullCardRequest final : public CardUnmaskDelegate { // The timestamp when the full PAN was requested from a server. For // histograms. - base::Time real_pan_request_timestamp_; + base::TimeTicks real_pan_request_timestamp_; // The timestamp when the form is parsed. For histograms. base::TimeTicks form_parsed_timestamp_; diff --git a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc index f4fb8e536a2..d57e76c31c4 100644 --- a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc @@ -8,6 +8,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/strings/stringprintf.h" +#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" @@ -18,6 +19,8 @@ #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_personal_data_manager.h" +#include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "net/url_request/url_request_test_util.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" @@ -106,6 +109,17 @@ class FullCardRequestTest : public testing::Test { request_->OnDidGetRealPan(result, response.with_real_pan(real_pan)); } + void OnDidGetRealPanWithDcvv(AutofillClient::PaymentsRpcResult result, + const std::string& real_pan, + const std::string& dcvv) { + payments::PaymentsClient::UnmaskResponseDetails response; + request_->OnDidGetRealPan(result, + response.with_real_pan(real_pan).with_dcvv(dcvv)); + } + + protected: + base::test::ScopedFeatureList scoped_feature_list_; + private: base::test::SingleThreadTaskEnvironment task_environment_; MockPersonalDataManager personal_data_; @@ -159,6 +173,56 @@ TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForMaskedServerCardViaCvc) { card_unmask_delegate()->OnUnmaskPromptClosed(); } +// Verify getting the full PAN and the dCVV for a masked server card when cloud +// tokenization is enabled. +TEST_F(FullCardRequestTest, GetFullCardPanAndDcvvForMaskedServerCardViaDcvv) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillAlwaysReturnCloudTokenizedCard); + EXPECT_CALL(*result_delegate(), + OnFullCardRequestSucceeded( + testing::Ref(*request()), + CardMatches(CreditCard::FULL_SERVER_CARD, "4111"), + base::ASCIIToUTF16("321"))); + EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _)); + EXPECT_CALL(*ui_delegate(), + OnUnmaskVerificationResult(AutofillClient::SUCCESS)); + + request()->GetFullCard( + CreditCard(CreditCard::MASKED_SERVER_CARD, "server_id"), + AutofillClient::UNMASK_FOR_AUTOFILL, result_delegate()->AsWeakPtr(), + ui_delegate()->AsWeakPtr()); + CardUnmaskDelegate::UserProvidedUnmaskDetails details; + details.cvc = base::ASCIIToUTF16("123"); + card_unmask_delegate()->OnUnmaskPromptAccepted(details); + OnDidGetRealPanWithDcvv(AutofillClient::SUCCESS, "4111", "321"); + card_unmask_delegate()->OnUnmaskPromptClosed(); +} + +// Verify getting the full PAN for a masked server card when cloud +// tokenization is enabled but no dCVV is returned. +TEST_F(FullCardRequestTest, GetFullCardPanForMaskedServerCardWithoutDcvv) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillAlwaysReturnCloudTokenizedCard); + EXPECT_CALL(*result_delegate(), + OnFullCardRequestSucceeded( + testing::Ref(*request()), + CardMatches(CreditCard::FULL_SERVER_CARD, "4111"), + base::ASCIIToUTF16("123"))); + EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _)); + EXPECT_CALL(*ui_delegate(), + OnUnmaskVerificationResult(AutofillClient::SUCCESS)); + + request()->GetFullCard( + CreditCard(CreditCard::MASKED_SERVER_CARD, "server_id"), + AutofillClient::UNMASK_FOR_AUTOFILL, result_delegate()->AsWeakPtr(), + ui_delegate()->AsWeakPtr()); + CardUnmaskDelegate::UserProvidedUnmaskDetails details; + details.cvc = base::ASCIIToUTF16("123"); + card_unmask_delegate()->OnUnmaskPromptAccepted(details); + OnDidGetRealPan(AutofillClient::SUCCESS, "4111"); + card_unmask_delegate()->OnUnmaskPromptClosed(); +} + // Verify getting the full PAN for a masked server card. TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForMaskedServerCardViaFido) { EXPECT_CALL(*result_delegate(), @@ -263,7 +327,7 @@ TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForExpiredFullServerCard) { OnUnmaskVerificationResult(AutofillClient::SUCCESS)); base::Time::Exploded today; - base::Time::Now().LocalExplode(&today); + AutofillClock::Now().LocalExplode(&today); CreditCard full_server_card(CreditCard::FULL_SERVER_CARD, "server_id"); test::SetCreditCardInfo(&full_server_card, nullptr, "4111", "12", base::StringPrintf("%d", today.year - 1).c_str(), @@ -493,7 +557,7 @@ TEST_F(FullCardRequestTest, UpdateExpDateForLocalCard) { OnUnmaskVerificationResult(AutofillClient::SUCCESS)); base::Time::Exploded today; - base::Time::Now().LocalExplode(&today); + AutofillClock::Now().LocalExplode(&today); CreditCard card; test::SetCreditCardInfo(&card, nullptr, "4111", "10", base::StringPrintf("%d", today.year - 1).c_str(), @@ -559,74 +623,5 @@ TEST_F(FullCardRequestTest, UnmaskForPaymentRequest) { card_unmask_delegate()->OnUnmaskPromptClosed(); } -// Verify that FullCardRequest::IsGettingFullCard() is true until the server -// returns the full PAN for a masked card. -TEST_F(FullCardRequestTest, IsGettingFullCardForMaskedServerCard) { - EXPECT_CALL(*result_delegate(), - OnFullCardRequestSucceeded( - testing::Ref(*request()), - CardMatches(CreditCard::FULL_SERVER_CARD, "4111"), - base::ASCIIToUTF16("123"))); - EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _)); - EXPECT_CALL(*ui_delegate(), - OnUnmaskVerificationResult(AutofillClient::SUCCESS)); - - EXPECT_FALSE(request()->IsGettingFullCard()); - - request()->GetFullCard( - CreditCard(CreditCard::MASKED_SERVER_CARD, "server_id"), - AutofillClient::UNMASK_FOR_AUTOFILL, result_delegate()->AsWeakPtr(), - ui_delegate()->AsWeakPtr()); - - EXPECT_TRUE(request()->IsGettingFullCard()); - - CardUnmaskDelegate::UserProvidedUnmaskDetails details; - details.cvc = base::ASCIIToUTF16("123"); - card_unmask_delegate()->OnUnmaskPromptAccepted(details); - - EXPECT_TRUE(request()->IsGettingFullCard()); - - OnDidGetRealPan(AutofillClient::SUCCESS, "4111"); - - EXPECT_FALSE(request()->IsGettingFullCard()); - - card_unmask_delegate()->OnUnmaskPromptClosed(); - - EXPECT_FALSE(request()->IsGettingFullCard()); -} - -// Verify that FullCardRequest::IsGettingFullCard() is true until the user types -// in the CVC for a card that is not masked. -TEST_F(FullCardRequestTest, IsGettingFullCardForLocalCard) { - EXPECT_CALL( - *result_delegate(), - OnFullCardRequestSucceeded(testing::Ref(*request()), - CardMatches(CreditCard::LOCAL_CARD, "4111"), - base::ASCIIToUTF16("123"))); - EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _)); - EXPECT_CALL(*ui_delegate(), - OnUnmaskVerificationResult(AutofillClient::SUCCESS)); - - EXPECT_FALSE(request()->IsGettingFullCard()); - - CreditCard card; - test::SetCreditCardInfo(&card, nullptr, "4111", "12", "2050", "1"); - request()->GetFullCard(card, AutofillClient::UNMASK_FOR_AUTOFILL, - result_delegate()->AsWeakPtr(), - ui_delegate()->AsWeakPtr()); - - EXPECT_TRUE(request()->IsGettingFullCard()); - - CardUnmaskDelegate::UserProvidedUnmaskDetails details; - details.cvc = base::ASCIIToUTF16("123"); - card_unmask_delegate()->OnUnmaskPromptAccepted(details); - - EXPECT_FALSE(request()->IsGettingFullCard()); - - card_unmask_delegate()->OnUnmaskPromptClosed(); - - EXPECT_FALSE(request()->IsGettingFullCard()); -} - } // namespace payments } // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/legal_message_line.cc b/chromium/components/autofill/core/browser/payments/legal_message_line.cc index b18bc273c41..34baff793d9 100644 --- a/chromium/components/autofill/core/browser/payments/legal_message_line.cc +++ b/chromium/components/autofill/core/browser/payments/legal_message_line.cc @@ -113,7 +113,7 @@ bool LegalMessageLine::ParseLine(const base::Value& line, const base::Value* template_parameters = line.FindKeyOfType("template_parameter", base::Value::Type::LIST); if (template_parameters) { - const base::Value::ListStorage& template_parameters_storage = + base::span<const base::Value> template_parameters_storage = template_parameters->GetList(); display_texts.reserve(template_parameters_storage.size()); links_.reserve(template_parameters_storage.size()); diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc index f3dae8c54d6..85556ad2c5d 100644 --- a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc +++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc @@ -5,8 +5,8 @@ #include "components/autofill/core/browser/payments/local_card_migration_manager.h" #include <stddef.h> - #include <algorithm> +#include <unordered_map> #include <vector> #include "base/bind.h" @@ -228,9 +228,19 @@ void LocalCardMigrationManager::OnDidGetUploadDetails( observer_for_testing_->OnReceivedGetUploadDetailsResponse(); if (result == AutofillClient::SUCCESS) { + LegalMessageLine::Parse(*legal_message, &legal_message_lines_, + /*escape_apostrophes=*/true); + + if (legal_message_lines_.empty()) { + AutofillMetrics::LogLocalCardMigrationDecisionMetric( + AutofillMetrics::LocalCardMigrationDecisionMetric:: + NOT_OFFERED_INVALID_LEGAL_MESSAGE); + return; + } + migration_request_.context_token = context_token; - legal_message_ = base::DictionaryValue::From(std::move(legal_message)); migration_request_.risk_data.clear(); + // If we successfully received the legal docs, trigger the offer-to-migrate // dialog. If triggered from settings page, we pop-up the main prompt // directly. If not, we pop up the intermediate bubble. @@ -274,6 +284,7 @@ void LocalCardMigrationManager::OnDidGetUploadDetails( local_card_migration_origin_, AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN); } + // TODO(crbug.com/876895): Clean up the LoadRiskData Bind/BindRepeating // usages client_->LoadRiskData(base::BindRepeating( @@ -330,6 +341,12 @@ void LocalCardMigrationManager::OnDidMigrateLocalCards( NOTREACHED(); } } + + // If at least one card was migrated, notifies the |personal_data_manager_|. + // PDM uses this information to update the avatar button UI. + if (!migrated_cards.empty()) + personal_data_manager_->OnCreditCardSaved(/*is_local_card=*/false); + // Remove cards that were successfully migrated from local storage. personal_data_manager_->DeleteLocalCreditCards(migrated_cards); } @@ -388,7 +405,7 @@ void LocalCardMigrationManager::ShowMainMigrationDialog() { local_card_migration_origin_, AutofillMetrics::MAIN_DIALOG_SHOWN); // Pops up a larger, modal dialog showing the local cards to be uploaded. client_->ConfirmMigrateLocalCardToCloud( - std::move(legal_message_), + legal_message_lines_, personal_data_manager_->GetAccountInfoForPaymentsServer().email, migratable_credit_cards_, base::BindOnce( diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.h b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.h index d717e199bd0..3f2c73c3720 100644 --- a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.h +++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.h @@ -7,12 +7,14 @@ #include <memory> #include <string> +#include <unordered_map> #include <utility> #include <vector> #include "base/strings/string16.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_metrics.h" +#include "components/autofill/core/browser/payments/legal_message_line.h" #include "components/autofill/core/browser/payments/local_card_migration_strike_database.h" #include "components/autofill/core/browser/payments/payments_client.h" @@ -209,7 +211,8 @@ class LocalCardMigrationManager { observer_for_testing_ = observer; } - std::unique_ptr<base::DictionaryValue> legal_message_; + // The parsed lines from the legal message return from GetUploadDetails. + LegalMessageLines legal_message_lines_; std::string app_locale_; diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc index e1441ba421d..2a09894c0e3 100644 --- a/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc @@ -1541,4 +1541,19 @@ TEST_F(LocalCardMigrationManagerTest, AutofillMetrics::LocalCardMigrationDecisionMetric::OFFERED); } +// Tests that if payment client returns an invalid legal message migration +// should not be offered. +TEST_F(LocalCardMigrationManagerTest, + InvalidLegalMessageInOnDidGetUploadDetails) { + payments_client_->SetUseInvalidLegalMessageInGetUploadDetails(true); + + base::HistogramTester histogram_tester; + UseLocalCardWithOtherLocalCardsOnFile(); + + // Verify that the correct histogram entries were logged. + ExpectUniqueLocalCardMigrationDecision( + histogram_tester, AutofillMetrics::LocalCardMigrationDecisionMetric:: + NOT_OFFERED_INVALID_LEGAL_MESSAGE); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/payments_client.cc b/chromium/components/autofill/core/browser/payments/payments_client.cc index b097a05e500..a7e30b9dcd5 100644 --- a/chromium/components/autofill/core/browser/payments/payments_client.cc +++ b/chromium/components/autofill/core/browser/payments/payments_client.cc @@ -56,9 +56,11 @@ const char kUnmaskCardRequestPath[] = const char kUnmaskCardRequestFormat[] = "requestContentType=application/json; charset=utf-8&request=%s" "&s7e_13_cvc=%s"; +const char kUnmaskCardRequestFormatWithoutCvc[] = + "requestContentType=application/json; charset=utf-8&request=%s"; const char kOptChangeRequestPath[] = - "payments/apis/chromepaymentsservice/autofillauthoptchange"; + "payments/apis/chromepaymentsservice/updateautofilluserpreference"; const char kGetUploadDetailsRequestPath[] = "payments/apis/chromepaymentsservice/getdetailsforsavecard"; @@ -142,7 +144,7 @@ void AppendStringIfNotEmpty(const AutofillProfile& profile, base::Value& list) { const base::string16 value = profile.GetInfo(type, app_locale); if (!value.empty()) - list.GetList().emplace_back(value); + list.Append(value); } // Returns a dictionary with the structure expected by Payments RPCs, containing @@ -228,7 +230,7 @@ void SetActiveExperiments(const std::vector<const char*>& active_experiments, base::Value active_chrome_experiments(base::Value::Type::LIST); for (const char* it : active_experiments) - active_chrome_experiments.GetList().emplace_back(it); + active_chrome_experiments.Append(it); request_dict.SetKey("active_chrome_experiments", std::move(active_chrome_experiments)); @@ -295,7 +297,7 @@ class GetUnmaskDetailsRequest : public PaymentsRequest { unmask_details_.fido_request_options = dictionary_value->Clone(); const auto* fido_eligible_card_ids = response.FindKeyOfType( - "fido_eligible_credit_card_id", base::Value::Type::LIST); + "fido_eligible_card_id", base::Value::Type::LIST); if (fido_eligible_card_ids) { for (const base::Value& result : fido_eligible_card_ids->GetList()) { unmask_details_.fido_eligible_card_ids.insert(result.GetString()); @@ -347,9 +349,14 @@ class UnmaskCardRequest : public PaymentsRequest { std::string GetRequestContent() override { base::Value request_dict(base::Value::Type::DICTIONARY); - request_dict.SetKey("encrypted_cvc", base::Value("__param:s7e_13_cvc")); request_dict.SetKey("credit_card_id", base::Value(request_details_.card.server_id())); + if (base::FeatureList::IsEnabled( + features::kAutofillAlwaysReturnCloudTokenizedCard)) { + // See b/140727361. + request_dict.SetKey("instrument_token", + base::Value("INSTRUMENT_TOKEN_FOR_TEST")); + } request_dict.SetKey("risk_data_encoded", BuildRiskDictionary(request_details_.risk_data)); base::Value context(base::Value::Type::DICTIONARY); @@ -380,19 +387,33 @@ class UnmaskCardRequest : public PaymentsRequest { "opt_in_fido_auth", base::Value(request_details_.user_response.enable_fido_auth)); - if (request_details_.fido_assertion_info.is_dict()) { + // Either FIDO assertion info is set or CVC is set, never both. + bool is_cvc_auth = !request_details_.user_response.cvc.empty(); + bool is_fido_auth = request_details_.fido_assertion_info.is_dict(); + + DCHECK_NE(is_cvc_auth, is_fido_auth); + if (is_cvc_auth) { + request_dict.SetKey("encrypted_cvc", base::Value("__param:s7e_13_cvc")); + } else { request_dict.SetKey("fido_assertion_info", std::move(request_details_.fido_assertion_info)); } std::string json_request; base::JSONWriter::Write(request_dict, &json_request); - std::string request_content = base::StringPrintf( - kUnmaskCardRequestFormat, - net::EscapeUrlEncodedData(json_request, true).c_str(), - net::EscapeUrlEncodedData( - base::UTF16ToASCII(request_details_.user_response.cvc), true) - .c_str()); + std::string request_content; + if (is_cvc_auth) { + request_content = base::StringPrintf( + kUnmaskCardRequestFormat, + net::EscapeUrlEncodedData(json_request, true).c_str(), + net::EscapeUrlEncodedData( + base::UTF16ToASCII(request_details_.user_response.cvc), true) + .c_str()); + } else { + request_content = base::StringPrintf( + kUnmaskCardRequestFormatWithoutCvc, + net::EscapeUrlEncodedData(json_request, true).c_str()); + } // Payments is reporting receiving blank or non-standard-length CVCs. // Log CVC length being sent to gauge how often this is happening. @@ -414,10 +435,21 @@ class UnmaskCardRequest : public PaymentsRequest { const auto* pan = response.FindStringKey("pan"); response_details_.real_pan = pan ? *pan : std::string(); + const auto* dcvv = response.FindStringKey("dcvv"); + response_details_.dcvv = dcvv ? *dcvv : std::string(); + const auto* creation_options = response.FindKeyOfType( "fido_creation_options", base::Value::Type::DICTIONARY); if (creation_options) response_details_.fido_creation_options = creation_options->Clone(); + + const auto* request_options = response.FindKeyOfType( + "fido_request_options", base::Value::Type::DICTIONARY); + if (request_options) + response_details_.fido_request_options = request_options->Clone(); + + const auto* token = response.FindStringKey("card_authorization_token"); + response_details_.card_authorization_token = token ? *token : std::string(); } bool IsResponseComplete() override { @@ -443,7 +475,9 @@ class OptChangeRequest : public PaymentsRequest { public: OptChangeRequest( const PaymentsClient::OptChangeRequestDetails& request_details, - OptChangeCallback callback, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + PaymentsClient::OptChangeResponseDetails&)> + callback, const bool full_sync_enabled) : request_details_(request_details), callback_(std::move(callback)), @@ -470,46 +504,84 @@ class OptChangeRequest : public PaymentsRequest { std::move(chrome_user_context)); } - request_dict.SetKey("opt_in", base::Value(request_details_.opt_in)); + std::string reason; + switch (request_details_.reason) { + case PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH: + reason = "ENABLE_FIDO_AUTH"; + break; + case PaymentsClient::OptChangeRequestDetails::DISABLE_FIDO_AUTH: + reason = "DISABLE_FIDO_AUTH"; + break; + case PaymentsClient::OptChangeRequestDetails::ADD_CARD_FOR_FIDO_AUTH: + reason = "ADD_CARD_FOR_FIDO_AUTH"; + break; + default: + NOTREACHED(); + break; + } + request_dict.SetKey("reason", base::Value(reason)); if (request_details_.fido_authenticator_response.is_dict()) { - request_dict.SetKey( + base::Value fido_authentication_info(base::Value::Type::DICTIONARY); + + fido_authentication_info.SetKey( "fido_authenticator_response", std::move(request_details_.fido_authenticator_response)); + + if (!request_details_.card_authorization_token.empty()) { + fido_authentication_info.SetKey( + "card_authorization_token", + base::Value(request_details_.card_authorization_token)); + } + + request_dict.SetKey("fido_authentication_info", + std::move(fido_authentication_info)); } std::string request_content; base::JSONWriter::Write(request_dict, &request_content); - VLOG(3) << "autofillauthoptchange request body: " << request_content; + VLOG(3) << "updateautofilluserpreference request body: " << request_content; return request_content; } void ParseResponse(const base::Value& response) override { - const auto* user_is_opted_in = - response.FindKeyOfType("user_is_opted_in", base::Value::Type::BOOLEAN); - if (user_is_opted_in) - user_is_opted_in_ = user_is_opted_in->GetBool(); + const auto* fido_authentication_info = response.FindKeyOfType( + "fido_authentication_info", base::Value::Type::DICTIONARY); + if (!fido_authentication_info) + return; - const auto* fido_creation_options = response.FindKeyOfType( + const auto* user_status = + fido_authentication_info->FindStringKey("user_status"); + if (user_status && *user_status != "UNKNOWN_USER_STATUS") + response_details_.user_is_opted_in = + (*user_status == "FIDO_AUTH_ENABLED"); + + const auto* fido_creation_options = fido_authentication_info->FindKeyOfType( "fido_creation_options", base::Value::Type::DICTIONARY); if (fido_creation_options) - fido_creation_options_ = fido_creation_options->Clone(); + response_details_.fido_creation_options = fido_creation_options->Clone(); + + const auto* fido_request_options = fido_authentication_info->FindKeyOfType( + "fido_request_options", base::Value::Type::DICTIONARY); + if (fido_request_options) + response_details_.fido_request_options = fido_request_options->Clone(); } - bool IsResponseComplete() override { return user_is_opted_in_.has_value(); } + bool IsResponseComplete() override { + return response_details_.user_is_opted_in.has_value(); + } void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override { - std::move(callback_).Run( - result, user_is_opted_in_.value_or(!request_details_.opt_in), - std::move(fido_creation_options_)); + std::move(callback_).Run(result, response_details_); } private: PaymentsClient::OptChangeRequestDetails request_details_; - OptChangeCallback callback_; + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + PaymentsClient::OptChangeResponseDetails&)> + callback_; const bool full_sync_enabled_; - base::Optional<bool> user_is_opted_in_; - base::Value fido_creation_options_; + PaymentsClient::OptChangeResponseDetails response_details_; DISALLOW_COPY_AND_ASSIGN(OptChangeRequest); }; @@ -568,8 +640,7 @@ class GetUploadDetailsRequest : public PaymentsRequest { // min address is not possible). The final parameter directs // BuildAddressDictionary to omit names and phone numbers, which aren't // useful for these purposes. - addresses.GetList().push_back( - BuildAddressDictionary(profile, app_locale_, false)); + addresses.Append(BuildAddressDictionary(profile, app_locale_, false)); } request_dict.SetKey("address", std::move(addresses)); @@ -740,8 +811,7 @@ class UploadCardRequest : public PaymentsRequest { base::Value addresses(base::Value::Type::LIST); for (const AutofillProfile& profile : request_details_.profiles) { - addresses.GetList().push_back( - BuildAddressDictionary(profile, app_locale, true)); + addresses.Append(BuildAddressDictionary(profile, app_locale, true)); } request_dict.SetKey("address", std::move(addresses)); @@ -859,7 +929,7 @@ class MigrateCardsRequest : public PaymentsRequest { for (size_t index = 0; index < migratable_credit_cards_.size(); ++index) { std::string pan_field_name = GetPanFieldName(index); // Generate credit card dictionary. - migrate_cards.GetList().push_back(BuildCreditCardDictionary( + migrate_cards.Append(BuildCreditCardDictionary( migratable_credit_cards_[index].credit_card(), app_locale, pan_field_name)); // Append pan data to the |all_pans_data|. @@ -968,6 +1038,12 @@ operator=(const PaymentsClient::UnmaskResponseDetails& other) { } else { fido_creation_options.reset(); } + if (other.fido_request_options.has_value()) { + fido_request_options = other.fido_request_options->Clone(); + } else { + fido_request_options.reset(); + } + card_authorization_token = other.card_authorization_token; return *this; } @@ -975,11 +1051,30 @@ PaymentsClient::OptChangeRequestDetails::OptChangeRequestDetails() {} PaymentsClient::OptChangeRequestDetails::OptChangeRequestDetails( const OptChangeRequestDetails& other) { app_locale = other.app_locale; - opt_in = other.opt_in; + reason = other.reason; fido_authenticator_response = other.fido_authenticator_response.Clone(); + card_authorization_token = other.card_authorization_token; } PaymentsClient::OptChangeRequestDetails::~OptChangeRequestDetails() {} +PaymentsClient::OptChangeResponseDetails::OptChangeResponseDetails() {} +PaymentsClient::OptChangeResponseDetails::OptChangeResponseDetails( + const OptChangeResponseDetails& other) { + user_is_opted_in = other.user_is_opted_in; + + if (other.fido_creation_options.has_value()) { + fido_creation_options = other.fido_creation_options->Clone(); + } else { + fido_creation_options.reset(); + } + if (other.fido_request_options.has_value()) { + fido_request_options = other.fido_request_options->Clone(); + } else { + fido_request_options.reset(); + } +} +PaymentsClient::OptChangeResponseDetails::~OptChangeResponseDetails() {} + PaymentsClient::UploadRequestDetails::UploadRequestDetails() {} PaymentsClient::UploadRequestDetails::UploadRequestDetails( const UploadRequestDetails& other) = default; @@ -1027,8 +1122,11 @@ void PaymentsClient::UnmaskCard( /*authenticate=*/true); } -void PaymentsClient::OptChange(const OptChangeRequestDetails request_details, - OptChangeCallback callback) { +void PaymentsClient::OptChange( + const OptChangeRequestDetails request_details, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + PaymentsClient::OptChangeResponseDetails&)> + callback) { IssueRequest(std::make_unique<OptChangeRequest>( request_details, std::move(callback), account_info_getter_->IsSyncFeatureEnabled()), @@ -1231,7 +1329,7 @@ void PaymentsClient::StartTokenFetch(bool invalidate_old) { identity::ScopeSet payments_scopes; payments_scopes.insert(kPaymentsOAuth2Scope); - std::string account_id = + CoreAccountId account_id = account_info_getter_->GetAccountInfoForPaymentsServer().account_id; if (invalidate_old) { DCHECK(!access_token_.empty()); diff --git a/chromium/components/autofill/core/browser/payments/payments_client.h b/chromium/components/autofill/core/browser/payments/payments_client.h index 07523979cc2..9ce00b334e2 100644 --- a/chromium/components/autofill/core/browser/payments/payments_client.h +++ b/chromium/components/autofill/core/browser/payments/payments_client.h @@ -53,11 +53,6 @@ typedef base::OnceCallback<void(AutofillClient::PaymentsRpcResult, AutofillClient::UnmaskDetails&)> GetUnmaskDetailsCallback; -// Callback type for OptChange callback. -typedef base::OnceCallback< - void(AutofillClient::PaymentsRpcResult, bool, base::Value)> - OptChangeCallback; - // Billable service number is defined in Payments server to distinguish // different requests. const int kUnmaskCardBillableServiceNumber = 70154; @@ -106,8 +101,22 @@ class PaymentsClient { return *this; } + UnmaskResponseDetails& with_dcvv(std::string d) { + dcvv = d; + return *this; + } + std::string real_pan; - base::Optional<base::Value> fido_creation_options; + std::string dcvv; + // Challenge required for enrolling user into FIDO authentication for future + // card unmasking. + base::Optional<base::Value> fido_creation_options = base::nullopt; + // Challenge required for authorizing user for FIDO authentication for + // future card unmasking. + base::Optional<base::Value> fido_request_options = base::nullopt; + // An opaque token used to logically chain consecutive UnmaskCard and + // OptChange calls together. + std::string card_authorization_token = std::string(); }; // Information required to either opt-in or opt-out a user for FIDO @@ -118,8 +127,45 @@ class PaymentsClient { ~OptChangeRequestDetails(); std::string app_locale; - bool opt_in; + + // The reason for making the request. + enum Reason { + // Unknown default. + UNKNOWN_REASON = 0, + // The user wants to enable FIDO authentication for card unmasking. + ENABLE_FIDO_AUTH = 1, + // The user wants to disable FIDO authentication for card unmasking. + DISABLE_FIDO_AUTH = 2, + // The user is authorizing a new card for future FIDO authentication + // unmasking. + ADD_CARD_FOR_FIDO_AUTH = 3, + }; + + // Reason for the request. + Reason reason; + // Signature required for enrolling user into FIDO authentication for future + // card unmasking. base::Value fido_authenticator_response; + // An opaque token used to logically chain consecutive UnmaskCard and + // OptChange calls together. + std::string card_authorization_token = std::string(); + }; + + // Information retrieved from an OptChange request. + struct OptChangeResponseDetails { + OptChangeResponseDetails(); + OptChangeResponseDetails(const OptChangeResponseDetails& other); + ~OptChangeResponseDetails(); + + // Unset if response failed. True if user is opted-in for FIDO + // authentication for card unmasking. False otherwise. + base::Optional<bool> user_is_opted_in; + // Challenge required for enrolling user into FIDO authentication for future + // card unmasking. + base::Optional<base::Value> fido_creation_options; + // Challenge required for authorizing user for FIDO authentication for + // future card unmasking. + base::Optional<base::Value> fido_request_options; }; // A collection of the information required to make a credit card upload @@ -206,8 +252,11 @@ class PaymentsClient { // Opts-in or opts-out the user to use FIDO authentication for card unmasking // on this device. - void OptChange(const OptChangeRequestDetails request_details, - OptChangeCallback callback); + void OptChange( + const OptChangeRequestDetails request_details, + base::OnceCallback<void(AutofillClient::PaymentsRpcResult, + PaymentsClient::OptChangeResponseDetails&)> + callback); // Determine if the user meets the Payments service's conditions for upload. // The service uses |addresses| (from which names and phone numbers are diff --git a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc index 39f0e812a59..10d0dfc4bbd 100644 --- a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc @@ -24,6 +24,7 @@ #include "components/autofill/core/browser/payments/local_card_migration_manager.h" #include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/test_personal_data_manager.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_switches.h" @@ -140,13 +141,15 @@ class PaymentsClientTest : public testing::Test { unmask_response_details_ = &response; } - void OnDidGetOptChangeResult(AutofillClient::PaymentsRpcResult result, - bool user_is_opted_in, - base::Value fido_creation_options) { + void OnDidGetOptChangeResult( + AutofillClient::PaymentsRpcResult result, + PaymentsClient::OptChangeResponseDetails& response) { result_ = result; - user_is_opted_in_ = user_is_opted_in; - if (fido_creation_options.is_dict()) - fido_creation_options_ = fido_creation_options.Clone(); + opt_change_response_.user_is_opted_in = response.user_is_opted_in; + opt_change_response_.fido_creation_options = + std::move(response.fido_creation_options); + opt_change_response_.fido_request_options = + std::move(response.fido_request_options); } void OnDidGetUploadDetails( @@ -209,9 +212,10 @@ class PaymentsClientTest : public testing::Test { // If |opt_in| is set to true, then opts the user in to use FIDO // authentication for card unmasking. Otherwise opts the user out. - void StartOptChangeRequest(bool opt_in) { + void StartOptChangeRequest( + PaymentsClient::OptChangeRequestDetails::Reason reason) { PaymentsClient::OptChangeRequestDetails request_details; - request_details.opt_in = opt_in; + request_details.reason = reason; client_->OptChange( request_details, base::BindOnce(&PaymentsClientTest::OnDidGetOptChangeResult, @@ -279,7 +283,7 @@ class PaymentsClientTest : public testing::Test { void IssueOAuthToken() { identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( "totally_real_token", - base::Time::Now() + base::TimeDelta::FromDays(10)); + AutofillClock::Now() + base::TimeDelta::FromDays(10)); // Verify the auth header. std::string auth_header_value; @@ -299,10 +303,8 @@ class PaymentsClientTest : public testing::Test { // Server ID of a saved card via credit card upload save. std::string server_id_; - // Status of the user's FIDO auth opt-in; returned from an OptChange call. - base::Optional<bool> user_is_opted_in_; - // FIDO auth enrollment creation options; returned from an OptChange call. - base::Value fido_creation_options_; + // The OptChangeResponseDetails retrieved from an OptChangeRequest. + PaymentsClient::OptChangeResponseDetails opt_change_response_; // The UnmaskResponseDetails retrieved from an UnmaskRequest. Includes PAN. PaymentsClient::UnmaskResponseDetails* unmask_response_details_ = nullptr; // The legal message returned from a GetDetails upload save preflight call. @@ -428,11 +430,13 @@ TEST_F(PaymentsClientTest, UnmaskSuccessViaFIDO) { TEST_F(PaymentsClientTest, UnmaskSuccessViaCVCWithCreationOptions) { StartUnmasking(CardUnmaskOptions().with_use_fido(false)); IssueOAuthToken(); - ReturnResponse(net::HTTP_OK, - "{ \"pan\": \"1234\", \"fido_creation_options\": " - "{\"relying_party_id\": \"google.com\"}}"); + ReturnResponse( + net::HTTP_OK, + "{ \"pan\": \"1234\", \"dcvv\": \"321\", \"fido_creation_options\": " + "{\"relying_party_id\": \"google.com\"}}"); EXPECT_EQ(AutofillClient::SUCCESS, result_); EXPECT_EQ("1234", unmask_response_details_->real_pan); + EXPECT_EQ("321", unmask_response_details_->dcvv); EXPECT_EQ("google.com", *unmask_response_details_->fido_creation_options->FindStringKey( "relying_party_id")); @@ -514,51 +518,51 @@ TEST_F(PaymentsClientTest, UnmaskLogsCvcLengthForPaymentRequest) { "Autofill.CardUnmask.CvcLength.ForPaymentRequest", 5, 1); } -TEST_F(PaymentsClientTest, UnmaskLogsBlankCvcLength) { - base::HistogramTester histogram_tester; - StartUnmasking(CardUnmaskOptions() - .with_reason(AutofillClient::UNMASK_FOR_AUTOFILL) - .with_cvc("")); - IssueOAuthToken(); - - histogram_tester.ExpectBucketCount( - "Autofill.CardUnmask.CvcLength.ForAutofill", 0, 1); -} - TEST_F(PaymentsClientTest, OptInSuccess) { - StartOptChangeRequest(/*opt_in=*/true); + StartOptChangeRequest( + PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH); IssueOAuthToken(); - ReturnResponse(net::HTTP_OK, "{ \"user_is_opted_in\": true }"); + ReturnResponse(net::HTTP_OK, + "{ \"fido_authentication_info\": { \"user_status\": " + "\"FIDO_AUTH_ENABLED\"}}"); EXPECT_EQ(AutofillClient::SUCCESS, result_); - EXPECT_TRUE(user_is_opted_in_.value()); + EXPECT_TRUE(opt_change_response_.user_is_opted_in.value()); } TEST_F(PaymentsClientTest, OptInServerUnresponsive) { - StartOptChangeRequest(/*opt_in=*/true); + StartOptChangeRequest( + PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH); IssueOAuthToken(); ReturnResponse(net::HTTP_REQUEST_TIMEOUT, ""); EXPECT_EQ(AutofillClient::NETWORK_ERROR, result_); - EXPECT_FALSE(user_is_opted_in_.value()); + EXPECT_FALSE(opt_change_response_.user_is_opted_in.has_value()); } TEST_F(PaymentsClientTest, OptOutSuccess) { - StartOptChangeRequest(/*opt_in=*/false); + StartOptChangeRequest( + PaymentsClient::OptChangeRequestDetails::DISABLE_FIDO_AUTH); IssueOAuthToken(); - ReturnResponse(net::HTTP_OK, "{ \"user_is_opted_in\": false }"); + ReturnResponse(net::HTTP_OK, + "{ \"fido_authentication_info\": { \"user_status\": " + "\"FIDO_AUTH_DISABLED\"}}"); EXPECT_EQ(AutofillClient::SUCCESS, result_); - EXPECT_FALSE(user_is_opted_in_.value()); + EXPECT_FALSE(opt_change_response_.user_is_opted_in.value()); } TEST_F(PaymentsClientTest, EnrollAttemptReturnsCreationOptions) { - StartOptChangeRequest(/*opt_in=*/true); + StartOptChangeRequest( + PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH); IssueOAuthToken(); ReturnResponse(net::HTTP_OK, - "{ \"user_is_opted_in\": false, \"fido_creation_options\": { " - "\"relying_party_id\": \"google.com\"} }"); + "{ \"fido_authentication_info\": { \"user_status\": " + "\"FIDO_AUTH_DISABLED\"," + "\"fido_creation_options\": {" + "\"relying_party_id\": \"google.com\"}}}"); EXPECT_EQ(AutofillClient::SUCCESS, result_); - EXPECT_FALSE(user_is_opted_in_.value()); + EXPECT_FALSE(opt_change_response_.user_is_opted_in.value()); EXPECT_EQ("google.com", - *fido_creation_options_.FindStringKey("relying_party_id")); + *opt_change_response_.fido_creation_options->FindStringKey( + "relying_party_id")); } TEST_F(PaymentsClientTest, GetDetailsSuccess) { @@ -806,7 +810,7 @@ TEST_F(PaymentsClientTest, GetUploadAccountFromSyncTest) { // Issue a token for the secondary account. identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( secondary_account_info.account_id, "secondary_account_token", - base::Time::Now() + base::TimeDelta::FromDays(10)); + AutofillClock::Now() + base::TimeDelta::FromDays(10)); // Verify the auth header. std::string auth_header_value; diff --git a/chromium/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.cc b/chromium/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.cc index e8a556c8081..bce45685589 100644 --- a/chromium/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.cc +++ b/chromium/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.cc @@ -22,12 +22,14 @@ TestCreditCardFIDOAuthenticator::~TestCreditCardFIDOAuthenticator() {} void TestCreditCardFIDOAuthenticator::GetAssertion( PublicKeyCredentialRequestOptionsPtr request_options) { - request_options_ = std::move(request_options); + request_options_ = request_options->Clone(); + CreditCardFIDOAuthenticator::GetAssertion(std::move(request_options)); } void TestCreditCardFIDOAuthenticator::MakeCredential( PublicKeyCredentialCreationOptionsPtr creation_options) { - creation_options_ = std::move(creation_options); + creation_options_ = creation_options->Clone(); + CreditCardFIDOAuthenticator::MakeCredential(std::move(creation_options)); } // static diff --git a/chromium/components/autofill/core/browser/payments/test_payments_client.cc b/chromium/components/autofill/core/browser/payments/test_payments_client.cc index 88ba1252ce0..144de6532c2 100644 --- a/chromium/components/autofill/core/browser/payments/test_payments_client.cc +++ b/chromium/components/autofill/core/browser/payments/test_payments_client.cc @@ -7,7 +7,9 @@ #include <memory> #include <unordered_map> +#include "base/json/json_reader.h" #include "base/strings/utf_string_conversions.h" +#include "base/values.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -33,7 +35,8 @@ TestPaymentsClient::~TestPaymentsClient() {} void TestPaymentsClient::GetUnmaskDetails(GetUnmaskDetailsCallback callback, const std::string& app_locale) { - std::move(callback).Run(AutofillClient::SUCCESS, unmask_details_); + if (should_return_unmask_details_) + std::move(callback).Run(AutofillClient::SUCCESS, unmask_details_); } void TestPaymentsClient::GetUploadDetails( @@ -56,7 +59,7 @@ void TestPaymentsClient::GetUploadDetails( app_locale == "en-US" ? AutofillClient::SUCCESS : AutofillClient::PERMANENT_FAILURE, base::ASCIIToUTF16("this is a context token"), - std::unique_ptr<base::Value>(nullptr), supported_card_bin_ranges_); + TestPaymentsClient::LegalMessage(), supported_card_bin_ranges_); } void TestPaymentsClient::UploadCard( @@ -76,13 +79,20 @@ void TestPaymentsClient::MigrateCards( "this is display text"); } +void TestPaymentsClient::ShouldReturnUnmaskDetailsImmediately( + bool should_return_unmask_details) { + should_return_unmask_details_ = should_return_unmask_details; +} + void TestPaymentsClient::AllowFidoRegistration(bool offer_fido_opt_in) { + should_return_unmask_details_ = true; unmask_details_.offer_fido_opt_in = offer_fido_opt_in; } void TestPaymentsClient::AddFidoEligibleCard(std::string server_id, std::string credential_id, std::string relying_party_id) { + should_return_unmask_details_ = true; unmask_details_.offer_fido_opt_in = false; unmask_details_.unmask_auth_method = AutofillClient::UnmaskAuthMethod::FIDO; unmask_details_.fido_eligible_card_ids.insert(server_id); @@ -136,5 +146,40 @@ void TestPaymentsClient::SetSupportedBINRanges( supported_card_bin_ranges_ = bin_ranges; } +void TestPaymentsClient::SetUseInvalidLegalMessageInGetUploadDetails( + bool use_invalid_legal_message) { + use_invalid_legal_message_ = use_invalid_legal_message; +} + +std::unique_ptr<base::Value> TestPaymentsClient::LegalMessage() { + if (use_invalid_legal_message_) { + // Legal message is invalid because it's missing the url. + return std::unique_ptr<base::Value>( + base::JSONReader::ReadDeprecated("{" + " \"line\" : [ {" + " \"template\": \"Panda {0}.\"," + " \"template_parameter\": [ {" + " \"display_text\": \"bear\"" + " } ]" + " } ]" + "}")); + return std::unique_ptr<base::Value>(base::JSONReader::ReadDeprecated("{}")); + } else { + return std::unique_ptr<base::Value>(base::JSONReader::ReadDeprecated( + "{" + " \"line\" : [ {" + " \"template\": \"The legal documents are: {0} and {1}.\"," + " \"template_parameter\" : [ {" + " \"display_text\" : \"Terms of Service\"," + " \"url\": \"http://www.example.com/tos\"" + " }, {" + " \"display_text\" : \"Privacy Policy\"," + " \"url\": \"http://www.example.com/pp\"" + " } ]" + " } ]" + "}")); + } +} + } // namespace payments } // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/test_payments_client.h b/chromium/components/autofill/core/browser/payments/test_payments_client.h index 01763edd62f..03ffcc0bea3 100644 --- a/chromium/components/autofill/core/browser/payments/test_payments_client.h +++ b/chromium/components/autofill/core/browser/payments/test_payments_client.h @@ -56,6 +56,10 @@ class TestPaymentsClient : public payments::PaymentsClient { const std::vector<MigratableCreditCard>& migratable_credit_cards, MigrateCardsCallback callback) override; + // Some metrics are affected by the latency of GetUnmaskDetails, so it is + // useful to control whether or not GetUnmaskDetails() is responded to. + void ShouldReturnUnmaskDetailsImmediately(bool should_return_unmask_details); + void AllowFidoRegistration(bool offer_fido_opt_in = true); void AddFidoEligibleCard(std::string server_id, @@ -70,6 +74,9 @@ class TestPaymentsClient : public payments::PaymentsClient { void SetSupportedBINRanges(std::vector<std::pair<int, int>> bin_ranges); + void SetUseInvalidLegalMessageInGetUploadDetails( + bool use_invalid_legal_message); + int detected_values_in_upload_details() const { return detected_values_; } const std::vector<AutofillProfile>& addresses_in_upload_details() const { return upload_details_addresses_; @@ -89,6 +96,9 @@ class TestPaymentsClient : public payments::PaymentsClient { private: std::string server_id_; + // Some metrics are affected by the latency of GetUnmaskDetails, so it is + // useful to control whether or not GetUnmaskDetails() is responded to. + bool should_return_unmask_details_ = true; AutofillClient::UnmaskDetails unmask_details_; std::vector<std::pair<int, int>> supported_card_bin_ranges_; std::vector<AutofillProfile> upload_details_addresses_; @@ -99,6 +109,8 @@ class TestPaymentsClient : public payments::PaymentsClient { int billable_service_number_; PaymentsClient::UploadCardSource upload_card_source_; std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_; + bool use_invalid_legal_message_ = false; + std::unique_ptr<base::Value> LegalMessage(); DISALLOW_COPY_AND_ASSIGN(TestPaymentsClient); }; diff --git a/chromium/components/autofill/core/browser/payments/test_strike_database.cc b/chromium/components/autofill/core/browser/payments/test_strike_database.cc index 7b96773e25b..d80df7cbac1 100644 --- a/chromium/components/autofill/core/browser/payments/test_strike_database.cc +++ b/chromium/components/autofill/core/browser/payments/test_strike_database.cc @@ -5,6 +5,7 @@ #include "components/autofill/core/browser/payments/test_strike_database.h" #include "components/autofill/core/browser/proto/strike_data.pb.h" +#include "components/autofill/core/common/autofill_clock.h" namespace autofill { @@ -36,7 +37,7 @@ void TestStrikeDatabase::AddEntryWithNumStrikes(const std::string& key, StrikeData strike_data; strike_data.set_num_strikes(num_strikes); strike_data.set_last_update_timestamp( - base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds()); + AutofillClock::Now().ToDeltaSinceWindowsEpoch().InMicroseconds()); db_[key] = strike_data; } diff --git a/chromium/components/autofill/core/browser/payments/upi_vpa_save_manager.cc b/chromium/components/autofill/core/browser/payments/upi_vpa_save_manager.cc new file mode 100644 index 00000000000..324fbfc53bc --- /dev/null +++ b/chromium/components/autofill/core/browser/payments/upi_vpa_save_manager.cc @@ -0,0 +1,21 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/payments/upi_vpa_save_manager.h" + +#include "base/logging.h" + +namespace autofill { + +UpiVpaSaveManager::UpiVpaSaveManager(PersonalDataManager* personal_data_manager) + : personal_data_manager_(personal_data_manager) {} + +void UpiVpaSaveManager::OfferLocalSave(const std::string& upi_id) { + // TODO(crbug.com/986289): Ask user with a prompt before saving. + + if (personal_data_manager_) + personal_data_manager_->AddVPA(upi_id); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/upi_vpa_save_manager.h b/chromium/components/autofill/core/browser/payments/upi_vpa_save_manager.h new file mode 100644 index 00000000000..b97a6330969 --- /dev/null +++ b/chromium/components/autofill/core/browser/payments/upi_vpa_save_manager.h @@ -0,0 +1,29 @@ +// 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_UPI_VPA_SAVE_MANAGER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_UPI_VPA_SAVE_MANAGER_H_ + +#include "base/strings/string16.h" +#include "components/autofill/core/browser/personal_data_manager.h" + +namespace autofill { + +class UpiVpaSaveManager { + public: + UpiVpaSaveManager(PersonalDataManager* personal_data_manager); + ~UpiVpaSaveManager() = default; + + void OfferLocalSave(const std::string& upi_id); + + private: + // The personal data manager, used to save and load personal data to/from the + // web database. This is overridden by the AutofillManagerTest. + // Weak reference. May be nullptr, which indicates OTR. + PersonalDataManager* personal_data_manager_; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_UPI_VPA_SAVE_MANAGER_H_ diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc index 41cd4d5bb74..10787c72754 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager.cc +++ b/chromium/components/autofill/core/browser/personal_data_manager.cc @@ -47,6 +47,7 @@ #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.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_switches.h" #include "components/autofill/core/common/autofill_util.h" @@ -641,6 +642,13 @@ void PersonalDataManager::RecordUseOf(const AutofillDataModel& data_model) { } } +void PersonalDataManager::AddVPA(const std::string& vpa_id) { + DCHECK(!vpa_id.empty()); + if (is_off_the_record_ || !database_helper_->GetLocalDatabase()) + return; + database_helper_->GetLocalDatabase()->AddVPA(vpa_id); +} + void PersonalDataManager::AddProfile(const AutofillProfile& profile) { if (!IsAutofillProfileEnabled()) return; @@ -1305,7 +1313,7 @@ bool PersonalDataManager::ShouldSuggestServerCards() const { // seeing them in the dropdown. if (!prefs::IsUserOptedInWalletSyncTransport( pref_service_, - sync_service_->GetAuthenticatedAccountInfo().account_id)) { + sync_service_->GetAuthenticatedAccountInfo().account_id.id)) { return false; } } @@ -1349,7 +1357,6 @@ void PersonalDataManager::ClearProfileNonSettingsOrigins() { UpdateProfileInDB(*profile, /*enforced=*/true); } } - } void PersonalDataManager::ClearCreditCardNonSettingsOrigins() { @@ -1369,35 +1376,6 @@ void PersonalDataManager::ClearCreditCardNonSettingsOrigins() { Refresh(); } -void PersonalDataManager::MoveJapanCityToStreetAddress() { - if (!database_helper_->GetLocalDatabase()) - return; - - // Don't run if the migration has already been performed. - if (pref_service_->GetBoolean(prefs::kAutofillJapanCityFieldMigrated)) - return; - - base::string16 japan_country_code = base::ASCIIToUTF16("JP"); - base::string16 line_separator = base::ASCIIToUTF16("\n"); - for (AutofillProfile* profile : GetProfiles()) { - base::string16 country_code = profile->GetRawInfo(ADDRESS_HOME_COUNTRY); - base::string16 city = profile->GetRawInfo(ADDRESS_HOME_CITY); - if (country_code == japan_country_code && !city.empty()) { - base::string16 street_address = - profile->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS); - street_address = street_address.empty() - ? city - : street_address + line_separator + city; - profile->SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, street_address); - profile->SetRawInfo(ADDRESS_HOME_CITY, base::string16()); - UpdateProfileInDB(*profile, /*enforced=*/true); - } - } - - // Set the pref so that this migration is never run again. - pref_service_->SetBoolean(prefs::kAutofillJapanCityFieldMigrated, true); -} - void PersonalDataManager::OnValidated(const AutofillProfile* profile) { if (!profile) return; @@ -1452,94 +1430,6 @@ const ProfileValidityMap& PersonalDataManager::GetProfileValidityByGUID( return empty_validity_map; } -// static -std::string PersonalDataManager::MergeProfile( - const AutofillProfile& new_profile, - std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles, - const std::string& app_locale, - std::vector<AutofillProfile>* merged_profiles) { - merged_profiles->clear(); - - // Sort the existing profiles in decreasing order of frecency, so the "best" - // profiles are checked first. Put the verified profiles last so the non - // verified profiles get deduped among themselves before reaching the verified - // profiles. - // TODO(crbug.com/620521): Remove the check for verified from the sort. - base::Time comparison_time = AutofillClock::Now(); - std::sort(existing_profiles->begin(), existing_profiles->end(), - [comparison_time](const std::unique_ptr<AutofillProfile>& a, - const std::unique_ptr<AutofillProfile>& b) { - if (a->IsVerified() != b->IsVerified()) - return !a->IsVerified(); - return a->HasGreaterFrecencyThan(b.get(), comparison_time); - }); - - // Set to true if |existing_profiles| already contains an equivalent profile. - bool matching_profile_found = false; - std::string guid = new_profile.guid(); - - // If we have already saved this address, merge in any missing values. - // Only merge with the first match. Merging the new profile into the existing - // one preserves the validity of credit card's billing address reference. - AutofillProfileComparator comparator(app_locale); - for (const auto& existing_profile : *existing_profiles) { - if (!matching_profile_found && - comparator.AreMergeable(new_profile, *existing_profile) && - existing_profile->SaveAdditionalInfo(new_profile, app_locale)) { - // Unverified profiles should always be updated with the newer data, - // whereas verified profiles should only ever be overwritten by verified - // data. If an automatically aggregated profile would overwrite a - // verified profile, just drop it. - matching_profile_found = true; - guid = existing_profile->guid(); - - // We set the modification date so that immediate requests for profiles - // will properly reflect the fact that this profile has been modified - // recently. After writing to the database and refreshing the local copies - // the profile will have a very slightly newer time reflecting what's - // actually stored in the database. - existing_profile->set_modification_date(AutofillClock::Now()); - } - merged_profiles->push_back(*existing_profile); - } - - // If the new profile was not merged with an existing one, add it to the list. - if (!matching_profile_found) { - merged_profiles->push_back(new_profile); - // Similar to updating merged profiles above, set the modification date on - // new profiles. - merged_profiles->back().set_modification_date(AutofillClock::Now()); - AutofillMetrics::LogProfileActionOnFormSubmitted( - AutofillMetrics::NEW_PROFILE_CREATED); - } - - return guid; -} - -bool PersonalDataManager::IsCountryOfInterest( - const std::string& country_code) const { - DCHECK_EQ(2U, country_code.size()); - - const std::vector<AutofillProfile*>& profiles = GetProfiles(); - std::list<std::string> country_codes; - for (size_t i = 0; i < profiles.size(); ++i) { - country_codes.push_back(base::ToLowerASCII( - base::UTF16ToASCII(profiles[i]->GetRawInfo(ADDRESS_HOME_COUNTRY)))); - } - - std::string timezone_country = CountryCodeForCurrentTimezone(); - if (!timezone_country.empty()) - country_codes.push_back(base::ToLowerASCII(timezone_country)); - - // Only take the locale into consideration if all else fails. - if (country_codes.empty()) { - country_codes.push_back(base::ToLowerASCII( - AutofillCountry::CountryCodeForLocale(app_locale()))); - } - - return base::Contains(country_codes, base::ToLowerASCII(country_code)); -} - const std::string& PersonalDataManager::GetDefaultCountryCodeForNewAddress() const { if (default_country_code_.empty()) @@ -1762,8 +1652,8 @@ std::string PersonalDataManager::SaveImportedProfile( return std::string(); std::vector<AutofillProfile> profiles; - std::string guid = - MergeProfile(imported_profile, &web_profiles_, app_locale_, &profiles); + std::string guid = AutofillProfileComparator::MergeProfile( + imported_profile, &web_profiles_, app_locale_, &profiles); SetProfiles(&profiles); return guid; } @@ -1799,6 +1689,10 @@ std::string PersonalDataManager::SaveImportedCreditCard( credit_cards.push_back(imported_card); SetCreditCards(&credit_cards); + + // After a card is saved locally, notifies the observers. + OnCreditCardSaved(/*is_local_card=*/true); + return guid; } @@ -1945,7 +1839,8 @@ bool PersonalDataManager::ShouldShowCardsFromAccountOption() const { features::kAutofillEnableAccountWalletStorage)); bool is_opted_in = prefs::IsUserOptedInWalletSyncTransport( - pref_service_, sync_service_->GetAuthenticatedAccountInfo().account_id); + pref_service_, + sync_service_->GetAuthenticatedAccountInfo().account_id.id); AutofillMetrics::LogWalletSyncTransportCardsOptIn(is_opted_in); @@ -1957,7 +1852,7 @@ void PersonalDataManager::OnUserAcceptedCardsFromAccountOption() { DCHECK_EQ(AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled, GetSyncSigninState()); prefs::SetUserOptedInWalletSyncTransport( - pref_service_, sync_service_->GetAuthenticatedAccountInfo().account_id, + pref_service_, sync_service_->GetAuthenticatedAccountInfo().account_id.id, /*opted_in=*/true); } @@ -2014,7 +1909,8 @@ void PersonalDataManager::OnUserAcceptedUpstreamOffer() { if (GetSyncSigninState() == AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled) { prefs::SetUserOptedInWalletSyncTransport( - pref_service_, sync_service_->GetAuthenticatedAccountInfo().account_id, + pref_service_, + sync_service_->GetAuthenticatedAccountInfo().account_id.id, /*opted_in=*/true); } } @@ -2033,6 +1929,16 @@ void PersonalDataManager::NotifyPersonalDataObserver() { } } +void PersonalDataManager::OnCreditCardSaved(bool is_local_card) { + if (!base::FeatureList::IsEnabled( + features::kAutofillCreditCardUploadFeedback)) { + return; + } + for (PersonalDataManagerObserver& observer : observers_) + observer.OnCreditCardSaved( + /*should_show_sign_in_promo_if_applicable=*/is_local_card); +} + std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards( const AutofillType& type, const base::string16& field_contents, @@ -2421,9 +2327,6 @@ void PersonalDataManager::ApplyAddressFixesAndCleanups() { // Ran everytime it is called. ClearProfileNonSettingsOrigins(); - - // One-time fix, otherwise NOP. - MoveJapanCityToStreetAddress(); } void PersonalDataManager::ApplyCardFixesAndCleanups() { diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h index 912b4542d40..0e652553e43 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager.h +++ b/chromium/components/autofill/core/browser/personal_data_manager.h @@ -154,6 +154,10 @@ class PersonalDataManager : public KeyedService, std::string OnAcceptedLocalCreditCardSave( const CreditCard& imported_credit_card); + // Triggered when the user accepts saving a VPA value. Stores the |vpa_id| to + // the database. + virtual void AddVPA(const std::string& vpa_id); + // Adds |profile| to the web database. virtual void AddProfile(const AutofillProfile& profile); @@ -264,12 +268,6 @@ class PersonalDataManager : public KeyedService, // Returns the profiles to suggest to the user, ordered by frecency. std::vector<AutofillProfile*> GetProfilesToSuggest() const; - // Remove profiles that whose |type| field is flagged as invalid, if Chrome - // is configured to not make suggestions based on invalid data. - static void MaybeRemoveInvalidSuggestions( - const AutofillType& type, - std::vector<AutofillProfile*>* profiles); - // Returns Suggestions corresponding to the focused field's |type| and // |field_contents|, i.e. what the user has typed. |field_is_autofilled| is // true if the field has already been autofilled, and |field_types| stores the @@ -325,22 +323,6 @@ class PersonalDataManager : public KeyedService, const std::string& app_locale() const { return app_locale_; } - // Merges |new_profile| into one of the |existing_profiles| if possible; - // otherwise appends |new_profile| to the end of that list. Fills - // |merged_profiles| with the result. Returns the |guid| of the new or updated - // profile. - static std::string MergeProfile( - const AutofillProfile& new_profile, - std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles, - const std::string& app_locale, - std::vector<AutofillProfile>* merged_profiles); - - // Returns true if |country_code| is a country that the user is likely to - // be associated with the user. More concretely, it checks if there are any - // addresses with this country or if the user's system timezone is in the - // given country. - virtual bool IsCountryOfInterest(const std::string& country_code) const; - // Returns our best guess for the country a user is likely to use when // inputting a new address. The value is calculated once and cached, so it // will only update when Chrome is restarted. @@ -387,6 +369,10 @@ class PersonalDataManager : public KeyedService, // Notifies observers that the waiting should be stopped. void NotifyPersonalDataObserver(); + // Called when at least one (can be multiple) card was saved. |is_local_card| + // indicates if the card is saved to local storage. + void OnCreditCardSaved(bool is_local_card); + void set_client_profile_validator_for_test( AutofillProfileValidator* validator) { client_profile_validator_ = validator; @@ -466,8 +452,6 @@ class PersonalDataManager : public KeyedService, FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, ClearCreditCardNonSettingsOrigins); FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, - MoveJapanCityToStreetAddress); - FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, RequestProfileServerValidity); FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, GetProfileSuggestions_Validity); @@ -555,12 +539,6 @@ class PersonalDataManager : public KeyedService, void ClearProfileNonSettingsOrigins(); void ClearCreditCardNonSettingsOrigins(); - // Appends the value of the city field of a JP address to its street address - // field, separated by a newline, and clears the city field. - // TODO(rouslan): Remove this migration in or after October 2019. See bug: - // https://crbug.com/871301 - void MoveJapanCityToStreetAddress(); - // Called when the |profile| is validated by the AutofillProfileValidator, // updates the profiles on the |ongoing_profile_changes_| and the DB. virtual void OnValidated(const AutofillProfile* profile); @@ -703,13 +681,6 @@ class PersonalDataManager : public KeyedService, void RemoveAutofillProfileByGUIDAndBlankCreditCardReference( const std::string& guid); - // Returns true if an address can be deleted in a major version upgrade. - // An address is deletable if it is unverified, and not used by a valid - // credit card as billing address, and not used for a long time(13 months). - bool IsAddressDeletable( - AutofillProfile* profile, - const std::unordered_set<std::string>& used_billing_address_guids); - // Applies various fixes and cleanups on autofill addresses. void ApplyAddressFixesAndCleanups(); diff --git a/chromium/components/autofill/core/browser/personal_data_manager_observer.h b/chromium/components/autofill/core/browser/personal_data_manager_observer.h index d09bc934f9e..4a40dbba366 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager_observer.h +++ b/chromium/components/autofill/core/browser/personal_data_manager_observer.h @@ -13,7 +13,7 @@ namespace autofill { class PersonalDataManagerObserver { public: // Notifies the observer that the PersonalDataManager changed in some way. - virtual void OnPersonalDataChanged() = 0; + virtual void OnPersonalDataChanged() {} // Called when there is insufficient data to fill a form. Used for testing. virtual void OnInsufficientFormData() {} @@ -22,6 +22,11 @@ class PersonalDataManagerObserver { // handle. virtual void OnPersonalDataFinishedProfileTasks() {} + // Notifies the observer whenever at least one (can be multiple) credit card + // is suceesfully saved. + virtual void OnCreditCardSaved(bool should_show_sign_in_promo_if_applicable) { + } + protected: virtual ~PersonalDataManagerObserver() {} }; diff --git a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc index ed12c5048f9..16972154375 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc @@ -286,19 +286,8 @@ class PersonalDataManagerTestBase { return account_info; } - void MoveJapanCityToStreetAddress(PersonalDataManager* personal_data, - int move_times) { - base::RunLoop run_loop; - EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) - .WillRepeatedly(QuitMessageLoop(&run_loop)); - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) - .Times(move_times); - personal_data->MoveJapanCityToStreetAddress(); - run_loop.Run(); - } - - base::test::TaskEnvironment task_environment_{ - base::test::TaskEnvironment::MainThreadType::UI}; + base::test::SingleThreadTaskEnvironment task_environment_{ + base::test::SingleThreadTaskEnvironment::MainThreadType::UI}; std::unique_ptr<PrefService> prefs_; network::TestURLLoaderFactory test_url_loader_factory_; signin::IdentityTestEnvironment identity_test_env_; @@ -958,7 +947,7 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfileSetModificationDate) { SaveImportedProfileToPersonalDataManager(profile); const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles(); ASSERT_EQ(1U, profiles.size()); - EXPECT_GT(base::TimeDelta::FromMilliseconds(1000), + EXPECT_GT(base::TimeDelta::FromMilliseconds(2000), AutofillClock::Now() - profiles[0]->modification_date()); } @@ -1338,7 +1327,6 @@ TEST_F(PersonalDataManagerTest, AddFullCardAsMaskedCard) { "378282246310005" /* American Express */, "04", "2999", "1"); - personal_data_->AddFullServerCreditCard(server_card); WaitForOnPersonalDataChanged(); @@ -2773,7 +2761,7 @@ TEST_F(PersonalDataManagerTest, profile2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(10)); profile2.set_use_count(1); - EXPECT_TRUE(profile1.HasGreaterFrecencyThan(&profile2, base::Time::Now())); + EXPECT_TRUE(profile1.HasGreaterFrecencyThan(&profile2, AutofillClock::Now())); AddProfileToPersonalDataManager(profile1); AddProfileToPersonalDataManager(profile2); @@ -4478,7 +4466,7 @@ TEST_F(PersonalDataManagerTest, MergeProfile_Frecency) { // Merge the imported profile into the existing profiles. std::vector<AutofillProfile> profiles; - std::string guid = personal_data_->MergeProfile( + std::string guid = AutofillProfileComparator::MergeProfile( imported_profile, &existing_profiles, "US-EN", &profiles); // The new profile should be merged into the "fox" profile. @@ -4527,7 +4515,7 @@ TEST_F(PersonalDataManagerTest, MAYBE_MergeProfile_UsageStats) { // Merge the imported profile into the existing profiles. std::vector<AutofillProfile> profiles; - std::string guid = personal_data_->MergeProfile( + std::string guid = AutofillProfileComparator::MergeProfile( imported_profile, &existing_profiles, "US-EN", &profiles); // The new profile should be merged into the existing profile. @@ -6881,108 +6869,6 @@ TEST_F(PersonalDataManagerTest, ClearCreditCardNonSettingsOrigins) { personal_data_->GetCreditCardsToSuggest(false)[3]->origin()); } -// Tests that all city fields in a Japan profile are moved to the street address -// field. -TEST_F(PersonalDataManagerTest, MoveJapanCityToStreetAddress) { - // Turn on sync feature to avoid calling MoveJapanCityToStreetAddress on - // adding the profiles implicitly. - ASSERT_TRUE(TurnOnSyncFeature()); - // A US profile with both street address and a city. - std::string guid0 = base::GenerateGUID(); - { - AutofillProfile profile0(guid0, test::kEmptyOrigin); - test::SetProfileInfo(&profile0, "Homer", "J", "Simpson", - "homer.simpson@abc.com", "", "742. Evergreen Terrace", - "", "Springfield", "IL", "91601", "US", ""); - AddProfileToPersonalDataManager(profile0); - } - - // A JP profile with both street address and a city. - std::string guid1 = base::GenerateGUID(); - { - AutofillProfile profile1(guid1, test::kEmptyOrigin); - test::SetProfileInfo(&profile1, "Homer", "J", "Simpson", - "homer.simpson@abc.com", "", "742. Evergreen Terrace", - "", "Springfield", "IL", "91601", "JP", ""); - AddProfileToPersonalDataManager(profile1); - } - - // A JP profile with only a city. - std::string guid2 = base::GenerateGUID(); - { - AutofillProfile profile2(guid2, test::kEmptyOrigin); - test::SetProfileInfo(&profile2, "Homer", "J", "Simpson", - "homer.simpson@abc.com", "", "", "", "Springfield", - "IL", "91601", "JP", ""); - AddProfileToPersonalDataManager(profile2); - } - - // A JP profile with only a street address. - std::string guid3 = base::GenerateGUID(); - { - AutofillProfile profile3(guid3, test::kEmptyOrigin); - test::SetProfileInfo(&profile3, "Homer", "J", "Simpson", - "homer.simpson@abc.com", "", "742. Evergreen Terrace", - "", "", "IL", "91601", "JP", ""); - AddProfileToPersonalDataManager(profile3); - } - - // A JP profile with neither a street address nor a city. - std::string guid4 = base::GenerateGUID(); - { - AutofillProfile profile4(guid4, test::kEmptyOrigin); - test::SetProfileInfo(&profile4, "Homer", "J", "Simpson", - "homer.simpson@abc.com", "", "", "", "", "IL", "91601", - "JP", ""); - AddProfileToPersonalDataManager(profile4); - } - auto profiles = personal_data_->GetProfiles(); - ASSERT_EQ(5U, profiles.size()); - - MoveJapanCityToStreetAddress( - personal_data_.get(), - 2); // For the japan profiles where the city is not empty. - - { - AutofillProfile* profile0 = personal_data_->GetProfileByGUID(guid0); - EXPECT_EQ(base::ASCIIToUTF16("742. Evergreen Terrace"), - profile0->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)); - EXPECT_EQ(base::ASCIIToUTF16("Springfield"), - profile0->GetRawInfo(ADDRESS_HOME_CITY)); - } - - { - AutofillProfile* profile1 = personal_data_->GetProfileByGUID(guid1); - EXPECT_EQ(base::ASCIIToUTF16("742. Evergreen Terrace\nSpringfield"), - profile1->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)); - EXPECT_EQ(base::ASCIIToUTF16("742. Evergreen Terrace"), - profile1->GetRawInfo(ADDRESS_HOME_LINE1)); - EXPECT_EQ(base::ASCIIToUTF16("Springfield"), - profile1->GetRawInfo(ADDRESS_HOME_LINE2)); - EXPECT_TRUE(profile1->GetRawInfo(ADDRESS_HOME_CITY).empty()); - } - - { - AutofillProfile* profile2 = personal_data_->GetProfileByGUID(guid2); - EXPECT_EQ(base::ASCIIToUTF16("Springfield"), - profile2->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)); - EXPECT_TRUE(profile2->GetRawInfo(ADDRESS_HOME_CITY).empty()); - } - - { - AutofillProfile* profile3 = personal_data_->GetProfileByGUID(guid3); - EXPECT_EQ(base::ASCIIToUTF16("742. Evergreen Terrace"), - profile3->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)); - EXPECT_TRUE(profile3->GetRawInfo(ADDRESS_HOME_CITY).empty()); - } - - { - AutofillProfile* profile4 = personal_data_->GetProfileByGUID(guid4); - EXPECT_TRUE(profile4->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS).empty()); - EXPECT_TRUE(profile4->GetRawInfo(ADDRESS_HOME_CITY).empty()); - } -} - // Tests that all the non settings origins of autofill profiles are cleared even // if sync is disabled. TEST_F( @@ -7192,7 +7078,7 @@ TEST_F(PersonalDataManagerTest, RequestProfileServerValidity) { AutofillDataModel::INVALID, AutofillDataModel::VALID, AutofillDataModel::UNVALIDATED, AutofillDataModel::INVALID}; ASSERT_EQ(types.size(), states.size()); - for (unsigned long i = 0; i < types.size(); ++i) { + for (uint64_t i = 0; i < types.size(); ++i) { (*profile_validity_map .mutable_field_validity_states())[static_cast<int>(types[i])] = static_cast<int>(states[i]); @@ -7231,7 +7117,7 @@ TEST_F(PersonalDataManagerTest, RequestProfileServerValidity) { auto validities = personal_data_->GetProfileValidityByGUID(guid).field_validity_states(); ASSERT_EQ(validities.size(), types.size()); - for (unsigned long i = 0; i < types.size(); ++i) + for (uint64_t i = 0; i < types.size(); ++i) EXPECT_EQ(validities.at(types[i]), states[i]); guid = "00000000-0000-0000-0000-0000000000002"; @@ -7952,7 +7838,7 @@ namespace { class OneTimeObserver : public PersonalDataManagerObserver { public: - OneTimeObserver(PersonalDataManager* manager) : manager_(manager) {} + explicit OneTimeObserver(PersonalDataManager* manager) : manager_(manager) {} ~OneTimeObserver() override { if (manager_) diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto index 67002a10096..72e0e4f60bc 100644 --- a/chromium/components/autofill/core/browser/proto/server.proto +++ b/chromium/components/autofill/core/browser/proto/server.proto @@ -337,11 +337,11 @@ message AutofillUploadContents { // Whether the password has any lowercase letter. optional bool password_has_lowercase_letter = 25; - // Whether the password has any uppercase letter. - optional bool password_has_uppercase_letter = 26; + // Deprecated since M80: Whether the password has any uppercase letter. + optional bool password_has_uppercase_letter = 26 [deprecated = true]; - // Whether the password has any digit. - optional bool password_has_numeric = 27; + // Deprecated since M80: Whether the password has any digit. + optional bool password_has_numeric = 27 [deprecated = true]; // Whether the password has any special symbol. optional bool password_has_special_symbol = 28; diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc index 89baf299c69..a04561e1fe1 100644 --- a/chromium/components/autofill/core/browser/test_autofill_client.cc +++ b/chromium/components/autofill/core/browser/test_autofill_client.cc @@ -88,7 +88,7 @@ void TestAutofillClient::ShowLocalCardMigrationDialog( } void TestAutofillClient::ConfirmMigrateLocalCardToCloud( - std::unique_ptr<base::DictionaryValue> legal_message, + const LegalMessageLines& legal_message_lines, const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) { @@ -107,9 +107,20 @@ void TestAutofillClient::ShowLocalCardMigrationResults( const std::vector<MigratableCreditCard>& migratable_credit_cards, MigrationDeleteCardCallback delete_local_card_callback) {} +#if !defined(OS_ANDROID) && !defined(OS_IOS) +void TestAutofillClient::ShowVerifyPendingDialog( + base::OnceClosure cancel_card_verification_callback) {} + +void TestAutofillClient::CloseVerifyPendingDialog() {} +#endif + void TestAutofillClient::ShowWebauthnOfferDialog( WebauthnOfferDialogCallback callback) {} +bool TestAutofillClient::CloseWebauthnOfferDialog() { + return true; +} + void TestAutofillClient::ConfirmSaveAutofillProfile( const AutofillProfile& profile, base::OnceClosure callback) { @@ -128,13 +139,15 @@ void TestAutofillClient::ConfirmSaveCreditCardLocally( std::move(callback).Run(AutofillClient::ACCEPTED); } -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_IOS) void TestAutofillClient::ConfirmAccountNameFixFlow( base::OnceCallback<void(const base::string16&)> callback) { credit_card_name_fix_flow_bubble_was_shown_ = true; std::move(callback).Run(base::string16(base::ASCIIToUTF16("Gaia Name"))); } +#endif // defined(OS_ANDROID) || defined(OS_IOS) +#if defined(OS_ANDROID) void TestAutofillClient::ConfirmExpirationDateFixFlow( const CreditCard& card, base::OnceCallback<void(const base::string16&, const base::string16&)> @@ -148,7 +161,7 @@ void TestAutofillClient::ConfirmExpirationDateFixFlow( void TestAutofillClient::ConfirmSaveCreditCardToCloud( const CreditCard& card, - std::unique_ptr<base::DictionaryValue> legal_message, + const LegalMessageLines& legal_message_lines, SaveCreditCardOptions options, UploadSaveCardPromptCallback callback) { offer_to_save_credit_card_bubble_was_shown_ = options.show_prompt; diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h index 2f8b9bdda12..92b7019d260 100644 --- a/chromium/components/autofill/core/browser/test_autofill_client.h +++ b/chromium/components/autofill/core/browser/test_autofill_client.h @@ -16,6 +16,7 @@ #include "build/build_config.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/mock_autocomplete_history_manager.h" +#include "components/autofill/core/browser/payments/legal_message_line.h" #include "components/autofill/core/browser/payments/test_payments_client.h" #include "components/autofill/core/browser/payments/test_strike_database.h" #include "components/autofill/core/browser/test_address_normalizer.h" @@ -55,7 +56,7 @@ class TestAutofillClient : public AutofillClient { void ShowLocalCardMigrationDialog( base::OnceClosure show_migration_dialog_closure) override; void ConfirmMigrateLocalCardToCloud( - std::unique_ptr<base::DictionaryValue> legal_message, + const LegalMessageLines& legal_message_lines, const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) override; @@ -64,16 +65,25 @@ class TestAutofillClient : public AutofillClient { const base::string16& tip_message, const std::vector<MigratableCreditCard>& migratable_credit_cards, MigrationDeleteCardCallback delete_local_card_callback) override; +#if !defined(OS_ANDROID) && !defined(OS_IOS) + void ShowVerifyPendingDialog( + base::OnceClosure cancel_card_verification_callback) override; + void CloseVerifyPendingDialog() override; +#endif void ShowWebauthnOfferDialog(WebauthnOfferDialogCallback callback) override; + bool CloseWebauthnOfferDialog() override; void ConfirmSaveAutofillProfile(const AutofillProfile& profile, base::OnceClosure callback) override; void ConfirmSaveCreditCardLocally( const CreditCard& card, SaveCreditCardOptions options, LocalSaveCardPromptCallback callback) override; -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_IOS) void ConfirmAccountNameFixFlow( base::OnceCallback<void(const base::string16&)> callback) override; +#endif // defined(OS_ANDROID) || defined(OS_IOS) + +#if defined(OS_ANDROID) void ConfirmExpirationDateFixFlow( const CreditCard& card, base::OnceCallback<void(const base::string16&, const base::string16&)> @@ -81,7 +91,7 @@ class TestAutofillClient : public AutofillClient { #endif // defined(OS_ANDROID) void ConfirmSaveCreditCardToCloud( const CreditCard& card, - std::unique_ptr<base::DictionaryValue> legal_message, + const LegalMessageLines& legal_message_lines, SaveCreditCardOptions options, UploadSaveCardPromptCallback callback) override; void CreditCardUploadCompleted(bool card_saved) override; diff --git a/chromium/components/autofill/core/browser/test_autofill_clock.h b/chromium/components/autofill/core/browser/test_autofill_clock.h index 2b973619433..19ea0a8962b 100644 --- a/chromium/components/autofill/core/browser/test_autofill_clock.h +++ b/chromium/components/autofill/core/browser/test_autofill_clock.h @@ -19,7 +19,7 @@ namespace autofill { // Handles the customization of the time in tests. Replaces the clock in // AutofillClock with a test version that can be manipulated from this class. // Automatically resets a normal clock to AutofillClock when this gets -// destroyed, +// destroyed. class TestAutofillClock { public: TestAutofillClock(); diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.cc b/chromium/components/autofill/core/browser/test_autofill_driver.cc index dd51b9637b6..e7ce762307b 100644 --- a/chromium/components/autofill/core/browser/test_autofill_driver.cc +++ b/chromium/components/autofill/core/browser/test_autofill_driver.cc @@ -79,7 +79,7 @@ void TestAutofillDriver::RendererShouldPreviewFieldWithValue( } void TestAutofillDriver::RendererShouldSetSuggestionAvailability( - bool available) {} + const mojom::AutofillState state) {} void TestAutofillDriver::PopupHidden() { } diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.h b/chromium/components/autofill/core/browser/test_autofill_driver.h index d65c2b23cd8..f524de90b92 100644 --- a/chromium/components/autofill/core/browser/test_autofill_driver.h +++ b/chromium/components/autofill/core/browser/test_autofill_driver.h @@ -46,7 +46,8 @@ class TestAutofillDriver : public AutofillDriver { void RendererShouldFillFieldWithValue(const base::string16& value) override; void RendererShouldPreviewFieldWithValue( const base::string16& value) override; - void RendererShouldSetSuggestionAvailability(bool available) override; + void RendererShouldSetSuggestionAvailability( + const mojom::AutofillState state) override; void PopupHidden() override; gfx::RectF TransformBoundingBoxToViewportCoordinates( const gfx::RectF& bounding_box) override; diff --git a/chromium/components/autofill/core/browser/test_autofill_external_delegate.cc b/chromium/components/autofill/core/browser/test_autofill_external_delegate.cc index f38acc764ca..d97cfccf5c2 100644 --- a/chromium/components/autofill/core/browser/test_autofill_external_delegate.cc +++ b/chromium/components/autofill/core/browser/test_autofill_external_delegate.cc @@ -68,8 +68,11 @@ bool TestAutofillExternalDelegate::HasActiveScreenReader() const { } void TestAutofillExternalDelegate::OnAutofillAvailabilityEvent( - bool has_suggestions) { - has_suggestions_available_on_field_focus_ = has_suggestions; + const mojom::AutofillState state) { + if (state == mojom::AutofillState::kAutofillAvailable) + has_suggestions_available_on_field_focus_ = true; + else if (state == mojom::AutofillState::kNoSuggestions) + has_suggestions_available_on_field_focus_ = false; } void TestAutofillExternalDelegate::WaitForPopupHidden() { diff --git a/chromium/components/autofill/core/browser/test_autofill_external_delegate.h b/chromium/components/autofill/core/browser/test_autofill_external_delegate.h index 7757ba9682e..2aa50399df6 100644 --- a/chromium/components/autofill/core/browser/test_autofill_external_delegate.h +++ b/chromium/components/autofill/core/browser/test_autofill_external_delegate.h @@ -31,7 +31,7 @@ class TestAutofillExternalDelegate : public AutofillExternalDelegate { bool autoselect_first_suggestion, bool is_all_server_suggestions) override; bool HasActiveScreenReader() const override; - void OnAutofillAvailabilityEvent(bool has_suggestions) override; + void OnAutofillAvailabilityEvent(const mojom::AutofillState state) override; // Functions unique to TestAutofillExternalDelegate. diff --git a/chromium/components/autofill/core/browser/test_autofill_tick_clock.cc b/chromium/components/autofill/core/browser/test_autofill_tick_clock.cc new file mode 100644 index 00000000000..c558ed8b8f6 --- /dev/null +++ b/chromium/components/autofill/core/browser/test_autofill_tick_clock.cc @@ -0,0 +1,31 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/test_autofill_tick_clock.h" + +#include <utility> + +#include "base/test/simple_test_tick_clock.h" +#include "components/autofill/core/common/autofill_tick_clock.h" + +namespace autofill { + +TestAutofillTickClock::TestAutofillTickClock() { + AutofillTickClock::SetTestTickClock(&test_tick_clock_); +} + +TestAutofillTickClock::~TestAutofillTickClock() { + // Destroys the test tick_clock and resets a normal tick_clock. + AutofillTickClock::SetTickClock(); +} + +void TestAutofillTickClock::SetNowTicks(base::TimeTicks now) { + test_tick_clock_.SetNowTicks(now); +} + +void TestAutofillTickClock::Advance(base::TimeDelta delta) { + test_tick_clock_.Advance(delta); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/test_autofill_tick_clock.h b/chromium/components/autofill/core/browser/test_autofill_tick_clock.h new file mode 100644 index 00000000000..481d493725c --- /dev/null +++ b/chromium/components/autofill/core/browser/test_autofill_tick_clock.h @@ -0,0 +1,42 @@ +// 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_TICK_CLOCK_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_TICK_CLOCK_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/test/simple_test_tick_clock.h" + +namespace base { +class TimeTicks; +} // namespace base + +namespace autofill { + +// Handles the customization of the time in tests. Replaces the tick_clock in +// AutofillTickClock with a test version that can be manipulated from this +// class. Automatically resets a normal tick_clock to AutofillTickClock when +// this gets destroyed. +class TestAutofillTickClock { + public: + TestAutofillTickClock(); + ~TestAutofillTickClock(); + + // Set the time to be returned from AutofillTickClock::Now() calls. + void SetNowTicks(base::TimeTicks now); + + // Advances the tick_clock by |delta|. + void Advance(base::TimeDelta delta); + + private: + base::SimpleTestTickClock test_tick_clock_; + + DISALLOW_COPY_AND_ASSIGN(TestAutofillTickClock); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_TICK_CLOCK_H_ diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.cc b/chromium/components/autofill/core/browser/test_personal_data_manager.cc index f1d48c3d9bc..02cdc5f4ebb 100644 --- a/chromium/components/autofill/core/browser/test_personal_data_manager.cc +++ b/chromium/components/autofill/core/browser/test_personal_data_manager.cc @@ -46,6 +46,10 @@ std::string TestPersonalDataManager::SaveImportedCreditCard( return imported_credit_card.guid(); } +void TestPersonalDataManager::AddVPA(const std::string& profile) { + num_times_save_vpa_called_++; +} + void TestPersonalDataManager::AddProfile(const AutofillProfile& profile) { std::unique_ptr<AutofillProfile> profile_ptr = std::make_unique<AutofillProfile>(profile); @@ -222,8 +226,7 @@ bool TestPersonalDataManager::ShouldSuggestServerCards() const { return IsAutofillCreditCardEnabled() && IsAutofillWalletImportEnabled(); } -std::string TestPersonalDataManager::CountryCodeForCurrentTimezone() - const { +std::string TestPersonalDataManager::CountryCodeForCurrentTimezone() const { return timezone_country_code_; } diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.h b/chromium/components/autofill/core/browser/test_personal_data_manager.h index 688fe7fc9b8..a4d9dde9e4e 100644 --- a/chromium/components/autofill/core/browser/test_personal_data_manager.h +++ b/chromium/components/autofill/core/browser/test_personal_data_manager.h @@ -34,6 +34,7 @@ class TestPersonalDataManager : public PersonalDataManager { const AutofillProfile& imported_profile) override; std::string SaveImportedCreditCard( const CreditCard& imported_credit_card) override; + void AddVPA(const std::string& vpa) override; void AddProfile(const AutofillProfile& profile) override; void UpdateProfile(const AutofillProfile& profile) override; void RemoveByGUID(const std::string& guid) override; @@ -91,6 +92,8 @@ class TestPersonalDataManager : public PersonalDataManager { return num_times_save_imported_credit_card_called_; } + int num_times_save_vpa_called() const { return num_times_save_vpa_called_; } + bool sync_service_initialized() const { return sync_service_initialized_; } void SetAutofillEnabled(bool autofill_enabled) { @@ -129,6 +132,7 @@ class TestPersonalDataManager : public PersonalDataManager { std::string default_country_code_; int num_times_save_imported_profile_called_ = 0; int num_times_save_imported_credit_card_called_ = 0; + int num_times_save_vpa_called_ = 0; base::Optional<bool> autofill_enabled_; base::Optional<bool> autofill_profile_enabled_; base::Optional<bool> autofill_credit_card_enabled_; diff --git a/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller.h b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller.h new file mode 100644 index 00000000000..96d9faeb47f --- /dev/null +++ b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller.h @@ -0,0 +1,36 @@ +// 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_CONTROLLER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_CONTROLLER_H_ + +#include "base/strings/string16.h" + +namespace autofill { + +// Enables the user to accept or deny cardholder name fix flow prompt. +// Only used on mobile. +class CardNameFixFlowController { + public: + virtual ~CardNameFixFlowController() {} + + // Interaction. + virtual void OnConfirmNameDialogClosed() = 0; + virtual void OnNameAccepted(const base::string16& name) = 0; + virtual void OnDismissed() = 0; + + // State. + virtual int GetIconId() const = 0; + virtual base::string16 GetCancelButtonLabel() const = 0; + virtual base::string16 GetInferredCardholderName() const = 0; + virtual base::string16 GetInferredNameTooltipText() const = 0; + virtual base::string16 GetInputLabel() const = 0; + virtual base::string16 GetInputPlaceholderText() const = 0; + virtual base::string16 GetSaveButtonLabel() const = 0; + virtual base::string16 GetTitleText() const = 0; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_CONTROLLER_H_ diff --git a/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.cc b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.cc new file mode 100644 index 00000000000..ea355c2fbff --- /dev/null +++ b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.cc @@ -0,0 +1,127 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.h" + +#include <utility> + +#include "base/logging.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/values.h" +#include "build/branding_buildflags.h" +#include "build/build_config.h" +#include "components/autofill/core/browser/autofill_metrics.h" +#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h" +#include "components/grit/components_scaled_resources.h" +#include "components/strings/grit/components_strings.h" +#include "ui/base/l10n/l10n_util.h" + +namespace autofill { + +CardNameFixFlowControllerImpl::CardNameFixFlowControllerImpl() {} + +CardNameFixFlowControllerImpl::~CardNameFixFlowControllerImpl() { + if (card_name_fix_flow_view_) + card_name_fix_flow_view_->ControllerGone(); + + if (shown_ && !had_user_interaction_) { + AutofillMetrics::LogCardholderNameFixFlowPromptEvent( + AutofillMetrics:: + CARDHOLDER_NAME_FIX_FLOW_PROMPT_CLOSED_WITHOUT_INTERACTION); + } +} + +void CardNameFixFlowControllerImpl::Show( + CardNameFixFlowView* card_name_fix_flow_view, + const base::string16& inferred_cardholder_name, + base::OnceCallback<void(const base::string16&)> name_accepted_callback) { + DCHECK(!name_accepted_callback.is_null()); + DCHECK(card_name_fix_flow_view); + + if (card_name_fix_flow_view_) + card_name_fix_flow_view_->ControllerGone(); + card_name_fix_flow_view_ = card_name_fix_flow_view; + + name_accepted_callback_ = std::move(name_accepted_callback); + + inferred_cardholder_name_ = inferred_cardholder_name; + AutofillMetrics::LogSaveCardCardholderNamePrefilled( + !inferred_cardholder_name_.empty()); + + card_name_fix_flow_view_->Show(); + AutofillMetrics::LogCardholderNameFixFlowPromptEvent( + AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_SHOWN); + shown_ = true; +} + +void CardNameFixFlowControllerImpl::OnConfirmNameDialogClosed() { + card_name_fix_flow_view_ = nullptr; +} + +void CardNameFixFlowControllerImpl::OnNameAccepted(const base::string16& name) { + AutofillMetrics::LogCardholderNameFixFlowPromptEvent( + AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_ACCEPTED); + had_user_interaction_ = true; + AutofillMetrics::LogSaveCardCardholderNameWasEdited( + inferred_cardholder_name_ != name); + base::string16 trimmed_name; + base::TrimWhitespace(name, base::TRIM_ALL, &trimmed_name); + std::move(name_accepted_callback_).Run(trimmed_name); +} + +void CardNameFixFlowControllerImpl::OnDismissed() { + AutofillMetrics::LogCardholderNameFixFlowPromptEvent( + AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_DISMISSED); + had_user_interaction_ = true; +} + +int CardNameFixFlowControllerImpl::GetIconId() const { +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) + return IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER; +#else + return 0; +#endif +} + +base::string16 CardNameFixFlowControllerImpl::GetCancelButtonLabel() const { + return l10n_util::GetStringUTF16(IDS_CANCEL); +} + +base::string16 CardNameFixFlowControllerImpl::GetInferredCardholderName() + const { + return inferred_cardholder_name_; +} + +base::string16 CardNameFixFlowControllerImpl::GetInferredNameTooltipText() + const { + return l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_CARD_PROMPT_CARDHOLDER_NAME_TOOLTIP); +} + +base::string16 CardNameFixFlowControllerImpl::GetInputLabel() const { + return l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_CARD_PROMPT_CARDHOLDER_NAME); +} + +base::string16 CardNameFixFlowControllerImpl::GetInputPlaceholderText() const { + return l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_CARD_PROMPT_CARDHOLDER_NAME); +} + +base::string16 CardNameFixFlowControllerImpl::GetSaveButtonLabel() const { +#if defined(OS_IOS) + return l10n_util::GetStringUTF16(IDS_SAVE); +#else + return l10n_util::GetStringUTF16( + IDS_AUTOFILL_FIX_FLOW_PROMPT_SAVE_CARD_LABEL); +#endif +} + +base::string16 CardNameFixFlowControllerImpl::GetTitleText() const { + return l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_CARD_CARDHOLDER_NAME_FIX_FLOW_HEADER); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.h b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.h new file mode 100644 index 00000000000..e9f4d9ba72a --- /dev/null +++ b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.h @@ -0,0 +1,62 @@ +// 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_CONTROLLER_IMPL_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_CONTROLLER_IMPL_H_ + +#include <string> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/strings/string16.h" +#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_controller.h" + +namespace autofill { + +class CardNameFixFlowView; + +class CardNameFixFlowControllerImpl : public CardNameFixFlowController { + public: + CardNameFixFlowControllerImpl(); + ~CardNameFixFlowControllerImpl() override; + + void Show(CardNameFixFlowView* card_name_fix_flow_view, + const base::string16& inferred_cardholder_name, + base::OnceCallback<void(const base::string16&)> name_callback); + + // CardNameFixFlowController implementation. + void OnConfirmNameDialogClosed() override; + void OnNameAccepted(const base::string16& name) override; + void OnDismissed() override; + int GetIconId() const override; + base::string16 GetCancelButtonLabel() const override; + base::string16 GetInferredCardholderName() const override; + base::string16 GetInferredNameTooltipText() const override; + base::string16 GetInputLabel() const override; + base::string16 GetInputPlaceholderText() const override; + base::string16 GetSaveButtonLabel() const override; + base::string16 GetTitleText() const override; + + private: + // Inferred cardholder name from Gaia account. + base::string16 inferred_cardholder_name_; + + // View that displays the fix flow prompt. + CardNameFixFlowView* card_name_fix_flow_view_ = nullptr; + + // The callback to call once user confirms their name through the fix flow. + base::OnceCallback<void(const base::string16&)> name_accepted_callback_; + + // Whether the prompt was shown to the user. + bool shown_ = false; + + // Whether the user explicitly accepted or dismissed this prompt. + bool had_user_interaction_ = false; + + DISALLOW_COPY_AND_ASSIGN(CardNameFixFlowControllerImpl); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_CONTROLLER_IMPL_H_ diff --git a/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl_unittest.cc b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl_unittest.cc new file mode 100644 index 00000000000..c6dc583e35b --- /dev/null +++ b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl_unittest.cc @@ -0,0 +1,147 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.h" + +#include <stddef.h> +#include <memory> + +#include "base/bind.h" +#include "base/macros.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/metrics/histogram_tester.h" +#include "components/autofill/core/browser/autofill_metrics.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { + +class TestCardNameFixFlowView : public CardNameFixFlowView { + public: + void Show() override {} + void ControllerGone() override {} +}; + +class CardNameFixFlowControllerImplGenericTest { + public: + CardNameFixFlowControllerImplGenericTest() {} + + void ShowPromptWithInferredName() { + inferred_name_ = base::ASCIIToUTF16("John Doe"); + ShowPrompt(); + } + + void ShowPromptWithoutInferredName() { + inferred_name_ = base::ASCIIToUTF16(""); + ShowPrompt(); + } + + void AcceptWithInferredName() { controller_->OnNameAccepted(inferred_name_); } + + void AcceptWithEditedName() { + controller_->OnNameAccepted(base::ASCIIToUTF16("Edited Name")); + } + + protected: + std::unique_ptr<TestCardNameFixFlowView> test_card_name_fix_flow_view_; + std::unique_ptr<CardNameFixFlowControllerImpl> controller_; + base::string16 inferred_name_; + base::string16 accepted_name_; + base::WeakPtrFactory<CardNameFixFlowControllerImplGenericTest> + weak_ptr_factory_{this}; + + private: + void OnNameAccepted(const base::string16& name) { accepted_name_ = name; } + + void ShowPrompt() { + controller_->Show( + test_card_name_fix_flow_view_.get(), inferred_name_, + base::BindOnce( + &CardNameFixFlowControllerImplGenericTest::OnNameAccepted, + weak_ptr_factory_.GetWeakPtr())); + } + + DISALLOW_COPY_AND_ASSIGN(CardNameFixFlowControllerImplGenericTest); +}; + +class CardNameFixFlowControllerImplTest + : public CardNameFixFlowControllerImplGenericTest, + public testing::Test { + public: + CardNameFixFlowControllerImplTest() {} + ~CardNameFixFlowControllerImplTest() override {} + + void SetUp() override { + test_card_name_fix_flow_view_.reset(new TestCardNameFixFlowView()); + controller_.reset(new CardNameFixFlowControllerImpl()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(CardNameFixFlowControllerImplTest); +}; + +TEST_F(CardNameFixFlowControllerImplTest, LogShown) { + base::HistogramTester histogram_tester; + ShowPromptWithInferredName(); + + histogram_tester.ExpectUniqueSample( + "Autofill.CardholderNameFixFlowPrompt.Events", + AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_SHOWN, 1); +} + +TEST_F(CardNameFixFlowControllerImplTest, LogPrefilled) { + base::HistogramTester histogram_tester; + ShowPromptWithInferredName(); + + histogram_tester.ExpectBucketCount("Autofill.SaveCardCardholderNamePrefilled", + true, 1); +} + +TEST_F(CardNameFixFlowControllerImplTest, LogNotPrefilled) { + base::HistogramTester histogram_tester; + ShowPromptWithoutInferredName(); + + histogram_tester.ExpectBucketCount("Autofill.SaveCardCardholderNamePrefilled", + false, 1); +} + +TEST_F(CardNameFixFlowControllerImplTest, LogAccepted) { + base::HistogramTester histogram_tester; + ShowPromptWithInferredName(); + AcceptWithInferredName(); + + histogram_tester.ExpectBucketCount( + "Autofill.CardholderNameFixFlowPrompt.Events", + AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_ACCEPTED, 1); +} + +TEST_F(CardNameFixFlowControllerImplTest, LogUserAcceptedInferredName) { + base::HistogramTester histogram_tester; + ShowPromptWithInferredName(); + AcceptWithInferredName(); + + histogram_tester.ExpectBucketCount("Autofill.SaveCardCardholderNameWasEdited", + false, 1); +} + +TEST_F(CardNameFixFlowControllerImplTest, LogUserAcceptedEditedName) { + base::HistogramTester histogram_tester; + ShowPromptWithInferredName(); + AcceptWithEditedName(); + + histogram_tester.ExpectBucketCount("Autofill.SaveCardCardholderNameWasEdited", + true, 1); +} + +TEST_F(CardNameFixFlowControllerImplTest, LogDismissed) { + base::HistogramTester histogram_tester; + controller_->OnDismissed(); + + histogram_tester.ExpectBucketCount( + "Autofill.CardholderNameFixFlowPrompt.Events", + AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_DISMISSED, 1); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h new file mode 100644 index 00000000000..f9bf6cea366 --- /dev/null +++ b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h @@ -0,0 +1,26 @@ +// 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_H_ + +#include "base/macros.h" +#include "base/strings/string16.h" + +namespace autofill { + +// The cross-platform UI interface which prompts the user to confirm their name. +// This object is responsible for its own lifetime. +class CardNameFixFlowView { + public: + virtual void Show() = 0; + virtual void ControllerGone() = 0; + + protected: + virtual ~CardNameFixFlowView() = default; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_H_ diff --git a/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.cc b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.cc deleted file mode 100644 index 94d6dc8b052..00000000000 --- a/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2018 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/ui/payments/card_name_fix_flow_view_delegate_mobile.h" - -#include <utility> - -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "build/branding_buildflags.h" -#include "components/grit/components_scaled_resources.h" -#include "components/strings/grit/components_strings.h" -#include "ui/base/l10n/l10n_util.h" - -namespace autofill { - -CardNameFixFlowViewDelegateMobile::CardNameFixFlowViewDelegateMobile( - const base::string16& inferred_cardholder_name, - base::OnceCallback<void(const base::string16&)> upload_save_card_callback) - : inferred_cardholder_name_(inferred_cardholder_name), - upload_save_card_callback_(std::move(upload_save_card_callback)), - shown_(false), - had_user_interaction_(false) { - DCHECK(!upload_save_card_callback_.is_null()); - AutofillMetrics::LogSaveCardCardholderNamePrefilled( - !inferred_cardholder_name_.empty()); -} - -CardNameFixFlowViewDelegateMobile::~CardNameFixFlowViewDelegateMobile() { - if (shown_ && !had_user_interaction_) - AutofillMetrics::LogCardholderNameFixFlowPromptEvent( - AutofillMetrics:: - CARDHOLDER_NAME_FIX_FLOW_PROMPT_CLOSED_WITHOUT_INTERACTION); -} - -int CardNameFixFlowViewDelegateMobile::GetIconId() const { -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) - return IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER; -#else - return 0; -#endif -} - -base::string16 CardNameFixFlowViewDelegateMobile::GetTitleText() const { - return l10n_util::GetStringUTF16( - IDS_AUTOFILL_SAVE_CARD_CARDHOLDER_NAME_FIX_FLOW_HEADER); -} - -base::string16 CardNameFixFlowViewDelegateMobile::GetInferredCardHolderName() - const { - return inferred_cardholder_name_; -} - -base::string16 CardNameFixFlowViewDelegateMobile::GetSaveButtonLabel() const { - return l10n_util::GetStringUTF16( - IDS_AUTOFILL_FIX_FLOW_PROMPT_SAVE_CARD_LABEL); -} - -void CardNameFixFlowViewDelegateMobile::Accept(const base::string16& name) { - std::move(upload_save_card_callback_).Run(name); - AutofillMetrics::LogCardholderNameFixFlowPromptEvent( - AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_ACCEPTED); - had_user_interaction_ = true; - AutofillMetrics::LogSaveCardCardholderNameWasEdited( - inferred_cardholder_name_ != name); -} - -void CardNameFixFlowViewDelegateMobile::Dismissed() { - AutofillMetrics::LogCardholderNameFixFlowPromptEvent( - AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_DISMISSED); - had_user_interaction_ = true; -} - -void CardNameFixFlowViewDelegateMobile::Shown() { - AutofillMetrics::LogCardholderNameFixFlowPromptEvent( - AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_SHOWN); - shown_ = true; -} - -} // namespace autofill diff --git a/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.h b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.h deleted file mode 100644 index 64415a44661..00000000000 --- a/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2018 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. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ - -#include <memory> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/strings/string16.h" -#include "components/autofill/core/browser/autofill_metrics.h" - -namespace autofill { - -// Enables the user to accept or deny cardholder name fix flow prompt. -// Only used on mobile. -class CardNameFixFlowViewDelegateMobile { - public: - CardNameFixFlowViewDelegateMobile( - const base::string16& inferred_cardholder_name, - base::OnceCallback<void(const base::string16&)> - upload_save_card_callback); - - ~CardNameFixFlowViewDelegateMobile(); - - int GetIconId() const; - base::string16 GetTitleText() const; - base::string16 GetInferredCardHolderName() const; - base::string16 GetSaveButtonLabel() const; - void Accept(const base::string16& name); - void Dismissed(); - void Shown(); - - private: - // Inferred cardholder name from Gaia account. - base::string16 inferred_cardholder_name_; - - // The callback to save the credit card to Google Payments once user accepts - // fix flow. - base::OnceCallback<void(const base::string16&)> upload_save_card_callback_; - - // Whether the prompt was shown to the user. - bool shown_; - - // Did the user ever explicitly accept or dismiss this prompt? - bool had_user_interaction_; - - DISALLOW_COPY_AND_ASSIGN(CardNameFixFlowViewDelegateMobile); -}; - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h index 8a33e40f7dd..e2df819d693 100644 --- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h +++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h @@ -33,6 +33,7 @@ class CardUnmaskPromptController { virtual bool ShouldRequestExpirationDate() const = 0; virtual bool CanStoreLocally() const = 0; virtual bool GetStoreLocallyStartState() const = 0; + virtual bool GetWebauthnOfferStartState() const = 0; virtual base::TimeDelta GetSuccessMessageDuration() const = 0; virtual AutofillClient::PaymentsRpcResult GetVerificationResult() const = 0; diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc index f4918d2ff28..14a43d4a1a5 100644 --- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc +++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc @@ -134,6 +134,16 @@ void CardUnmaskPromptControllerImpl::OnUnmaskPromptAccepted( pending_details_.should_store_pan = false; } + // The FIDO authentication checkbox is only shown when the local storage + // checkbox is not shown and the flag is turned on. If it is shown, then + // remember the last choice the user made on this device. + if (base::FeatureList::IsEnabled( + features::kAutofillCreditCardAuthentication) && + !CanStoreLocally()) { + pref_service_->SetBoolean( + prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, enable_fido_auth); + } + // There is a chance the delegate has disappeared (i.e. tab closed) before the // unmask response came in. Avoid a crash. if (delegate_) @@ -219,6 +229,11 @@ bool CardUnmaskPromptControllerImpl::GetStoreLocallyStartState() const { prefs::kAutofillWalletImportStorageCheckboxState); } +bool CardUnmaskPromptControllerImpl::GetWebauthnOfferStartState() const { + return pref_service_->GetBoolean( + prefs::kAutofillCreditCardFidoAuthOfferCheckboxState); +} + bool CardUnmaskPromptControllerImpl::InputCvcIsValid( const base::string16& input_text) const { base::string16 trimmed_text; diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h index dd174d24644..345de4c8d82 100644 --- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h +++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h @@ -48,6 +48,7 @@ class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController { bool ShouldRequestExpirationDate() const override; bool CanStoreLocally() const override; bool GetStoreLocallyStartState() const override; + bool GetWebauthnOfferStartState() const override; bool InputCvcIsValid(const base::string16& input_text) const override; bool InputExpirationIsValid(const base::string16& month, const base::string16& year) const override; diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc index 418ac6c636e..56275f7a2dc 100644 --- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc +++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc @@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/autofill_test_utils.h" @@ -105,11 +106,12 @@ class CardUnmaskPromptControllerImplGenericTest { AutofillClient::UNMASK_FOR_AUTOFILL, delegate_->GetWeakPtr()); } - void ShowPromptAndSimulateResponse(bool should_store_pan) { + void ShowPromptAndSimulateResponse(bool should_store_pan, + bool enable_fido_auth) { ShowPrompt(); controller_->OnUnmaskPromptAccepted(ASCIIToUTF16("444"), ASCIIToUTF16("01"), ASCIIToUTF16("2050"), should_store_pan, - /*enable_fido_auth=*/false); + enable_fido_auth); EXPECT_EQ(should_store_pan, pref_service_->GetBoolean( prefs::kAutofillWalletImportStorageCheckboxState)); @@ -121,6 +123,7 @@ class CardUnmaskPromptControllerImplGenericTest { value); } + base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<TestCardUnmaskPromptView> test_unmask_prompt_view_; std::unique_ptr<TestingPrefServiceSimple> pref_service_; std::unique_ptr<TestCardUnmaskPromptController> controller_; @@ -144,6 +147,8 @@ class CardUnmaskPromptControllerImplTest delegate_.reset(new TestCardUnmaskDelegate()); pref_service_->registry()->RegisterBooleanPref( prefs::kAutofillWalletImportStorageCheckboxState, false); + pref_service_->registry()->RegisterBooleanPref( + prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true); } private: @@ -169,7 +174,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogClosedNoAttempts) { } TEST_F(CardUnmaskPromptControllerImplTest, LogClosedAbandonUnmasking) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnUnmaskDialogClosed(); @@ -180,7 +186,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogClosedAbandonUnmasking) { } TEST_F(CardUnmaskPromptControllerImplTest, LogClosedFailedToUnmaskRetriable) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); controller_->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE); base::HistogramTester histogram_tester; @@ -198,7 +205,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogClosedFailedToUnmaskRetriable) { TEST_F(CardUnmaskPromptControllerImplTest, LogClosedFailedToUnmaskNonRetriable) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); controller_->OnVerificationResult(AutofillClient::PERMANENT_FAILURE); base::HistogramTester histogram_tester; @@ -216,7 +224,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, } TEST_F(CardUnmaskPromptControllerImplTest, LogUnmaskedCardFirstAttempt) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnVerificationResult(AutofillClient::SUCCESS); @@ -232,7 +241,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogUnmaskedCardFirstAttempt) { } TEST_F(CardUnmaskPromptControllerImplTest, LogUnmaskedCardAfterFailure) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); controller_->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE); controller_->OnUnmaskPromptAccepted(ASCIIToUTF16("444"), ASCIIToUTF16("01"), ASCIIToUTF16("2050"), @@ -249,7 +259,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogUnmaskedCardAfterFailure) { } TEST_F(CardUnmaskPromptControllerImplTest, LogSavedCardLocally) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/true); + ShowPromptAndSimulateResponse(/*should_store_pan=*/true, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnVerificationResult(AutofillClient::SUCCESS); @@ -262,7 +273,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogSavedCardLocally) { TEST_F(CardUnmaskPromptControllerImplTest, LogDidOptIn) { SetImportCheckboxState(false); - ShowPromptAndSimulateResponse(/*should_store_pan=*/true); + ShowPromptAndSimulateResponse(/*should_store_pan=*/true, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnUnmaskDialogClosed(); @@ -273,7 +285,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogDidOptIn) { TEST_F(CardUnmaskPromptControllerImplTest, LogDidNotOptIn) { SetImportCheckboxState(false); - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnUnmaskDialogClosed(); @@ -284,7 +297,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogDidNotOptIn) { TEST_F(CardUnmaskPromptControllerImplTest, LogDidOptOut) { SetImportCheckboxState(true); - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnUnmaskDialogClosed(); @@ -295,7 +309,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogDidOptOut) { TEST_F(CardUnmaskPromptControllerImplTest, LogDidNotOptOut) { SetImportCheckboxState(true); - ShowPromptAndSimulateResponse(/*should_store_pan=*/true); + ShowPromptAndSimulateResponse(/*should_store_pan=*/true, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnUnmaskDialogClosed(); @@ -306,7 +321,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogDidNotOptOut) { TEST_F(CardUnmaskPromptControllerImplTest, DontLogForHiddenCheckbox) { controller_->set_can_store_locally(false); - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnUnmaskDialogClosed(); @@ -324,6 +340,22 @@ TEST_F(CardUnmaskPromptControllerImplTest, DontLogForHiddenCheckbox) { AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_NOT_OPT_OUT, 0); } +TEST_F(CardUnmaskPromptControllerImplTest, + FidoAuthOfferCheckboxStatePersistent) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillCreditCardAuthentication); + controller_->set_can_store_locally(false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/true); + EXPECT_TRUE(pref_service_->GetBoolean( + prefs::kAutofillCreditCardFidoAuthOfferCheckboxState)); + + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); + EXPECT_FALSE(pref_service_->GetBoolean( + prefs::kAutofillCreditCardFidoAuthOfferCheckboxState)); +} + TEST_F(CardUnmaskPromptControllerImplTest, LogDurationNoAttempts) { ShowPrompt(); base::HistogramTester histogram_tester; @@ -336,7 +368,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogDurationNoAttempts) { } TEST_F(CardUnmaskPromptControllerImplTest, LogDurationAbandonUnmasking) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnUnmaskDialogClosed(); @@ -347,7 +380,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogDurationAbandonUnmasking) { } TEST_F(CardUnmaskPromptControllerImplTest, LogDurationFailedToUnmaskRetriable) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); controller_->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE); base::HistogramTester histogram_tester; @@ -360,7 +394,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogDurationFailedToUnmaskRetriable) { TEST_F(CardUnmaskPromptControllerImplTest, LogDurationFailedToUnmaskNonRetriable) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); controller_->OnVerificationResult(AutofillClient::PERMANENT_FAILURE); base::HistogramTester histogram_tester; @@ -372,7 +407,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, } TEST_F(CardUnmaskPromptControllerImplTest, LogDurationCardFirstAttempt) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnVerificationResult(AutofillClient::SUCCESS); @@ -385,7 +421,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogDurationCardFirstAttempt) { TEST_F(CardUnmaskPromptControllerImplTest, LogDurationUnmaskedCardAfterFailure) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); controller_->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE); controller_->OnUnmaskPromptAccepted( base::ASCIIToUTF16("444"), base::ASCIIToUTF16("01"), @@ -402,7 +439,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, } TEST_F(CardUnmaskPromptControllerImplTest, LogTimeBeforeAbandonUnmasking) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnUnmaskDialogClosed(); @@ -412,7 +450,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogTimeBeforeAbandonUnmasking) { } TEST_F(CardUnmaskPromptControllerImplTest, LogRealPanResultSuccess) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnVerificationResult(AutofillClient::SUCCESS); @@ -422,7 +461,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogRealPanResultSuccess) { } TEST_F(CardUnmaskPromptControllerImplTest, LogRealPanTryAgainFailure) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE); @@ -433,7 +473,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogRealPanTryAgainFailure) { } TEST_F(CardUnmaskPromptControllerImplTest, LogUnmaskingDurationResultSuccess) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnVerificationResult(AutofillClient::SUCCESS); @@ -446,7 +487,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogUnmaskingDurationResultSuccess) { TEST_F(CardUnmaskPromptControllerImplTest, LogUnmaskingDurationTryAgainFailure) { - ShowPromptAndSimulateResponse(/*should_store_pan=*/false); + ShowPromptAndSimulateResponse(/*should_store_pan=*/false, + /*enable_fido_auth=*/false); base::HistogramTester histogram_tester; controller_->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE); diff --git a/chromium/components/autofill/core/browser/ui/popup_item_ids.h b/chromium/components/autofill/core/browser/ui/popup_item_ids.h index 917f68981fb..52193d51e05 100644 --- a/chromium/components/autofill/core/browser/ui/popup_item_ids.h +++ b/chromium/components/autofill/core/browser/ui/popup_item_ids.h @@ -25,9 +25,8 @@ enum PopupItemId { POPUP_ITEM_ID_USERNAME_ENTRY = -11, POPUP_ITEM_ID_CREATE_HINT = -12, POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY = -13, - POPUP_ITEM_ID_GOOGLE_PAY_BRANDING = -14, - POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY = -15, - POPUP_ITEM_ID_SHOW_ACCOUNT_CARDS = -16, + POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY = -14, + POPUP_ITEM_ID_SHOW_ACCOUNT_CARDS = -15, }; } // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc index 7ae1e1cadbc..66e412c2b9f 100644 --- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc @@ -23,7 +23,7 @@ #include "components/autofill/core/browser/webdata/autofill_entry.h" #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h" -#include "components/sync/base/hash_util.h" +#include "components/sync/base/client_tag_hash.h" #include "components/sync/model/data_batch.h" #include "components/sync/model/data_type_activation_request.h" #include "components/sync/model/metadata_batch.h" @@ -245,7 +245,7 @@ class AutocompleteSyncBridgeTest : public testing::Test { const AutofillSpecifics& specifics) { auto data = std::make_unique<EntityData>(); *data->specifics.mutable_autofill() = specifics; - data->client_tag_hash = syncer::GenerateSyncableHash( + data->client_tag_hash = syncer::ClientTagHash::FromUnhashed( syncer::AUTOFILL, bridge()->GetClientTag(*data)); return data; } @@ -293,7 +293,7 @@ class AutocompleteSyncBridgeTest : public testing::Test { private: ScopedTempDir temp_dir_; - base::test::TaskEnvironment task_environment_; + base::test::SingleThreadTaskEnvironment task_environment_; testing::NiceMock<MockAutofillWebDataBackend> backend_; AutofillTable table_; WebDatabase db_; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.cc index eeda7a580d9..d2489486839 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.cc @@ -14,11 +14,12 @@ namespace browser_sync { AutofillProfileModelTypeController::AutofillProfileModelTypeController( - std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk, + std::unique_ptr<syncer::ModelTypeControllerDelegate> + delegate_for_full_sync_mode, PrefService* pref_service, syncer::SyncService* sync_service) : ModelTypeController(syncer::AUTOFILL_PROFILE, - std::move(delegate_on_disk)), + std::move(delegate_for_full_sync_mode)), pref_service_(pref_service), sync_service_(sync_service) { pref_registrar_.Init(pref_service_); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.h b/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.h index ed684b9e63e..9ff3493d283 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_model_type_controller.h @@ -24,7 +24,8 @@ namespace browser_sync { class AutofillProfileModelTypeController : public syncer::ModelTypeController { public: AutofillProfileModelTypeController( - std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate_on_disk, + std::unique_ptr<syncer::ModelTypeControllerDelegate> + delegate_for_full_sync_mode, PrefService* pref_service, syncer::SyncService* sync_service); ~AutofillProfileModelTypeController() override; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc index e0579be7e08..0ebf17dc2c8 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc @@ -28,7 +28,7 @@ #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h" #include "components/autofill/core/common/autofill_constants.h" -#include "components/sync/base/hash_util.h" +#include "components/sync/base/client_tag_hash.h" #include "components/sync/model/data_batch.h" #include "components/sync/model/data_type_activation_request.h" #include "components/sync/model/entity_data.h" @@ -296,7 +296,7 @@ class AutofillProfileSyncBridgeTest : public testing::Test { const AutofillProfileSpecifics& specifics) { auto data = std::make_unique<EntityData>(); *data->specifics.mutable_autofill_profile() = specifics; - data->client_tag_hash = syncer::GenerateSyncableHash( + data->client_tag_hash = syncer::ClientTagHash::FromUnhashed( syncer::AUTOFILL_PROFILE, bridge()->GetClientTag(*data)); return data; } @@ -321,7 +321,7 @@ class AutofillProfileSyncBridgeTest : public testing::Test { private: autofill::TestAutofillClock test_clock_; ScopedTempDir temp_dir_; - base::test::TaskEnvironment task_environment_; + base::test::SingleThreadTaskEnvironment task_environment_; testing::NiceMock<MockAutofillWebDataBackend> backend_; AutofillTable table_; WebDatabase db_; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc index 0ca087cdd24..997d51b187b 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc @@ -14,7 +14,7 @@ #include "components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h" #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/common/autofill_constants.h" -#include "components/sync/base/hash_util.h" +#include "components/sync/base/client_tag_hash.h" #include "components/sync/model/entity_data.h" #include "components/sync/protocol/sync.pb.h" #include "testing/gtest/include/gtest/gtest.h" @@ -50,8 +50,8 @@ std::unique_ptr<EntityData> SpecificsToEntity( const std::string& client_tag) { auto data = std::make_unique<syncer::EntityData>(); *data->specifics.mutable_autofill_wallet() = specifics; - data->client_tag_hash = - syncer::GenerateSyncableHash(syncer::AUTOFILL_WALLET_DATA, client_tag); + data->client_tag_hash = syncer::ClientTagHash::FromUnhashed( + syncer::AUTOFILL_WALLET_DATA, client_tag); return data; } diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc index df8bf08bddc..c6448b452e4 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc @@ -410,7 +410,8 @@ bool AutofillTable::CreateTablesIfNecessary() { InitMaskedCreditCardsTable() && InitUnmaskedCreditCardsTable() && InitServerCardMetadataTable() && InitServerAddressesTable() && InitServerAddressMetadataTable() && InitAutofillSyncMetadataTable() && - InitModelTypeStateTable() && InitPaymentsCustomerDataTable()); + InitModelTypeStateTable() && InitPaymentsCustomerDataTable() && + InitPaymentsUPIVPATable()); } bool AutofillTable::IsSyncable() { @@ -1640,6 +1641,21 @@ bool AutofillTable::GetPaymentsCustomerData( return s.Succeeded(); } +bool AutofillTable::InsertVPA(const std::string& vpa) { + sql::Transaction transaction(db_); + if (!transaction.Begin()) + return false; + + sql::Statement insert_vpa_statement( + db_->GetUniqueStatement("INSERT INTO payments_upi_vpa (vpa) VALUES (?)")); + insert_vpa_statement.BindString(0, vpa); + insert_vpa_statement.Run(); + + transaction.Commit(); + + return db_->GetLastChangeCount() > 0; +} + bool AutofillTable::ClearAllServerData() { sql::Transaction transaction(db_); if (!transaction.Begin()) @@ -1843,36 +1859,6 @@ bool AutofillTable::RemoveOriginURLsModifiedBetween( return true; } -bool AutofillTable::GetAutofillProfilesInTrash( - std::vector<std::string>* guids) { - guids->clear(); - - sql::Statement s( - db_->GetUniqueStatement("SELECT guid FROM autofill_profiles_trash")); - - while (s.Step()) { - std::string guid = s.ColumnString(0); - guids->push_back(guid); - } - - return s.Succeeded(); -} - -bool AutofillTable::EmptyAutofillProfilesTrash() { - sql::Statement s( - db_->GetUniqueStatement("DELETE FROM autofill_profiles_trash")); - - return s.Run(); -} - -bool AutofillTable::AddAutofillGUIDToTrash(const std::string& guid) { - sql::Statement s(db_->GetUniqueStatement( - "INSERT INTO autofill_profiles_trash (guid) VALUES (?)")); - s.BindString(0, guid); - - return s.Run(); -} - bool AutofillTable::ClearAutofillProfiles() { sql::Statement s1(db_->GetUniqueStatement("DELETE FROM autofill_profiles")); @@ -2609,11 +2595,12 @@ bool AutofillTable::MigrateToVersion78AddModelTypeColumns() { "SELECT ?, storage_key, value " "FROM autofill_sync_metadata")); // Note: This uses the *wrong* ID for the ModelType - instead of - // |syncer::ModelTypeToHistogramInt|, this should be |GetKeyValueForModelType| + // |syncer::ModelTypeHistogramValue|, this should be |GetKeyValueForModelType| // aka |syncer::ModelTypeToStableIdentifier|. But at this point, fixing it // here would just make an even bigger mess. Instead, we clean this up in the // migration to version 81. See also crbug.com/895826. - insert_metadata.BindInt(0, syncer::ModelTypeToHistogramInt(syncer::AUTOFILL)); + insert_metadata.BindInt( + 0, static_cast<int>(syncer::ModelTypeHistogramValue(syncer::AUTOFILL))); // Prior to this migration, the table was a singleton, containing only one // entry with id being hard-coded to 1. @@ -2622,7 +2609,8 @@ bool AutofillTable::MigrateToVersion78AddModelTypeColumns() { "(model_type, value) SELECT ?, value " "FROM autofill_model_type_state WHERE id=1")); // Note: Like above, this uses the *wrong* ID for the ModelType. - insert_state.BindInt(0, syncer::ModelTypeToHistogramInt(syncer::AUTOFILL)); + insert_state.BindInt( + 0, static_cast<int>(syncer::ModelTypeHistogramValue(syncer::AUTOFILL))); if (!insert_metadata.Run() || !insert_state.Run()) { return false; @@ -2655,7 +2643,7 @@ bool AutofillTable::MigrateToVersion81CleanUpWrongModelTypeData() { // in trying to recover anything, since by now it'll have been redownloaded // anyway. const int bad_model_type_id = - syncer::ModelTypeToHistogramInt(syncer::AUTOFILL); + static_cast<int>(syncer::ModelTypeHistogramValue(syncer::AUTOFILL)); DCHECK_NE(bad_model_type_id, GetKeyValueForModelType(syncer::AUTOFILL)); sql::Transaction transaction(db_); @@ -3139,4 +3127,15 @@ bool AutofillTable::InitPaymentsCustomerDataTable() { return true; } +bool AutofillTable::InitPaymentsUPIVPATable() { + if (!db_->DoesTableExist("payments_upi_vpa")) { + if (!db_->Execute("CREATE TABLE payments_upi_vpa (" + "vpa VARCHAR)")) { + NOTREACHED(); + return false; + } + } + return true; +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.h b/chromium/components/autofill/core/browser/webdata/autofill_table.h index 0e212e999ac..ba29c015768 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_table.h @@ -177,6 +177,8 @@ struct PaymentsCustomerData; // exp_month Expiration month: 1-12 // exp_year Four-digit year: 2017 // bank_name Issuer bank name of the credit card. +// cloud_token_data Opaque identifier for the cloud token associated with +// the payment instrument. // // unmasked_credit_cards // When a masked credit credit card is unmasked and the @@ -273,6 +275,11 @@ struct PaymentsCustomerData; // Contains Google Payments customer data. // // customer_id A string representing the Google Payments customer id. +// +// payments_upi_vpa Contains saved UPI/VPA payment data. +// https://en.wikipedia.org/wiki/Unified_Payments_Interface +// +// vpa_id A string representing the VPA value. class AutofillTable : public WebDatabaseTable, public syncer::SyncMetadataStore { @@ -433,6 +440,9 @@ class AutofillTable : public WebDatabaseTable, bool GetPaymentsCustomerData( std::unique_ptr<PaymentsCustomerData>* customer_data) const; + // Adds |vpa| to the saved VPA ids. + bool InsertVPA(const std::string& vpa); + // Deletes all data from the server card and profile tables. Returns true if // any data was deleted, false if not (so false means "commit not needed" // rather than "error"). @@ -466,17 +476,6 @@ class AutofillTable : public WebDatabaseTable, const base::Time& delete_end, std::vector<std::unique_ptr<AutofillProfile>>* profiles); - // Retrieves all profiles in the database that have been deleted since last - // "empty" of the trash. - bool GetAutofillProfilesInTrash(std::vector<std::string>* guids); - - // Empties the Autofill profiles "trash can". - bool EmptyAutofillProfilesTrash(); - - // Retrieves all profiles in the database that have been deleted since last - // "empty" of the trash. - bool AddAutofillGUIDToTrash(const std::string& guid); - // Clear all profiles. bool ClearAutofillProfiles(); @@ -635,6 +634,7 @@ class AutofillTable : public WebDatabaseTable, bool InitAutofillSyncMetadataTable(); bool InitModelTypeStateTable(); bool InitPaymentsCustomerDataTable(); + bool InitPaymentsUPIVPATable(); std::unique_ptr<AutofillTableEncryptor> autofill_table_encryptor_; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc index cd9547ff280..54444cbb468 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc @@ -85,14 +85,15 @@ std::ostream& operator<<(std::ostream& os, const AutofillChange& change) { namespace { typedef std::set<AutofillEntry, - bool (*)(const AutofillEntry&, const AutofillEntry&)> AutofillEntrySet; + bool (*)(const AutofillEntry&, const AutofillEntry&)> + AutofillEntrySet; typedef AutofillEntrySet::iterator AutofillEntrySetIterator; bool CompareAutofillEntries(const AutofillEntry& a, const AutofillEntry& b) { - return std::tie(a.key().name(), a.key().value(), - a.date_created(), a.date_last_used()) < - std::tie(b.key().name(), b.key().value(), - b.date_created(), b.date_last_used()); + return std::tie(a.key().name(), a.key().value(), a.date_created(), + a.date_last_used()) < + std::tie(b.key().name(), b.key().value(), b.date_created(), + b.date_last_used()); } AutofillEntry MakeAutofillEntry(const std::string& name, @@ -160,7 +161,7 @@ class AutofillTableTest : public testing::Test { }; TEST_F(AutofillTableTest, Autofill) { - Time t1 = Time::Now(); + Time t1 = AutofillClock::Now(); // Simulate the submission of a handful of entries in a field called "Name", // some more often than others. @@ -168,25 +169,25 @@ TEST_F(AutofillTableTest, Autofill) { FormFieldData field; field.name = ASCIIToUTF16("Name"); field.value = ASCIIToUTF16("Superman"); - base::Time now = base::Time::Now(); + base::Time now = AutofillClock::Now(); base::TimeDelta two_seconds = base::TimeDelta::FromSeconds(2); EXPECT_TRUE(table_->AddFormFieldValue(field, &changes)); std::vector<AutofillEntry> v; for (int i = 0; i < 5; ++i) { field.value = ASCIIToUTF16("Clark Kent"); - EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, - now + i * two_seconds)); + EXPECT_TRUE( + table_->AddFormFieldValueTime(field, &changes, now + i * two_seconds)); } for (int i = 0; i < 3; ++i) { field.value = ASCIIToUTF16("Clark Sutter"); - EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, - now + i * two_seconds)); + EXPECT_TRUE( + table_->AddFormFieldValueTime(field, &changes, now + i * two_seconds)); } for (int i = 0; i < 2; ++i) { field.name = ASCIIToUTF16("Favorite Color"); field.value = ASCIIToUTF16("Green"); - EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, - now + i * two_seconds)); + EXPECT_TRUE( + table_->AddFormFieldValueTime(field, &changes, now + i * two_seconds)); } // We have added the name Clark Kent 5 times, so count should be 5. @@ -205,8 +206,8 @@ TEST_F(AutofillTableTest, Autofill) { // in the second argument means it should return all suggestions for a name // no matter what they start with. The order that the names occur in the list // should be decreasing order by count. - EXPECT_TRUE(table_->GetFormValuesForElementName( - ASCIIToUTF16("Name"), base::string16(), &v, 6)); + EXPECT_TRUE(table_->GetFormValuesForElementName(ASCIIToUTF16("Name"), + base::string16(), &v, 6)); EXPECT_EQ(3U, v.size()); if (v.size() == 3) { EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0].key().value()); @@ -216,8 +217,8 @@ TEST_F(AutofillTableTest, Autofill) { // If we query again limiting the list size to 1, we should only get the most // frequent entry. - EXPECT_TRUE(table_->GetFormValuesForElementName( - ASCIIToUTF16("Name"), base::string16(), &v, 1)); + EXPECT_TRUE(table_->GetFormValuesForElementName(ASCIIToUTF16("Name"), + base::string16(), &v, 1)); EXPECT_EQ(1U, v.size()); if (v.size() == 1) { EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0].key().value()); @@ -225,8 +226,8 @@ TEST_F(AutofillTableTest, Autofill) { // Querying for suggestions given a prefix is case-insensitive, so the prefix // "cLa" shoud get suggestions for both Clarks. - EXPECT_TRUE(table_->GetFormValuesForElementName( - ASCIIToUTF16("Name"), ASCIIToUTF16("cLa"), &v, 6)); + EXPECT_TRUE(table_->GetFormValuesForElementName(ASCIIToUTF16("Name"), + ASCIIToUTF16("cLa"), &v, 6)); EXPECT_EQ(2U, v.size()); if (v.size() == 2) { EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0].key().value()); @@ -239,18 +240,18 @@ TEST_F(AutofillTableTest, Autofill) { EXPECT_TRUE(table_->RemoveFormElementsAddedBetween(t1, Time(), &changes)); const AutofillChange kExpectedChanges[] = { - AutofillChange(AutofillChange::REMOVE, - AutofillKey(ASCIIToUTF16("Name"), - ASCIIToUTF16("Superman"))), - AutofillChange(AutofillChange::REMOVE, - AutofillKey(ASCIIToUTF16("Name"), - ASCIIToUTF16("Clark Kent"))), - AutofillChange(AutofillChange::REMOVE, - AutofillKey(ASCIIToUTF16("Name"), - ASCIIToUTF16("Clark Sutter"))), - AutofillChange(AutofillChange::REMOVE, - AutofillKey(ASCIIToUTF16("Favorite Color"), - ASCIIToUTF16("Green"))), + AutofillChange( + AutofillChange::REMOVE, + AutofillKey(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"))), + AutofillChange( + AutofillChange::REMOVE, + AutofillKey(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Kent"))), + AutofillChange( + AutofillChange::REMOVE, + AutofillKey(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Sutter"))), + AutofillChange( + AutofillChange::REMOVE, + AutofillKey(ASCIIToUTF16("Favorite Color"), ASCIIToUTF16("Green"))), }; EXPECT_EQ(base::size(kExpectedChanges), changes.size()); for (size_t i = 0; i < base::size(kExpectedChanges); ++i) { @@ -260,8 +261,8 @@ TEST_F(AutofillTableTest, Autofill) { EXPECT_EQ(0, GetAutofillEntryCount(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Kent"), db_.get())); - EXPECT_TRUE(table_->GetFormValuesForElementName( - ASCIIToUTF16("Name"), base::string16(), &v, 6)); + EXPECT_TRUE(table_->GetFormValuesForElementName(ASCIIToUTF16("Name"), + base::string16(), &v, 6)); EXPECT_EQ(0U, v.size()); // Now add some values with empty strings. @@ -282,8 +283,8 @@ TEST_F(AutofillTableTest, Autofill) { // They should be stored normally as the DB layer does not check for empty // values. v.clear(); - EXPECT_TRUE(table_->GetFormValuesForElementName( - ASCIIToUTF16("blank"), base::string16(), &v, 10)); + EXPECT_TRUE(table_->GetFormValuesForElementName(ASCIIToUTF16("blank"), + base::string16(), &v, 10)); EXPECT_EQ(4U, v.size()); } @@ -329,21 +330,16 @@ TEST_F(AutofillTableTest, Autofill_GetCountOfValuesContainedBetween) { // This test makes time comparisons that are precise to a microsecond, but the // database uses the time_t format which is only precise to a second. // Make sure we use timestamps rounded to a second. - Time begin = Time::FromTimeT(Time::Now().ToTimeT()); + Time begin = Time::FromTimeT(AutofillClock::Now().ToTimeT()); Time now = begin; TimeDelta second = TimeDelta::FromSeconds(1); struct Entry { const char* name; const char* value; - } entries[] = { - { "Alter ego", "Superman" }, - { "Name", "Superman" }, - { "Name", "Clark Kent" }, - { "Name", "Superman" }, - { "Name", "Clark Sutter" }, - { "Nomen", "Clark Kent" } - }; + } entries[] = {{"Alter ego", "Superman"}, {"Name", "Superman"}, + {"Name", "Clark Kent"}, {"Name", "Superman"}, + {"Name", "Clark Sutter"}, {"Nomen", "Clark Kent"}}; for (Entry entry : entries) { FormFieldData field; @@ -356,30 +352,29 @@ TEST_F(AutofillTableTest, Autofill_GetCountOfValuesContainedBetween) { // While the entry "Alter ego" : "Superman" is entirely contained within // the first second, the value "Superman" itself appears in another entry, // so it is not contained. - EXPECT_EQ(0, table_->GetCountOfValuesContainedBetween( - begin, begin + second)); + EXPECT_EQ(0, table_->GetCountOfValuesContainedBetween(begin, begin + second)); // No values are entirely contained within the first three seconds either // (note that the second time constraint is exclusive). - EXPECT_EQ(0, table_->GetCountOfValuesContainedBetween( - begin, begin + 3 * second)); + EXPECT_EQ( + 0, table_->GetCountOfValuesContainedBetween(begin, begin + 3 * second)); // Only "Superman" is entirely contained within the first four seconds. - EXPECT_EQ(1, table_->GetCountOfValuesContainedBetween( - begin, begin + 4 * second)); + EXPECT_EQ( + 1, table_->GetCountOfValuesContainedBetween(begin, begin + 4 * second)); // "Clark Kent" and "Clark Sutter" are contained between the first // and seventh second. - EXPECT_EQ(2, table_->GetCountOfValuesContainedBetween( - begin + second, begin + 7 * second)); + EXPECT_EQ(2, table_->GetCountOfValuesContainedBetween(begin + second, + begin + 7 * second)); // Beginning from the third second, "Clark Kent" is not contained. - EXPECT_EQ(1, table_->GetCountOfValuesContainedBetween( - begin + 3 * second, begin + 7 * second)); + EXPECT_EQ(1, table_->GetCountOfValuesContainedBetween(begin + 3 * second, + begin + 7 * second)); // We have three distinct values total. - EXPECT_EQ(3, table_->GetCountOfValuesContainedBetween( - begin, begin + 7 * second)); + EXPECT_EQ( + 3, table_->GetCountOfValuesContainedBetween(begin, begin + 7 * second)); // And we should get the same result for unlimited time interval. EXPECT_EQ(3, table_->GetCountOfValuesContainedBetween(Time(), Time::Max())); @@ -388,8 +383,8 @@ TEST_F(AutofillTableTest, Autofill_GetCountOfValuesContainedBetween) { EXPECT_EQ(3, table_->GetCountOfValuesContainedBetween(Time(), Time())); // An interval that does not fully contain any entries returns zero. - EXPECT_EQ(0, table_->GetCountOfValuesContainedBetween( - begin + second, begin + 2 * second)); + EXPECT_EQ(0, table_->GetCountOfValuesContainedBetween(begin + second, + begin + 2 * second)); // So does an interval which has no intersection with any entry. EXPECT_EQ(0, table_->GetCountOfValuesContainedBetween(Time(), begin)); @@ -397,7 +392,7 @@ TEST_F(AutofillTableTest, Autofill_GetCountOfValuesContainedBetween) { TEST_F(AutofillTableTest, Autofill_RemoveBetweenChanges) { TimeDelta one_day(TimeDelta::FromDays(1)); - Time t1 = Time::Now(); + Time t1 = AutofillClock::Now(); Time t2 = t1 + one_day; AutofillChangeList changes; @@ -410,24 +405,24 @@ TEST_F(AutofillTableTest, Autofill_RemoveBetweenChanges) { changes.clear(); EXPECT_TRUE(table_->RemoveFormElementsAddedBetween(t1, t2, &changes)); ASSERT_EQ(1U, changes.size()); - EXPECT_EQ(AutofillChange(AutofillChange::UPDATE, - AutofillKey(ASCIIToUTF16("Name"), - ASCIIToUTF16("Superman"))), + EXPECT_EQ(AutofillChange( + AutofillChange::UPDATE, + AutofillKey(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"))), changes[0]); changes.clear(); EXPECT_TRUE( table_->RemoveFormElementsAddedBetween(t2, t2 + one_day, &changes)); ASSERT_EQ(1U, changes.size()); - EXPECT_EQ(AutofillChange(AutofillChange::REMOVE, - AutofillKey(ASCIIToUTF16("Name"), - ASCIIToUTF16("Superman"))), + EXPECT_EQ(AutofillChange( + AutofillChange::REMOVE, + AutofillKey(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"))), changes[0]); } TEST_F(AutofillTableTest, Autofill_AddChanges) { TimeDelta one_day(TimeDelta::FromDays(1)); - Time t1 = Time::Now(); + Time t1 = AutofillClock::Now(); Time t2 = t1 + one_day; AutofillChangeList changes; @@ -436,18 +431,17 @@ TEST_F(AutofillTableTest, Autofill_AddChanges) { field.value = ASCIIToUTF16("Superman"); EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, t1)); ASSERT_EQ(1U, changes.size()); - EXPECT_EQ(AutofillChange(AutofillChange::ADD, - AutofillKey(ASCIIToUTF16("Name"), - ASCIIToUTF16("Superman"))), + EXPECT_EQ(AutofillChange( + AutofillChange::ADD, + AutofillKey(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"))), changes[0]); changes.clear(); - EXPECT_TRUE( - table_->AddFormFieldValueTime(field, &changes, t2)); + EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, t2)); ASSERT_EQ(1U, changes.size()); - EXPECT_EQ(AutofillChange(AutofillChange::UPDATE, - AutofillKey(ASCIIToUTF16("Name"), - ASCIIToUTF16("Superman"))), + EXPECT_EQ(AutofillChange( + AutofillChange::UPDATE, + AutofillKey(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"))), changes[0]); } @@ -489,8 +483,7 @@ TEST_F(AutofillTableTest, Autofill_GetAutofillTimestamps) { Time date_created, date_last_used; ASSERT_TRUE(table_->GetAutofillTimestamps(ASCIIToUTF16("foo"), - ASCIIToUTF16("bar"), - &date_created, + ASCIIToUTF16("bar"), &date_created, &date_last_used)); EXPECT_EQ(Time::FromTimeT(1), date_created); EXPECT_EQ(Time::FromTimeT(2), date_last_used); @@ -555,7 +548,7 @@ TEST_F(AutofillTableTest, Autofill_UpdateReplace) { } TEST_F(AutofillTableTest, Autofill_UpdateDontReplace) { - Time t = Time::Now(); + Time t = AutofillClock::Now(); AutofillEntry existing( MakeAutofillEntry("Name", "Superman", t.ToTimeT(), -1)); @@ -573,15 +566,14 @@ TEST_F(AutofillTableTest, Autofill_UpdateDontReplace) { std::vector<AutofillEntry> all_entries; ASSERT_TRUE(table_->GetAllAutofillEntries(&all_entries)); ASSERT_EQ(2U, all_entries.size()); - AutofillEntrySet expected_entries(all_entries.begin(), - all_entries.end(), + AutofillEntrySet expected_entries(all_entries.begin(), all_entries.end(), CompareAutofillEntries); EXPECT_EQ(1U, expected_entries.count(existing)); EXPECT_EQ(1U, expected_entries.count(entry)); } TEST_F(AutofillTableTest, Autofill_AddFormFieldValues) { - Time t = Time::Now(); + Time t = AutofillClock::Now(); // Add multiple values for "firstname" and "lastname" names. Test that only // first value of each gets added. Related to security issue: @@ -610,10 +602,10 @@ TEST_F(AutofillTableTest, Autofill_AddFormFieldValues) { ASSERT_EQ(2U, changes.size()); EXPECT_EQ(changes[0], AutofillChange(AutofillChange::ADD, AutofillKey(ASCIIToUTF16("firstname"), - ASCIIToUTF16("Joe")))); + ASCIIToUTF16("Joe")))); EXPECT_EQ(changes[1], AutofillChange(AutofillChange::ADD, AutofillKey(ASCIIToUTF16("lastname"), - ASCIIToUTF16("Smith")))); + ASCIIToUTF16("Smith")))); std::vector<AutofillEntry> all_entries; ASSERT_TRUE(table_->GetAllAutofillEntries(&all_entries)); @@ -641,9 +633,8 @@ TEST_F(AutofillTableTest, EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get())); changes.clear(); - EXPECT_TRUE(table_->RemoveFormElementsAddedBetween(base::Time::FromTimeT(51), - base::Time::FromTimeT(60), - &changes)); + EXPECT_TRUE(table_->RemoveFormElementsAddedBetween( + base::Time::FromTimeT(51), base::Time::FromTimeT(60), &changes)); EXPECT_TRUE(changes.empty()); EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get())); } @@ -669,9 +660,8 @@ TEST_F(AutofillTableTest, EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get())); changes.clear(); - EXPECT_TRUE(table_->RemoveFormElementsAddedBetween(base::Time::FromTimeT(40), - base::Time::FromTimeT(50), - &changes)); + EXPECT_TRUE(table_->RemoveFormElementsAddedBetween( + base::Time::FromTimeT(40), base::Time::FromTimeT(50), &changes)); EXPECT_TRUE(changes.empty()); EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get())); } @@ -697,9 +687,8 @@ TEST_F(AutofillTableTest, EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get())); changes.clear(); - EXPECT_TRUE(table_->RemoveFormElementsAddedBetween(base::Time::FromTimeT(10), - base::Time::FromTimeT(51), - &changes)); + EXPECT_TRUE(table_->RemoveFormElementsAddedBetween( + base::Time::FromTimeT(10), base::Time::FromTimeT(51), &changes)); ASSERT_EQ(1U, changes.size()); EXPECT_EQ(AutofillChange(AutofillChange::REMOVE, AutofillKey(field.name, field.value)), @@ -728,18 +717,16 @@ TEST_F(AutofillTableTest, EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get())); changes.clear(); - EXPECT_TRUE(table_->RemoveFormElementsAddedBetween(base::Time::FromTimeT(40), - base::Time::FromTimeT(60), - &changes)); + EXPECT_TRUE(table_->RemoveFormElementsAddedBetween( + base::Time::FromTimeT(40), base::Time::FromTimeT(60), &changes)); ASSERT_EQ(1U, changes.size()); EXPECT_EQ(AutofillChange(AutofillChange::UPDATE, AutofillKey(field.name, field.value)), changes[0]); EXPECT_EQ(4, GetAutofillEntryCount(field.name, field.value, db_.get())); base::Time date_created, date_last_used; - EXPECT_TRUE( - table_->GetAutofillTimestamps(field.name, field.value, - &date_created, &date_last_used)); + EXPECT_TRUE(table_->GetAutofillTimestamps(field.name, field.value, + &date_created, &date_last_used)); EXPECT_EQ(base::Time::FromTimeT(10), date_created); EXPECT_EQ(base::Time::FromTimeT(39), date_last_used); } @@ -765,25 +752,23 @@ TEST_F(AutofillTableTest, EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get())); changes.clear(); - EXPECT_TRUE(table_->RemoveFormElementsAddedBetween(base::Time::FromTimeT(40), - base::Time::FromTimeT(80), - &changes)); + EXPECT_TRUE(table_->RemoveFormElementsAddedBetween( + base::Time::FromTimeT(40), base::Time::FromTimeT(80), &changes)); ASSERT_EQ(1U, changes.size()); EXPECT_EQ(AutofillChange(AutofillChange::UPDATE, AutofillKey(field.name, field.value)), changes[0]); EXPECT_EQ(2, GetAutofillEntryCount(field.name, field.value, db_.get())); base::Time date_created, date_last_used; - EXPECT_TRUE( - table_->GetAutofillTimestamps(field.name, field.value, - &date_created, &date_last_used)); + EXPECT_TRUE(table_->GetAutofillTimestamps(field.name, field.value, + &date_created, &date_last_used)); EXPECT_EQ(base::Time::FromTimeT(80), date_created); EXPECT_EQ(base::Time::FromTimeT(90), date_last_used); } TEST_F(AutofillTableTest, Autofill_RemoveFormElementsAddedBetween_OlderThan30Days) { - const base::Time kNow = base::Time::Now(); + const base::Time kNow = AutofillClock::Now(); const base::Time k29DaysOld = kNow - base::TimeDelta::FromDays(29); const base::Time k30DaysOld = kNow - base::TimeDelta::FromDays(30); const base::Time k31DaysOld = kNow - base::TimeDelta::FromDays(31); @@ -880,9 +865,9 @@ TEST_F(AutofillTableTest, AutofillProfile) { home_profile.SetClientValidityFromBitfieldValue(6); home_profile.set_is_client_validity_states_updated(true); - Time pre_creation_time = Time::Now(); + Time pre_creation_time = AutofillClock::Now(); EXPECT_TRUE(table_->AddAutofillProfile(home_profile)); - Time post_creation_time = Time::Now(); + Time post_creation_time = AutofillClock::Now(); // Get the 'Home' profile. std::unique_ptr<AutofillProfile> db_profile = @@ -907,9 +892,9 @@ TEST_F(AutofillTableTest, AutofillProfile) { ASCIIToUTF16("5678 Bottom Street")); billing_profile.SetRawInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("suite 3")); - pre_creation_time = Time::Now(); + pre_creation_time = AutofillClock::Now(); EXPECT_TRUE(table_->AddAutofillProfile(billing_profile)); - post_creation_time = Time::Now(); + post_creation_time = AutofillClock::Now(); // Get the 'Billing' profile. db_profile = table_->GetAutofillProfile(billing_profile.guid()); @@ -926,9 +911,9 @@ TEST_F(AutofillTableTest, AutofillProfile) { // Update the 'Billing' profile, name only. billing_profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane")); - Time pre_modification_time = Time::Now(); + Time pre_modification_time = AutofillClock::Now(); EXPECT_TRUE(table_->UpdateAutofillProfile(billing_profile)); - Time post_modification_time = Time::Now(); + Time post_modification_time = AutofillClock::Now(); db_profile = table_->GetAutofillProfile(billing_profile.guid()); ASSERT_TRUE(db_profile); EXPECT_EQ(billing_profile, *db_profile); @@ -937,10 +922,8 @@ TEST_F(AutofillTableTest, AutofillProfile) { s_billing_updated.BindString(0, billing_profile.guid()); ASSERT_TRUE(s_billing_updated.is_valid()); ASSERT_TRUE(s_billing_updated.Step()); - EXPECT_GE(s_billing_updated.ColumnInt64(0), - pre_modification_time.ToTimeT()); - EXPECT_LE(s_billing_updated.ColumnInt64(0), - post_modification_time.ToTimeT()); + EXPECT_GE(s_billing_updated.ColumnInt64(0), pre_modification_time.ToTimeT()); + EXPECT_LE(s_billing_updated.ColumnInt64(0), post_modification_time.ToTimeT()); EXPECT_FALSE(s_billing_updated.Step()); // Update the 'Billing' profile with non-default data. The specific values are @@ -965,9 +948,9 @@ TEST_F(AutofillTableTest, AutofillProfile) { billing_profile.SetClientValidityFromBitfieldValue(54); billing_profile.set_is_client_validity_states_updated(true); - Time pre_modification_time_2 = Time::Now(); + Time pre_modification_time_2 = AutofillClock::Now(); EXPECT_TRUE(table_->UpdateAutofillProfile(billing_profile)); - Time post_modification_time_2 = Time::Now(); + Time post_modification_time_2 = AutofillClock::Now(); db_profile = table_->GetAutofillProfile(billing_profile.guid()); ASSERT_TRUE(db_profile); EXPECT_EQ(billing_profile, *db_profile); @@ -989,87 +972,6 @@ TEST_F(AutofillTableTest, AutofillProfile) { EXPECT_FALSE(db_profile); } -TEST_F(AutofillTableTest, AutofillProfileTrash) { - std::vector<std::string> guids; - table_->GetAutofillProfilesInTrash(&guids); - EXPECT_TRUE(guids.empty()); - - ASSERT_TRUE(table_->AddAutofillGUIDToTrash( - "00000000-0000-0000-0000-000000000000")); - ASSERT_TRUE(table_->AddAutofillGUIDToTrash( - "00000000-0000-0000-0000-000000000001")); - ASSERT_TRUE(table_->GetAutofillProfilesInTrash(&guids)); - EXPECT_EQ(2UL, guids.size()); - EXPECT_EQ("00000000-0000-0000-0000-000000000000", guids[0]); - EXPECT_EQ("00000000-0000-0000-0000-000000000001", guids[1]); - - ASSERT_TRUE(table_->EmptyAutofillProfilesTrash()); - ASSERT_TRUE(table_->GetAutofillProfilesInTrash(&guids)); - EXPECT_TRUE(guids.empty()); -} - -TEST_F(AutofillTableTest, AutofillProfileTrashInteraction) { - std::vector<std::string> guids; - table_->GetAutofillProfilesInTrash(&guids); - EXPECT_TRUE(guids.empty()); - - AutofillProfile profile; - profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); - profile.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("Q.")); - profile.SetRawInfo(NAME_LAST, ASCIIToUTF16("Smith")); - profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("js@smith.xyz")); - profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1 Main St")); - profile.SetRawInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Los Angeles")); - profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA")); - profile.SetRawInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("90025")); - profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US")); - - // Mark this profile as in the trash. This stops |AddAutofillProfile| from - // adding it. - EXPECT_TRUE(table_->AddAutofillGUIDToTrash(profile.guid())); - EXPECT_TRUE(table_->AddAutofillProfile(profile)); - std::unique_ptr<AutofillProfile> added_profile = - table_->GetAutofillProfile(profile.guid()); - EXPECT_FALSE(added_profile); - - // Add the profile for real this time. - EXPECT_TRUE(table_->EmptyAutofillProfilesTrash()); - EXPECT_TRUE(table_->GetAutofillProfilesInTrash(&guids)); - EXPECT_TRUE(guids.empty()); - EXPECT_TRUE(table_->AddAutofillProfile(profile)); - added_profile = table_->GetAutofillProfile(profile.guid()); - EXPECT_TRUE(added_profile); - - // Mark this profile as in the trash. This stops |UpdateAutofillProfileMulti| - // from updating it. In normal operation a profile should not be both in the - // trash and in the profiles table simultaneously. - EXPECT_TRUE(table_->AddAutofillGUIDToTrash(profile.guid())); - profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane")); - EXPECT_TRUE(table_->UpdateAutofillProfile(profile)); - std::unique_ptr<AutofillProfile> updated_profile = - table_->GetAutofillProfile(profile.guid()); - EXPECT_TRUE(updated_profile); - EXPECT_EQ(ASCIIToUTF16("John"), updated_profile->GetRawInfo(NAME_FIRST)); - - // Try to delete the trashed profile. This stops |RemoveAutofillProfile| from - // deleting it. In normal operation deletion is done by migration step, and - // removal from trash is done by |WebDataService|. |RemoveAutofillProfile| - // does remove the item from the trash if it is found however, so that if - // other clients remove it (via Sync say) then it is gone and doesn't need to - // be processed further by |WebDataService|. - EXPECT_TRUE(table_->RemoveAutofillProfile(profile.guid())); - std::unique_ptr<AutofillProfile> removed_profile = - table_->GetAutofillProfile(profile.guid()); - EXPECT_TRUE(removed_profile); - EXPECT_FALSE(table_->IsAutofillGUIDInTrash(profile.guid())); - - // Check that emptying the trash now allows removal to occur. - EXPECT_TRUE(table_->EmptyAutofillProfilesTrash()); - EXPECT_TRUE(table_->RemoveAutofillProfile(profile.guid())); - removed_profile = table_->GetAutofillProfile(profile.guid()); - EXPECT_FALSE(removed_profile); -} - TEST_F(AutofillTableTest, CreditCard) { // Add a 'Work' credit card. CreditCard work_creditcard; @@ -1082,9 +984,9 @@ TEST_F(AutofillTableTest, CreditCard) { work_creditcard.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2013")); - Time pre_creation_time = Time::Now(); + Time pre_creation_time = AutofillClock::Now(); EXPECT_TRUE(table_->AddCreditCard(work_creditcard)); - Time post_creation_time = Time::Now(); + Time post_creation_time = AutofillClock::Now(); // Get the 'Work' credit card. std::unique_ptr<CreditCard> db_creditcard = @@ -1113,9 +1015,9 @@ TEST_F(AutofillTableTest, CreditCard) { target_creditcard.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2012")); - pre_creation_time = Time::Now(); + pre_creation_time = AutofillClock::Now(); EXPECT_TRUE(table_->AddCreditCard(target_creditcard)); - post_creation_time = Time::Now(); + post_creation_time = AutofillClock::Now(); db_creditcard = table_->GetCreditCard(target_creditcard.guid()); ASSERT_TRUE(db_creditcard); EXPECT_EQ(target_creditcard, *db_creditcard); @@ -1134,9 +1036,9 @@ TEST_F(AutofillTableTest, CreditCard) { target_creditcard.set_origin("Interactive Autofill dialog"); target_creditcard.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("Charles Grady")); - Time pre_modification_time = Time::Now(); + Time pre_modification_time = AutofillClock::Now(); EXPECT_TRUE(table_->UpdateCreditCard(target_creditcard)); - Time post_modification_time = Time::Now(); + Time post_modification_time = AutofillClock::Now(); db_creditcard = table_->GetCreditCard(target_creditcard.guid()); ASSERT_TRUE(db_creditcard); EXPECT_EQ(target_creditcard, *db_creditcard); @@ -1194,7 +1096,7 @@ TEST_F(AutofillTableTest, UpdateAutofillProfile) { table_->AddAutofillProfile(profile); // Set a mocked value for the profile's creation time. - const time_t kMockCreationDate = Time::Now().ToTimeT() - 13; + const time_t kMockCreationDate = AutofillClock::Now().ToTimeT() - 13; sql::Statement s_mock_creation_date( db_->GetSQLConnection()->GetUniqueStatement( "UPDATE autofill_profiles SET date_modified = ?")); @@ -1231,7 +1133,7 @@ TEST_F(AutofillTableTest, UpdateAutofillProfile) { EXPECT_FALSE(s_updated.Step()); // Set a mocked value for the profile's modification time. - const time_t mock_modification_date = Time::Now().ToTimeT() - 7; + const time_t mock_modification_date = AutofillClock::Now().ToTimeT() - 7; sql::Statement s_mock_modification_date( db_->GetSQLConnection()->GetUniqueStatement( "UPDATE autofill_profiles SET date_modified = ?")); @@ -1265,7 +1167,7 @@ TEST_F(AutofillTableTest, UpdateCreditCard) { table_->AddCreditCard(credit_card); // Set a mocked value for the credit card's creation time. - const time_t kMockCreationDate = Time::Now().ToTimeT() - 13; + const time_t kMockCreationDate = AutofillClock::Now().ToTimeT() - 13; sql::Statement s_mock_creation_date( db_->GetSQLConnection()->GetUniqueStatement( "UPDATE credit_cards SET date_modified = ?")); @@ -1302,7 +1204,7 @@ TEST_F(AutofillTableTest, UpdateCreditCard) { EXPECT_FALSE(s_updated.Step()); // Set a mocked value for the credit card's modification time. - const time_t mock_modification_date = Time::Now().ToTimeT() - 7; + const time_t mock_modification_date = AutofillClock::Now().ToTimeT() - 7; sql::Statement s_mock_modification_date( db_->GetSQLConnection()->GetUniqueStatement( "UPDATE credit_cards SET date_modified = ?")); @@ -1344,7 +1246,7 @@ TEST_F(AutofillTableTest, UpdateProfileOriginOnly) { table_->AddAutofillProfile(profile); // Set a mocked value for the profile's creation time. - const time_t kMockCreationDate = Time::Now().ToTimeT() - 13; + const time_t kMockCreationDate = AutofillClock::Now().ToTimeT() - 13; sql::Statement s_mock_creation_date( db_->GetSQLConnection()->GetUniqueStatement( "UPDATE autofill_profiles SET date_modified = ?")); @@ -1391,7 +1293,7 @@ TEST_F(AutofillTableTest, UpdateCreditCardOriginOnly) { table_->AddCreditCard(credit_card); // Set a mocked value for the credit card's creation time. - const time_t kMockCreationDate = Time::Now().ToTimeT() - 13; + const time_t kMockCreationDate = AutofillClock::Now().ToTimeT() - 13; sql::Statement s_mock_creation_date( db_->GetSQLConnection()->GetUniqueStatement( "UPDATE credit_cards SET date_modified = ?")); @@ -1725,8 +1627,8 @@ TEST_F(AutofillTableTest, RemoveOriginURLsModifiedBetween) { // Remove all origin URLs set in the bounded time range [21,27). std::vector<std::unique_ptr<AutofillProfile>> profiles; - table_->RemoveOriginURLsModifiedBetween( - Time::FromTimeT(21), Time::FromTimeT(27), &profiles); + table_->RemoveOriginURLsModifiedBetween(Time::FromTimeT(21), + Time::FromTimeT(27), &profiles); ASSERT_EQ(1UL, profiles.size()); EXPECT_EQ("00000000-0000-0000-0000-000000000001", profiles[0]->guid()); sql::Statement s_autofill_profiles_bounded( @@ -1751,8 +1653,7 @@ TEST_F(AutofillTableTest, RemoveOriginURLsModifiedBetween) { EXPECT_EQ(std::string(), s_credit_cards_bounded.ColumnString(1)); ASSERT_TRUE(s_credit_cards_bounded.Step()); EXPECT_EQ(27, s_credit_cards_bounded.ColumnInt64(0)); - EXPECT_EQ("https://www.example.com/", - s_credit_cards_bounded.ColumnString(1)); + EXPECT_EQ("https://www.example.com/", s_credit_cards_bounded.ColumnString(1)); ASSERT_TRUE(s_credit_cards_bounded.Step()); EXPECT_EQ(37, s_credit_cards_bounded.ColumnInt64(0)); EXPECT_EQ(kSettingsOrigin, s_credit_cards_bounded.ColumnString(1)); @@ -1774,9 +1675,8 @@ TEST_F(AutofillTableTest, RemoveOriginURLsModifiedBetween) { ASSERT_TRUE(s_autofill_profiles_all.Step()); EXPECT_EQ(31, s_autofill_profiles_all.ColumnInt64(0)); EXPECT_EQ(kSettingsOrigin, s_autofill_profiles_all.ColumnString(1)); - sql::Statement s_credit_cards_all( - db_->GetSQLConnection()->GetUniqueStatement( - "SELECT date_modified, origin FROM credit_cards")); + sql::Statement s_credit_cards_all(db_->GetSQLConnection()->GetUniqueStatement( + "SELECT date_modified, origin FROM credit_cards")); ASSERT_TRUE(s_credit_cards_all.is_valid()); ASSERT_TRUE(s_credit_cards_all.Step()); EXPECT_EQ(17, s_credit_cards_all.ColumnInt64(0)); @@ -1798,19 +1698,19 @@ TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_NoResults) { TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_OneResult) { AutofillChangeList changes; - std::map<std::string, std::vector<Time> > name_value_times_map; + std::map<std::string, std::vector<Time>> name_value_times_map; time_t start = 0; std::vector<Time> timestamps1; FormFieldData field; field.name = ASCIIToUTF16("Name"); field.value = ASCIIToUTF16("Superman"); - EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, - Time::FromTimeT(start))); + EXPECT_TRUE( + table_->AddFormFieldValueTime(field, &changes, Time::FromTimeT(start))); timestamps1.push_back(Time::FromTimeT(start)); std::string key1("NameSuperman"); name_value_times_map.insert( - std::pair<std::string, std::vector<Time> >(key1, timestamps1)); + std::pair<std::string, std::vector<Time>>(key1, timestamps1)); AutofillEntrySet expected_entries(CompareAutofillEntries); AutofillKey ak1(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman")); @@ -1828,30 +1728,30 @@ TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_OneResult) { TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_TwoDistinct) { AutofillChangeList changes; - std::map<std::string, std::vector<Time> > name_value_times_map; + std::map<std::string, std::vector<Time>> name_value_times_map; time_t start = 0; std::vector<Time> timestamps1; FormFieldData field; field.name = ASCIIToUTF16("Name"); field.value = ASCIIToUTF16("Superman"); - EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, - Time::FromTimeT(start))); + EXPECT_TRUE( + table_->AddFormFieldValueTime(field, &changes, Time::FromTimeT(start))); timestamps1.push_back(Time::FromTimeT(start)); std::string key1("NameSuperman"); name_value_times_map.insert( - std::pair<std::string, std::vector<Time> >(key1, timestamps1)); + std::pair<std::string, std::vector<Time>>(key1, timestamps1)); ++start; std::vector<Time> timestamps2; field.name = ASCIIToUTF16("Name"); field.value = ASCIIToUTF16("Clark Kent"); - EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, - Time::FromTimeT(start))); + EXPECT_TRUE( + table_->AddFormFieldValueTime(field, &changes, Time::FromTimeT(start))); timestamps2.push_back(Time::FromTimeT(start)); std::string key2("NameClark Kent"); name_value_times_map.insert( - std::pair<std::string, std::vector<Time> >(key2, timestamps2)); + std::pair<std::string, std::vector<Time>>(key2, timestamps2)); AutofillEntrySet expected_entries(CompareAutofillEntries); AutofillKey ak1(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman")); @@ -1872,7 +1772,7 @@ TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_TwoDistinct) { TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_TwoSame) { AutofillChangeList changes; - std::map<std::string, std::vector<Time> > name_value_times_map; + std::map<std::string, std::vector<Time>> name_value_times_map; std::vector<Time> timestamps; time_t start = 0; @@ -1880,14 +1780,14 @@ TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_TwoSame) { FormFieldData field; field.name = ASCIIToUTF16("Name"); field.value = ASCIIToUTF16("Superman"); - EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes, - Time::FromTimeT(start))); + EXPECT_TRUE( + table_->AddFormFieldValueTime(field, &changes, Time::FromTimeT(start))); timestamps.push_back(Time::FromTimeT(start)); } std::string key("NameSuperman"); name_value_times_map.insert( - std::pair<std::string, std::vector<Time> >(key, timestamps)); + std::pair<std::string, std::vector<Time>>(key, timestamps)); AutofillEntrySet expected_entries(CompareAutofillEntries); AutofillKey ak1(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman")); @@ -1980,8 +1880,7 @@ TEST_F(AutofillTableTest, SetGetServerCards) { inputs[0].SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2020")); inputs[0].SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("4111111111111111")); - inputs.push_back( - CreditCard(CreditCard::MASKED_SERVER_CARD, "b456")); + inputs.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "b456")); inputs[1].SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("Rick Roman")); inputs[1].SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("12")); inputs[1].SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("1997")); @@ -2019,7 +1918,7 @@ TEST_F(AutofillTableTest, SetGetRemoveServerCardMetadata) { AutofillMetadata input; input.id = "server id"; input.use_count = 50; - input.use_date = Time::Now(); + input.use_date = AutofillClock::Now(); input.billing_address_id = "billing id"; EXPECT_TRUE(table_->AddServerCardMetadata(input)); @@ -2042,7 +1941,7 @@ TEST_F(AutofillTableTest, SetGetRemoveServerAddressMetadata) { AutofillMetadata input; input.id = "server id"; input.use_count = 50; - input.use_date = Time::Now(); + input.use_date = AutofillClock::Now(); input.has_converted = true; table_->AddServerAddressMetadata(input); @@ -2065,7 +1964,7 @@ TEST_F(AutofillTableTest, AddUpdateServerAddressMetadata) { AutofillMetadata input; input.id = "server id"; input.use_count = 50; - input.use_date = Time::Now(); + input.use_date = AutofillClock::Now(); input.has_converted = true; ASSERT_TRUE(table_->AddServerAddressMetadata(input)); @@ -2096,7 +1995,7 @@ TEST_F(AutofillTableTest, AddUpdateServerCardMetadata) { AutofillMetadata input; input.id = "server id"; input.use_count = 50; - input.use_date = Time::Now(); + input.use_date = AutofillClock::Now(); input.billing_address_id = "billing id"; ASSERT_TRUE(table_->AddServerCardMetadata(input)); @@ -2192,7 +2091,7 @@ TEST_F(AutofillTableTest, RemoveWrongServerCardMetadata) { AutofillMetadata input; input.id = "server id"; input.use_count = 50; - input.use_date = Time::Now(); + input.use_date = AutofillClock::Now(); input.billing_address_id = "billing id"; table_->AddServerCardMetadata(input); @@ -2261,7 +2160,7 @@ TEST_F(AutofillTableTest, SetServerCardsData_ExistingMetadata) { AutofillMetadata input; input.id = "server id"; input.use_count = 50; - input.use_date = Time::Now(); + input.use_date = AutofillClock::Now(); input.billing_address_id = "billing id"; table_->AddServerCardMetadata(input); @@ -2318,7 +2217,7 @@ TEST_F(AutofillTableTest, SetServerAddressesData_ExistingMetadata) { AutofillMetadata input; input.id = "server id"; input.use_count = 50; - input.use_date = Time::Now(); + input.use_date = AutofillClock::Now(); input.has_converted = true; table_->AddServerAddressMetadata(input); @@ -2340,7 +2239,7 @@ TEST_F(AutofillTableTest, RemoveWrongServerAddressMetadata) { AutofillMetadata input; input.id = "server id"; input.use_count = 50; - input.use_date = Time::Now(); + input.use_date = AutofillClock::Now(); input.has_converted = true; table_->AddServerAddressMetadata(input); @@ -2371,8 +2270,7 @@ TEST_F(AutofillTableTest, MaskUnmaskServerCards) { // Unmask the number. The full number should be available. base::string16 full_number(ASCIIToUTF16("4111111111111111")); - ASSERT_TRUE(table_->UnmaskServerCreditCard(inputs[0], - full_number)); + ASSERT_TRUE(table_->UnmaskServerCreditCard(inputs[0], full_number)); std::vector<std::unique_ptr<CreditCard>> outputs; table_->GetServerCreditCards(&outputs); @@ -2601,7 +2499,7 @@ TEST_F(AutofillTableTest, SetServerProfileUpdateUsageStats) { // Update the usage stats; make sure they're reflected in GetServerProfiles. inputs.back().set_use_count(4U); - inputs.back().set_use_date(base::Time::Now()); + inputs.back().set_use_date(AutofillClock::Now()); table_->UpdateServerAddressMetadata(inputs.back()); table_->GetServerProfiles(&outputs); ASSERT_EQ(1u, outputs.size()); @@ -2627,7 +2525,7 @@ TEST_F(AutofillTableTest, SetServerProfileUpdateUsageStats) { TEST_F(AutofillTableTest, DeleteUnmaskedCard) { // This isn't the exact unmasked time, since the database will use the // current time that it is called. The code below has to be approximate. - base::Time unmasked_time = base::Time::Now(); + base::Time unmasked_time = AutofillClock::Now(); // Add a masked card. base::string16 masked_number = ASCIIToUTF16("1111"); @@ -2666,7 +2564,7 @@ TEST_F(AutofillTableTest, DeleteUnmaskedCard) { // Delete data in the range of the last 24 hours. // Fudge |now| to make sure it's strictly greater than the |now| that // the database uses. - base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(1); + base::Time now = AutofillClock::Now() + base::TimeDelta::FromSeconds(1); ASSERT_TRUE(table_->RemoveAutofillDataModifiedBetween( now - base::TimeDelta::FromDays(1), now, &profiles, &credit_cards)); @@ -2775,7 +2673,7 @@ TEST_P(GetFormValuesTest, GetFormValuesForElementName_SubstringMatchEnabled) { << "suggestion = " << test_case.field_suggestion[0] << ", contents = " << test_case.field_contents); - Time t1 = Time::Now(); + Time t1 = AutofillClock::Now(); // Simulate the submission of a handful of entries in a field called "Name". AutofillChangeList changes; @@ -3102,4 +3000,16 @@ TEST_F(AutofillTableTest, RemoveOrphanAutofillTableRows) { EXPECT_FALSE(s_autofill_profile_phones.Step()); } +TEST_F(AutofillTableTest, VPA) { + EXPECT_TRUE(table_->InsertVPA("name@indianbank")); + + sql::Statement s_inspect(db_->GetSQLConnection()->GetUniqueStatement( + "SELECT vpa FROM payments_upi_vpa")); + + ASSERT_TRUE(s_inspect.is_valid()); + ASSERT_TRUE(s_inspect.Step()); + EXPECT_GE(s_inspect.ColumnString(0), "name@indianbank"); + EXPECT_FALSE(s_inspect.Step()); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc index eeae78ff20d..0f78f82f872 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc @@ -29,7 +29,7 @@ #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h" #include "components/autofill/core/common/autofill_constants.h" -#include "components/sync/base/hash_util.h" +#include "components/sync/base/client_tag_hash.h" #include "components/sync/model/data_batch.h" #include "components/sync/model/entity_data.h" #include "components/sync/model/mock_model_type_change_processor.h" @@ -353,7 +353,7 @@ class AutofillWalletMetadataSyncBridgeTest : public testing::Test { bool is_deleted = false) { auto data = std::make_unique<EntityData>(); *data->specifics.mutable_wallet_metadata() = specifics; - data->client_tag_hash = syncer::GenerateSyncableHash( + data->client_tag_hash = syncer::ClientTagHash::FromUnhashed( syncer::AUTOFILL_WALLET_METADATA, bridge()->GetClientTag(*data)); if (is_deleted) { // Specifics had to be set in order to generate the client tag. Since @@ -451,7 +451,7 @@ class AutofillWalletMetadataSyncBridgeTest : public testing::Test { int response_version = 0; autofill::TestAutofillClock test_clock_; ScopedTempDir temp_dir_; - base::test::TaskEnvironment task_environment_; + base::test::SingleThreadTaskEnvironment task_environment_; testing::NiceMock<MockAutofillWebDataBackend> backend_; AutofillTable table_; WebDatabase db_; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc index 50741416fb7..12e7e536098 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc @@ -31,7 +31,7 @@ #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" #include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h" #include "components/autofill/core/common/autofill_constants.h" -#include "components/sync/base/hash_util.h" +#include "components/sync/base/client_tag_hash.h" #include "components/sync/driver/sync_driver_switches.h" #include "components/sync/model/entity_data.h" #include "components/sync/model/mock_model_type_change_processor.h" @@ -269,7 +269,7 @@ class AutofillWalletSyncBridgeTest : public testing::Test { const AutofillWalletSpecifics& specifics) { auto data = std::make_unique<EntityData>(); *data->specifics.mutable_autofill_wallet() = specifics; - data->client_tag_hash = syncer::GenerateSyncableHash( + data->client_tag_hash = syncer::ClientTagHash::FromUnhashed( syncer::AUTOFILL_WALLET_DATA, bridge()->GetClientTag(*data)); return data; } @@ -307,7 +307,7 @@ class AutofillWalletSyncBridgeTest : public testing::Test { private: autofill::TestAutofillClock test_clock_; ScopedTempDir temp_dir_; - base::test::TaskEnvironment task_environment_; + base::test::SingleThreadTaskEnvironment task_environment_; NiceMock<MockAutofillWebDataBackend> backend_; AutofillTable table_; WebDatabase db_; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc index 3573e2a2fc1..f7f343a4b7c 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc @@ -117,10 +117,6 @@ void AutofillWebDataBackendImpl::NotifyOfCreditCardChanged( void AutofillWebDataBackendImpl::NotifyOfMultipleAutofillChanges() { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); - // DB sequence notification. - for (auto& db_observer : db_observer_list_) - db_observer.AutofillMultipleChangedBySync(); - // UI sequence notification. ui_task_runner_->PostTask(FROM_HERE, on_changed_callback_); } @@ -157,11 +153,12 @@ void AutofillWebDataBackendImpl::ResetUserData() { } WebDatabase::State AutofillWebDataBackendImpl::AddFormElements( - const std::vector<FormFieldData>& fields, WebDatabase* db) { + const std::vector<FormFieldData>& fields, + WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); AutofillChangeList changes; - if (!AutofillTable::FromWebDatabase(db)->AddFormFieldValues( - fields, &changes)) { + if (!AutofillTable::FromWebDatabase(db)->AddFormFieldValues(fields, + &changes)) { NOTREACHED(); return WebDatabase::COMMIT_NOT_NEEDED; } @@ -211,7 +208,9 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveFormElementsAddedBetween( } WebDatabase::State AutofillWebDataBackendImpl::RemoveFormValueForElementName( - const base::string16& name, const base::string16& value, WebDatabase* db) { + const base::string16& name, + const base::string16& value, + WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); if (AutofillTable::FromWebDatabase(db)->RemoveFormElement(name, value)) { @@ -229,7 +228,8 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveFormValueForElementName( } WebDatabase::State AutofillWebDataBackendImpl::AddAutofillProfile( - const AutofillProfile& profile, WebDatabase* db) { + const AutofillProfile& profile, + WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); if (!AutofillTable::FromWebDatabase(db)->AddAutofillProfile(profile)) { NOTREACHED(); @@ -237,8 +237,8 @@ WebDatabase::State AutofillWebDataBackendImpl::AddAutofillProfile( } // Send GUID-based notification. - AutofillProfileChange change( - AutofillProfileChange::ADD, profile.guid(), &profile); + AutofillProfileChange change(AutofillProfileChange::ADD, profile.guid(), + &profile); for (auto& db_observer : db_observer_list_) db_observer.AutofillProfileChanged(change); @@ -253,7 +253,8 @@ WebDatabase::State AutofillWebDataBackendImpl::AddAutofillProfile( } WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillProfile( - const AutofillProfile& profile, WebDatabase* db) { + const AutofillProfile& profile, + WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); // Only perform the update if the profile exists. It is currently // valid to try to update a missing profile. We simply drop the write and @@ -269,8 +270,8 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillProfile( } // Send GUID-based notification. - AutofillProfileChange change( - AutofillProfileChange::UPDATE, profile.guid(), &profile); + AutofillProfileChange change(AutofillProfileChange::UPDATE, profile.guid(), + &profile); for (auto& db_observer : db_observer_list_) db_observer.AutofillProfileChanged(change); @@ -285,7 +286,8 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillProfile( } WebDatabase::State AutofillWebDataBackendImpl::RemoveAutofillProfile( - const std::string& guid, WebDatabase* db) { + const std::string& guid, + WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); std::unique_ptr<AutofillProfile> profile = AutofillTable::FromWebDatabase(db)->GetAutofillProfile(guid); @@ -352,8 +354,9 @@ AutofillWebDataBackendImpl::GetCountOfValuesContainedBetween( const base::Time& end, WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); - int value = AutofillTable::FromWebDatabase(db) - ->GetCountOfValuesContainedBetween(begin, end); + int value = + AutofillTable::FromWebDatabase(db)->GetCountOfValuesContainedBetween( + begin, end); return std::unique_ptr<WDTypedResult>( new WDResult<int>(AUTOFILL_VALUE_RESULT, value)); } @@ -362,15 +365,16 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillEntries( const std::vector<AutofillEntry>& autofill_entries, WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); - if (!AutofillTable::FromWebDatabase(db) - ->UpdateAutofillEntries(autofill_entries)) + if (!AutofillTable::FromWebDatabase(db)->UpdateAutofillEntries( + autofill_entries)) return WebDatabase::COMMIT_NOT_NEEDED; return WebDatabase::COMMIT_NEEDED; } WebDatabase::State AutofillWebDataBackendImpl::AddCreditCard( - const CreditCard& credit_card, WebDatabase* db) { + const CreditCard& credit_card, + WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); if (!AutofillTable::FromWebDatabase(db)->AddCreditCard(credit_card)) { NOTREACHED(); @@ -385,7 +389,8 @@ WebDatabase::State AutofillWebDataBackendImpl::AddCreditCard( } WebDatabase::State AutofillWebDataBackendImpl::UpdateCreditCard( - const CreditCard& credit_card, WebDatabase* db) { + const CreditCard& credit_card, + WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); // It is currently valid to try to update a missing profile. We simply drop // the write and the caller will detect this on the next refresh. @@ -407,7 +412,8 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateCreditCard( } WebDatabase::State AutofillWebDataBackendImpl::RemoveCreditCard( - const std::string& guid, WebDatabase* db) { + const std::string& guid, + WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); std::unique_ptr<CreditCard> card = AutofillTable::FromWebDatabase(db)->GetCreditCard(guid); @@ -470,16 +476,15 @@ WebDatabase::State AutofillWebDataBackendImpl::UnmaskServerCreditCard( const base::string16& full_number, WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); - if (AutofillTable::FromWebDatabase(db)->UnmaskServerCreditCard( - card, full_number)) + if (AutofillTable::FromWebDatabase(db)->UnmaskServerCreditCard(card, + full_number)) return WebDatabase::COMMIT_NEEDED; return WebDatabase::COMMIT_NOT_NEEDED; } -WebDatabase::State - AutofillWebDataBackendImpl::MaskServerCreditCard( - const std::string& id, - WebDatabase* db) { +WebDatabase::State AutofillWebDataBackendImpl::MaskServerCreditCard( + const std::string& id, + WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); if (AutofillTable::FromWebDatabase(db)->MaskServerCreditCard(id)) return WebDatabase::COMMIT_NEEDED; @@ -520,6 +525,15 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateServerAddressMetadata( return WebDatabase::COMMIT_NEEDED; } +WebDatabase::State AutofillWebDataBackendImpl::AddVPA(const std::string& vpa_id, + WebDatabase* db) { + DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); + + if (!AutofillTable::FromWebDatabase(db)->InsertVPA(vpa_id)) + return WebDatabase::COMMIT_NOT_NEEDED; + return WebDatabase::COMMIT_NEEDED; +} + std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetPaymentsCustomerData(WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); @@ -550,10 +564,10 @@ WebDatabase::State AutofillWebDataBackendImpl::ClearAllLocalData( } WebDatabase::State - AutofillWebDataBackendImpl::RemoveAutofillDataModifiedBetween( - const base::Time& delete_begin, - const base::Time& delete_end, - WebDatabase* db) { +AutofillWebDataBackendImpl::RemoveAutofillDataModifiedBetween( + const base::Time& delete_begin, + const base::Time& delete_end, + WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); std::vector<std::unique_ptr<AutofillProfile>> profiles; std::vector<std::unique_ptr<CreditCard>> credit_cards; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h index 16a0151ff85..0dbb45d2404 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h @@ -161,8 +161,7 @@ class AutofillWebDataBackendImpl WebDatabase* db); // Removes a credit card from the web database. Valid only for local cards. - WebDatabase::State RemoveCreditCard(const std::string& guid, - WebDatabase* db); + WebDatabase::State RemoveCreditCard(const std::string& guid, WebDatabase* db); // Adds a full server credit card to the web database. WebDatabase::State AddFullServerCreditCard(const CreditCard& credit_card, @@ -186,6 +185,8 @@ class AutofillWebDataBackendImpl WebDatabase::State UpdateServerAddressMetadata(const AutofillProfile& profile, WebDatabase* db); + WebDatabase::State AddVPA(const std::string& vpa_id, WebDatabase* db); + // Returns the PaymentsCustomerData from the database. std::unique_ptr<WDTypedResult> GetPaymentsCustomerData(WebDatabase* db); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc index 90f3917982b..6f9d4604f78 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc @@ -231,6 +231,11 @@ void AutofillWebDataService::MaskServerCreditCard(const std::string& id) { autofill_backend_, id)); } +void AutofillWebDataService::AddVPA(const std::string& vpa_id) { + wdbs_->ScheduleDBTask(FROM_HERE, Bind(&AutofillWebDataBackendImpl::AddVPA, + autofill_backend_, vpa_id)); +} + WebDataServiceBase::Handle AutofillWebDataService::GetPaymentsCustomerData( WebDataServiceConsumer* consumer) { return wdbs_->ScheduleDBTaskWithResult( diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h index 43184406221..a12c516e8cf 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h @@ -139,6 +139,9 @@ class AutofillWebDataService : public WebDataServiceBase { const base::string16& full_number); void MaskServerCreditCard(const std::string& id); + // Store a UPI/VPA value. + void AddVPA(const std::string& vpa_id); + // Initiates the request for Payments customer data. The method // OnWebDataServiceRequestDone of |consumer| gets called when the request is // finished, with the customer data included in the argument |result|. The diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h index 7fd955e98cc..60820bb1a51 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h @@ -23,13 +23,6 @@ class AutofillWebDataServiceObserverOnDBSequence { // the WebDatabase. virtual void CreditCardChanged(const CreditCardChange& change) {} - // Called on DB sequence when multiple Autofill entries have been modified by - // Sync. - // TODO(crbug.com/900607): Remove AutofillMultipleChangedBySync() from - // AutofillWebDataServiceObserverOnDBSequence once USS for wallet_metadata - // launches. - virtual void AutofillMultipleChangedBySync() {} - protected: virtual ~AutofillWebDataServiceObserverOnDBSequence() {} }; diff --git a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc index 8a3d73167f7..fbdec05751a 100644 --- a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc @@ -28,6 +28,7 @@ #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/form_field_data.h" #include "components/webdata/common/web_data_results.h" #include "components/webdata/common/web_data_service_base.h" @@ -48,7 +49,7 @@ using testing::ElementsAreArray; namespace { template <class T> -class AutofillWebDataServiceConsumer: public WebDataServiceConsumer { +class AutofillWebDataServiceConsumer : public WebDataServiceConsumer { public: AutofillWebDataServiceConsumer() : handle_(0) {} virtual ~AutofillWebDataServiceConsumer() {} @@ -82,8 +83,7 @@ ACTION_P(SignalEvent, event) { class MockAutofillWebDataServiceObserver : public AutofillWebDataServiceObserverOnDBSequence { public: - MOCK_METHOD1(AutofillEntriesChanged, - void(const AutofillChangeList& changes)); + MOCK_METHOD1(AutofillEntriesChanged, void(const AutofillChangeList& changes)); MOCK_METHOD1(AutofillProfileChanged, void(const AutofillProfileChange& change)); }; @@ -183,9 +183,8 @@ class WebDataServiceAutofillTest : public WebDataServiceTest { TEST_F(WebDataServiceAutofillTest, FormFillAdd) { const AutofillChange expected_changes[] = { - AutofillChange(AutofillChange::ADD, AutofillKey(name1_, value1_)), - AutofillChange(AutofillChange::ADD, AutofillKey(name2_, value2_)) - }; + AutofillChange(AutofillChange::ADD, AutofillKey(name1_, value1_)), + AutofillChange(AutofillChange::ADD, AutofillKey(name2_, value2_))}; // This will verify that the correct notification is triggered, // passing the correct list of autofill keys in the details. @@ -204,8 +203,8 @@ TEST_F(WebDataServiceAutofillTest, FormFillAdd) { AutofillWebDataServiceConsumer<std::vector<AutofillEntry>> consumer; WebDataServiceBase::Handle handle; static const int limit = 10; - handle = wds_->GetFormValuesForElementName( - name1_, base::string16(), limit, &consumer); + handle = wds_->GetFormValuesForElementName(name1_, base::string16(), limit, + &consumer); task_environment_.RunUntilIdle(); EXPECT_EQ(handle, consumer.handle()); ASSERT_EQ(1U, consumer.result().size()); @@ -226,8 +225,7 @@ TEST_F(WebDataServiceAutofillTest, FormFillRemoveOne) { // This will verify that the correct notification is triggered, // passing the correct list of autofill keys in the details. const AutofillChange expected_changes[] = { - AutofillChange(AutofillChange::REMOVE, AutofillKey(name1_, value1_)) - }; + AutofillChange(AutofillChange::REMOVE, AutofillKey(name1_, value1_))}; EXPECT_CALL(observer_, AutofillEntriesChanged(ElementsAreArray(expected_changes))) .WillOnce(SignalEvent(&done_event_)); @@ -239,7 +237,7 @@ TEST_F(WebDataServiceAutofillTest, FormFillRemoveOne) { TEST_F(WebDataServiceAutofillTest, FormFillRemoveMany) { TimeDelta one_day(TimeDelta::FromDays(1)); - Time t = Time::Now(); + Time t = AutofillClock::Now(); EXPECT_CALL(observer_, AutofillEntriesChanged(_)) .WillOnce(SignalEvent(&done_event_)); @@ -255,9 +253,8 @@ TEST_F(WebDataServiceAutofillTest, FormFillRemoveMany) { // This will verify that the correct notification is triggered, // passing the correct list of autofill keys in the details. const AutofillChange expected_changes[] = { - AutofillChange(AutofillChange::REMOVE, AutofillKey(name1_, value1_)), - AutofillChange(AutofillChange::REMOVE, AutofillKey(name2_, value2_)) - }; + AutofillChange(AutofillChange::REMOVE, AutofillKey(name1_, value1_)), + AutofillChange(AutofillChange::REMOVE, AutofillKey(name2_, value2_))}; EXPECT_CALL(observer_, AutofillEntriesChanged(ElementsAreArray(expected_changes))) .WillOnce(SignalEvent(&done_event_)); @@ -271,8 +268,8 @@ TEST_F(WebDataServiceAutofillTest, ProfileAdd) { AutofillProfile profile; // Check that GUID-based notification was sent. - const AutofillProfileChange expected_change( - AutofillProfileChange::ADD, profile.guid(), &profile); + const AutofillProfileChange expected_change(AutofillProfileChange::ADD, + profile.guid(), &profile); EXPECT_CALL(observer_, AutofillProfileChanged(expected_change)) .WillOnce(SignalEvent(&done_event_)); diff --git a/chromium/components/autofill/core/common/BUILD.gn b/chromium/components/autofill/core/common/BUILD.gn index 0bb58c919d6..2f096cab5d5 100644 --- a/chromium/components/autofill/core/common/BUILD.gn +++ b/chromium/components/autofill/core/common/BUILD.gn @@ -29,6 +29,8 @@ jumbo_static_library("common") { "autofill_regexes.h", "autofill_switches.cc", "autofill_switches.h", + "autofill_tick_clock.cc", + "autofill_tick_clock.h", "autofill_util.cc", "autofill_util.h", "form_data.cc", @@ -39,9 +41,10 @@ jumbo_static_library("common") { "form_field_data.h", "form_field_data_predictions.cc", "form_field_data_predictions.h", + "logging/log_buffer.cc", + "logging/log_buffer.h", "password_form.cc", "password_form.h", - "password_form_field_prediction_map.h", "password_form_fill_data.cc", "password_form_fill_data.h", "password_form_generation_data.cc", @@ -75,12 +78,15 @@ jumbo_static_library("common") { source_set("unit_tests") { testonly = true sources = [ + "autofill_internals/log_message_unittest.cc", + "autofill_internals/logging_scope_unittest.cc", "autofill_l10n_util_unittest.cc", "autofill_prefs_unittest.cc", "autofill_regexes_unittest.cc", "autofill_util_unittest.cc", "form_data_unittest.cc", "form_field_data_unittest.cc", + "logging/log_buffer_unittest.cc", "password_form_fill_data_unittest.cc", "save_password_progress_logger_unittest.cc", ] diff --git a/chromium/components/autofill/core/common/autofill_clock.cc b/chromium/components/autofill/core/common/autofill_clock.cc index 0336eb95132..60169c8c7fb 100644 --- a/chromium/components/autofill/core/common/autofill_clock.cc +++ b/chromium/components/autofill/core/common/autofill_clock.cc @@ -9,7 +9,7 @@ namespace autofill { namespace { -base::Clock* g_autofill_clock = nullptr; +const base::Clock* g_autofill_clock = nullptr; } // namespace // static @@ -25,7 +25,7 @@ void AutofillClock::SetClock() { } // static -void AutofillClock::SetTestClock(base::Clock* clock) { +void AutofillClock::SetTestClock(const base::Clock* clock) { DCHECK(clock); g_autofill_clock = clock; } diff --git a/chromium/components/autofill/core/common/autofill_clock.h b/chromium/components/autofill/core/common/autofill_clock.h index 651d9cdf496..2280d16851c 100644 --- a/chromium/components/autofill/core/common/autofill_clock.h +++ b/chromium/components/autofill/core/common/autofill_clock.h @@ -16,7 +16,7 @@ namespace autofill { // with a customizable clock to facilitate testing. class AutofillClock { public: - // Returns the current time based on |clock_|. + // Returns the current time based last set clock. static base::Time Now(); private: @@ -26,7 +26,7 @@ class AutofillClock { static void SetClock(); // Sets the clock to be used for tests. - static void SetTestClock(base::Clock* clock); + static void SetTestClock(const base::Clock* clock); AutofillClock() = delete; ~AutofillClock() = delete; diff --git a/chromium/components/autofill/core/common/autofill_features.cc b/chromium/components/autofill/core/common/autofill_features.cc index d7a0b6e4957..7f4ca82a5bf 100644 --- a/chromium/components/autofill/core/common/autofill_features.cc +++ b/chromium/components/autofill/core/common/autofill_features.cc @@ -112,6 +112,11 @@ const base::Feature kAutofillProfileServerValidation{ const base::Feature kAutofillRejectCompanyBirthyear{ "AutofillRejectCompanyBirthyear", base::FEATURE_DISABLED_BY_DEFAULT}; +// Controls whether autofill rejects using non-verified company names that are +// social titles (e.g., "Mrs.") in some languages. +const base::Feature kAutofillRejectCompanySocialTitle{ + "AutofillRejectCompanySocialTitle", base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether or not a group of fields not enclosed in a form can be // considered a form. If this is enabled, unowned fields will only constitute // a form if there are signals to suggest that this might a checkout page. @@ -126,6 +131,10 @@ const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout{ const base::Feature kAutofillRichMetadataQueries{ "AutofillRichMetadataQueries", base::FEATURE_DISABLED_BY_DEFAULT}; +// Controls whether UPI/VPA values will be saved and filled into payment forms. +const base::Feature kAutofillSaveAndFillVPA{"AutofillSaveAndFillVPA", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kAutofillSaveOnProbablySubmitted{ "AutofillSaveOnProbablySubmitted", base::FEATURE_ENABLED_BY_DEFAULT}; @@ -165,6 +174,10 @@ const base::Feature kAutofillSkipComparingInferredLabels{ const base::Feature kAutofillTokenPrefixMatching{ "AutofillTokenPrefixMatching", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables the touch to fill feature for Android. +const base::Feature kAutofillTouchToFill = {"TouchToFillAndroid", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kAutofillUploadThrottling{"AutofillUploadThrottling", base::FEATURE_ENABLED_BY_DEFAULT}; @@ -178,6 +191,10 @@ const base::Feature kAutofillUseImprovedLabelDisambiguation{ "AutofillUseImprovedLabelDisambiguation", base::FEATURE_DISABLED_BY_DEFAULT}; +// Server predictions for CVC fields are used if the feature is enabled. +const base::Feature kAutofillUseServerCVCPrediction{ + "AutofillUseServerCVCPrediction", base::FEATURE_ENABLED_BY_DEFAULT}; + #if defined(OS_ANDROID) // Controls whether the Autofill manual fallback for Addresses and Payments is // present on Android. @@ -188,10 +205,6 @@ const base::Feature kAutofillManualFallbackAndroid{ const base::Feature kAutofillRefreshStyleAndroid{ "AutofillRefreshStyleAndroid", base::FEATURE_DISABLED_BY_DEFAULT}; -// Enables the touch to fill feature for Android. -const base::Feature kTouchToFillAndroid = {"TouchToFillAndroid", - base::FEATURE_DISABLED_BY_DEFAULT}; - #endif // OS_ANDROID #if defined(OS_ANDROID) || defined(OS_IOS) diff --git a/chromium/components/autofill/core/common/autofill_features.h b/chromium/components/autofill/core/common/autofill_features.h index 8e6937f5447..78a8bfcbbbc 100644 --- a/chromium/components/autofill/core/common/autofill_features.h +++ b/chromium/components/autofill/core/common/autofill_features.h @@ -42,8 +42,10 @@ extern const base::Feature kAutofillPreferServerNamePredictions; extern const base::Feature kAutofillProfileClientValidation; extern const base::Feature kAutofillProfileServerValidation; extern const base::Feature kAutofillRejectCompanyBirthyear; +extern const base::Feature kAutofillRejectCompanySocialTitle; extern const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout; extern const base::Feature kAutofillRichMetadataQueries; +extern const base::Feature kAutofillSaveAndFillVPA; extern const base::Feature kAutofillSaveOnProbablySubmitted; extern const base::Feature kAutofillServerCommunication; extern const base::Feature kAutofillShowAllSuggestionsOnPrefilledForms; @@ -51,14 +53,14 @@ extern const base::Feature kAutofillShowAutocompleteConsoleWarnings; extern const base::Feature kAutofillShowTypePredictions; extern const base::Feature kAutofillSkipComparingInferredLabels; extern const base::Feature kAutofillTokenPrefixMatching; +extern const base::Feature kAutofillTouchToFill; extern const base::Feature kAutofillUploadThrottling; extern const base::Feature kAutofillUseApi; extern const base::Feature kAutofillUseImprovedLabelDisambiguation; - +extern const base::Feature kAutofillUseServerCVCPrediction; #if defined(OS_ANDROID) extern const base::Feature kAutofillManualFallbackAndroid; extern const base::Feature kAutofillRefreshStyleAndroid; -extern const base::Feature kTouchToFillAndroid; #endif // OS_ANDROID #if defined(OS_ANDROID) || defined(OS_IOS) diff --git a/chromium/components/autofill/core/common/autofill_internals/log_message.cc b/chromium/components/autofill/core/common/autofill_internals/log_message.cc index 450258c661c..60da13de84e 100644 --- a/chromium/components/autofill/core/common/autofill_internals/log_message.cc +++ b/chromium/components/autofill/core/common/autofill_internals/log_message.cc @@ -5,6 +5,7 @@ #include "components/autofill/core/common/autofill_internals/log_message.h" #include "base/logging.h" +#include "components/autofill/core/common/logging/log_buffer.h" namespace autofill { @@ -50,4 +51,11 @@ const char* LogMessageValue(LogMessage message) { return ""; } +LogBuffer& operator<<(LogBuffer& buf, LogMessage message) { + if (!buf.active()) + return buf; + return buf << Tag{"div"} << Attrib{"message", LogMessageToString(message)} + << Attrib{"class", "log-message"} << LogMessageValue(message); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/common/autofill_internals/log_message.h b/chromium/components/autofill/core/common/autofill_internals/log_message.h index 4862e5e448e..a7232ce6cbb 100644 --- a/chromium/components/autofill/core/common/autofill_internals/log_message.h +++ b/chromium/components/autofill/core/common/autofill_internals/log_message.h @@ -7,15 +7,28 @@ namespace autofill { +class LogBuffer; + /////////////// Log Messages ///////////// // Generator for log message. If you need to find the call site for a log // message, take the first parameter (e.g. ParsedForms) and search for // that name prefixed with a k (e.g. kParsedForms) in code search. -#define AUTOFILL_LOG_MESSAGE_TEMPLATES(T) \ - T(ParsedForms, "Parsed forms:") \ - T(SendAutofillUpload, "Sending Autofill Upload Request:") \ - T(LocalHeuristicRegExMatched, "RegEx of local heuristic matched:") +#define AUTOFILL_LOG_MESSAGE_TEMPLATES(T) \ + T(ParsedForms, "Parsed forms:") \ + T(SendAutofillUpload, "Sending Autofill Upload Request:") \ + T(LocalHeuristicRegExMatched, "RegEx of local heuristic matched:") \ + T(AbortParsingTooManyForms, "Abort parsing form: Too many forms in cache: ") \ + T(AbortParsingNotAllowedScheme, \ + "Abort parsing form: Ignoring form because the source url has no allowed " \ + "scheme") \ + T(AbortParsingNotEnoughFields, \ + "Abort parsing form: Not enough fields in form: ") \ + T(AbortParsingUrlMatchesSearchRegex, \ + "Abort parsing form: Action URL matches kUrlSearchActionRe, indicating " \ + "that the form may lead to a search.") \ + T(AbortParsingFormHasNoTextfield, \ + "Abort parsing form: Form has no text field.") // Log messages for chrome://autofill-internals. #define AUTOFILL_TEMPLATE(NAME, MESSAGE) k##NAME, @@ -29,6 +42,8 @@ const char* LogMessageToString(LogMessage message); // Returns the actual string to be presented to the user for |message|. const char* LogMessageValue(LogMessage message); +LogBuffer& operator<<(LogBuffer& buf, LogMessage message); + } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_INTERNALS_LOG_MESSAGE_H_ diff --git a/chromium/components/autofill/core/browser/autofill_internals_service_unittest.cc b/chromium/components/autofill/core/common/autofill_internals/log_message_unittest.cc index 2baaee02348..2d4f225cb99 100644 --- a/chromium/components/autofill/core/browser/autofill_internals_service_unittest.cc +++ b/chromium/components/autofill/core/common/autofill_internals/log_message_unittest.cc @@ -2,26 +2,15 @@ // 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/autofill_internals_service.h" +#include "components/autofill/core/common/autofill_internals/log_message.h" #include "base/json/json_writer.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest-death-test.h" +#include "components/autofill/core/common/logging/log_buffer.h" #include "testing/gtest/include/gtest/gtest.h" namespace autofill { -TEST(AutofillInternalsService, Scope) { - LogBuffer buffer; - buffer << LoggingScope::kContext; - std::string json; - EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json)); - EXPECT_EQ(R"({"attributes":{"class":"log-entry","scope":"Context"},)" - R"("type":"element","value":"div"})", - json); -} - -TEST(AutofillInternalsService, Message) { +TEST(LogMessage, Serialization) { LogBuffer buffer; buffer << LogMessage::kParsedForms; std::string json; diff --git a/chromium/components/autofill/core/common/autofill_internals/logging_scope.cc b/chromium/components/autofill/core/common/autofill_internals/logging_scope.cc index ab962d5eaf3..2e1597b07bf 100644 --- a/chromium/components/autofill/core/common/autofill_internals/logging_scope.cc +++ b/chromium/components/autofill/core/common/autofill_internals/logging_scope.cc @@ -5,6 +5,7 @@ #include "components/autofill/core/common/autofill_internals/logging_scope.h" #include "base/logging.h" +#include "components/autofill/core/common/logging/log_buffer.h" namespace autofill { @@ -29,4 +30,11 @@ const char* LoggingScopeToString(LoggingScope scope) { return ""; } +LogBuffer& operator<<(LogBuffer& buf, LoggingScope scope) { + if (!buf.active()) + return buf; + return buf << Tag{"div"} << Attrib{"scope", LoggingScopeToString(scope)} + << Attrib{"class", "log-entry"}; +} + } // namespace autofill diff --git a/chromium/components/autofill/core/common/autofill_internals/logging_scope.h b/chromium/components/autofill/core/common/autofill_internals/logging_scope.h index ac719ca73dd..5684511f84e 100644 --- a/chromium/components/autofill/core/common/autofill_internals/logging_scope.h +++ b/chromium/components/autofill/core/common/autofill_internals/logging_scope.h @@ -7,6 +7,8 @@ namespace autofill { +class LogBuffer; + /////////////// Logging Scopes ///////////// // Generator for source code related to logging scopes. Pass a template T which @@ -16,6 +18,8 @@ namespace autofill { T(Context) \ /* Log messages related to the discovery and parsing of forms. */ \ T(Parsing) \ + /* Log messages related to reasons to stop parsing a form. */ \ + T(AbortParsing) \ /* Log messages related to filling of forms. */ \ T(Filling) \ /* Log messages related to the submission of forms. */ \ @@ -33,6 +37,8 @@ enum class LoggingScope { // Returns the enum value of |scope| as a string (without the leading k). const char* LoggingScopeToString(LoggingScope scope); +LogBuffer& operator<<(LogBuffer& buf, LoggingScope scope); + } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_INTERNALS_LOGGING_SCOPE_H_ diff --git a/chromium/components/autofill/core/common/autofill_internals/logging_scope_unittest.cc b/chromium/components/autofill/core/common/autofill_internals/logging_scope_unittest.cc new file mode 100644 index 00000000000..16ffe96f22c --- /dev/null +++ b/chromium/components/autofill/core/common/autofill_internals/logging_scope_unittest.cc @@ -0,0 +1,23 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/common/autofill_internals/logging_scope.h" + +#include "base/json/json_writer.h" +#include "components/autofill/core/common/logging/log_buffer.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { + +TEST(LoggingScope, Serialization) { + LogBuffer buffer; + buffer << LoggingScope::kContext; + std::string json; + EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json)); + EXPECT_EQ(R"({"attributes":{"class":"log-entry","scope":"Context"},)" + R"("type":"element","value":"div"})", + json); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/common/autofill_payments_features.cc b/chromium/components/autofill/core/common/autofill_payments_features.cc index 6fd64901fe7..d5a33bdaa85 100644 --- a/chromium/components/autofill/core/common/autofill_payments_features.cc +++ b/chromium/components/autofill/core/common/autofill_payments_features.cc @@ -34,6 +34,14 @@ const char kAutofillSaveCreditCardUsesImprovedMessagingParamValueConfirmAndSaveCard[] = "Confirm & Save Card"; +// Features + +// Controls whether or not Autofill client will populate form with CPAN and +// dCVV, rather than FPAN. +const base::Feature kAutofillAlwaysReturnCloudTokenizedCard{ + "AutofillAlwaysReturnCloudTokenizedCard", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kAutofillCreditCardAblationExperiment{ "AutofillCreditCardAblationExperiment", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -52,12 +60,6 @@ const base::Feature kAutofillDoNotMigrateUnsupportedLocalCards{ "AutofillDoNotMigrateUnsupportedLocalCards", base::FEATURE_ENABLED_BY_DEFAULT}; -// Controls whether the credit card downstream keyboard accessory shows -// the Google Pay logo animation on iOS. -const base::Feature kAutofillDownstreamUseGooglePayBrandingOniOS{ - "AutofillDownstreamUseGooglePayBrandingOniOS", - base::FEATURE_DISABLED_BY_DEFAULT}; - // When enabled, enable local card migration flow for user who has signed in but // has not turned on sync. const base::Feature kAutofillEnableLocalCardMigrationForNonSyncUser{ @@ -69,15 +71,11 @@ const base::Feature kAutofillEnableLocalCardMigrationForNonSyncUser{ const base::Feature kAutofillEnableToolbarStatusChip{ "AutofillEnableToolbarStatusChip", base::FEATURE_DISABLED_BY_DEFAULT}; -// When enabled, autofill can import credit cards from dynamic change form. -const base::Feature kAutofillImportDynamicForms{ - "AutofillImportDynamicForms", base::FEATURE_ENABLED_BY_DEFAULT}; - // Controls whether offering to migrate cards will consider data from the // Autofill strike database (new version). const base::Feature kAutofillLocalCardMigrationUsesStrikeSystemV2{ "AutofillLocalCardMigrationUsesStrikeSystemV2", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; // When enabled, will remove the option to save unmasked server cards as // FULL_SERVER_CARDs upon successful unmask. @@ -89,12 +87,17 @@ const base::Feature kAutofillNoLocalSaveOnUnmaskSuccess{ const base::Feature kAutofillNoLocalSaveOnUploadSuccess{ "AutofillNoLocalSaveOnUploadSuccess", base::FEATURE_DISABLED_BY_DEFAULT}; +// When enabled, the Save Card infobar will be dismissed by a user initiated +// navigation other than one caused by submitted form. +const base::Feature kAutofillSaveCardDismissOnNavigation{ + "AutofillSaveCardDismissOnNavigation", base::FEATURE_ENABLED_BY_DEFAULT}; + // When enabled, local and upload credit card save dialogs will add a // [No thanks] cancel button option. This is intended to bring the // AutofillSaveCardImprovedUserConsent functionality to Chrome OS, Android, and // iOS without bringing the extended title string change with it. const base::Feature kAutofillSaveCardShowNoThanks{ - "AutofillSaveCardShowNoThanks", base::FEATURE_DISABLED_BY_DEFAULT}; + "AutofillSaveCardShowNoThanks", base::FEATURE_ENABLED_BY_DEFAULT}; // Controls what title and bubble label for the credit card upload bubble are // shown to users. diff --git a/chromium/components/autofill/core/common/autofill_payments_features.h b/chromium/components/autofill/core/common/autofill_payments_features.h index b0f0e2827e5..6dc8e2faa2d 100644 --- a/chromium/components/autofill/core/common/autofill_payments_features.h +++ b/chromium/components/autofill/core/common/autofill_payments_features.h @@ -19,17 +19,17 @@ namespace autofill { namespace features { // All features in alphabetical order. +extern const base::Feature kAutofillAlwaysReturnCloudTokenizedCard; extern const base::Feature kAutofillCreditCardAblationExperiment; extern const base::Feature kAutofillCreditCardAuthentication; extern const base::Feature kAutofillCreditCardUploadFeedback; extern const base::Feature kAutofillDoNotMigrateUnsupportedLocalCards; -extern const base::Feature kAutofillDownstreamUseGooglePayBrandingOniOS; extern const base::Feature kAutofillEnableLocalCardMigrationForNonSyncUser; extern const base::Feature kAutofillEnableToolbarStatusChip; -extern const base::Feature kAutofillImportDynamicForms; extern const base::Feature kAutofillLocalCardMigrationUsesStrikeSystemV2; extern const base::Feature kAutofillNoLocalSaveOnUnmaskSuccess; extern const base::Feature kAutofillNoLocalSaveOnUploadSuccess; +extern const base::Feature kAutofillSaveCardDismissOnNavigation; extern const base::Feature kAutofillSaveCardShowNoThanks; extern const base::Feature kAutofillSaveCreditCardUsesImprovedMessaging; extern const base::Feature kAutofillUpdatedCardUnmaskPromptUi; diff --git a/chromium/components/autofill/core/common/autofill_prefs.cc b/chromium/components/autofill/core/common/autofill_prefs.cc index 7801f45ada6..1607b0d7274 100644 --- a/chromium/components/autofill/core/common/autofill_prefs.cc +++ b/chromium/components/autofill/core/common/autofill_prefs.cc @@ -18,7 +18,6 @@ namespace { // was found. int GetSyncTransportOptInBitFieldForAccount(const PrefService* prefs, const std::string& account_hash) { - auto* dictionary = prefs->GetDictionary(prefs::kAutofillSyncTransportOptIn); // If there is no dictionary it means the account didn't opt-in. Use 0 because @@ -43,14 +42,18 @@ int GetSyncTransportOptInBitFieldForAccount(const PrefService* prefs, const char kAutofillAcceptSaveCreditCardPromptState[] = "autofill.accept_save_credit_card_prompt_state"; -// Boolean that is true if FIDO Authentication is enabled for card unmasking. -const char kAutofillCreditCardFIDOAuthEnabled[] = - "autofill.credit_card_fido_auth_enabled"; - // Boolean that is true if Autofill is enabled and allowed to save credit card // data. const char kAutofillCreditCardEnabled[] = "autofill.credit_card_enabled"; +// Boolean that is true if FIDO Authentication is enabled for card unmasking. +const char kAutofillCreditCardFidoAuthEnabled[] = + "autofill.credit_card_fido_auth_enabled"; + +// Boolean that is true if FIDO Authentication is enabled for card unmasking. +const char kAutofillCreditCardFidoAuthOfferCheckboxState[] = + "autofill.credit_card_fido_auth_offer_checkbox_state"; + // Number of times the credit card signin promo has been shown. const char kAutofillCreditCardSigninPromoImpressionCount[] = "autofill.credit_card_signin_promo_impression_count"; @@ -58,9 +61,8 @@ const char kAutofillCreditCardSigninPromoImpressionCount[] = // Boolean that is true if Autofill is enabled and allowed to save data. const char kAutofillEnabledDeprecated[] = "autofill.enabled"; -// Boolean that is true if Japan address city field has been migrated to be a -// part of the street field. -const char kAutofillJapanCityFieldMigrated[] = +// Deprecated 10/2019. +const char kAutofillJapanCityFieldMigratedDeprecated[] = "autofill.japan_city_field_migrated_to_street_address"; // Integer that is set to the last version where the profile deduping routine @@ -157,11 +159,12 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); // Non-synced prefs. Used for per-device choices, e.g., signin promo. - registry->RegisterBooleanPref(prefs::kAutofillCreditCardFIDOAuthEnabled, + registry->RegisterBooleanPref(prefs::kAutofillCreditCardFidoAuthEnabled, false); + registry->RegisterBooleanPref( + prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true); registry->RegisterIntegerPref( prefs::kAutofillCreditCardSigninPromoImpressionCount, 0); - registry->RegisterBooleanPref(prefs::kAutofillJapanCityFieldMigrated, false); registry->RegisterBooleanPref(prefs::kAutofillWalletImportEnabled, true); registry->RegisterBooleanPref( prefs::kAutofillWalletImportStorageCheckboxState, true); @@ -180,6 +183,10 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { registry->RegisterTimePref(prefs::kAutofillUploadEventsLastResetTimestamp, base::Time()); registry->RegisterDictionaryPref(prefs::kAutofillSyncTransportOptIn); + + // Deprecated prefs registered for migration. + registry->RegisterBooleanPref(kAutofillJapanCityFieldMigratedDeprecated, + false); } void MigrateDeprecatedAutofillPrefs(PrefService* prefs) { @@ -210,6 +217,9 @@ void MigrateDeprecatedAutofillPrefs(PrefService* prefs) { prefs->SetBoolean(kAutofillProfileEnabled, prefs->GetBoolean(kAutofillEnabledDeprecated)); } + + // Added 10/2019. + prefs->ClearPref(kAutofillJapanCityFieldMigratedDeprecated); } bool IsAutocompleteEnabled(const PrefService* prefs) { @@ -226,11 +236,11 @@ void SetAutofillEnabled(PrefService* prefs, bool enabled) { } bool IsCreditCardFIDOAuthEnabled(PrefService* prefs) { - return prefs->GetBoolean(kAutofillCreditCardFIDOAuthEnabled); + return prefs->GetBoolean(kAutofillCreditCardFidoAuthEnabled); } void SetCreditCardFIDOAuthEnabled(PrefService* prefs, bool enabled) { - prefs->SetBoolean(kAutofillCreditCardFIDOAuthEnabled, enabled); + prefs->SetBoolean(kAutofillCreditCardFidoAuthEnabled, enabled); } bool IsCreditCardAutofillEnabled(const PrefService* prefs) { diff --git a/chromium/components/autofill/core/common/autofill_prefs.h b/chromium/components/autofill/core/common/autofill_prefs.h index f807434285e..7558441a2ac 100644 --- a/chromium/components/autofill/core/common/autofill_prefs.h +++ b/chromium/components/autofill/core/common/autofill_prefs.h @@ -20,12 +20,13 @@ namespace prefs { // component. Keep alphabetized, and document each in the .cc file. extern const char kAutofillAcceptSaveCreditCardPromptState[]; // Do not get/set the value of this pref directly. Use provided getter/setter. -extern const char kAutofillCreditCardFIDOAuthEnabled[]; extern const char kAutofillCreditCardEnabled[]; +extern const char kAutofillCreditCardFidoAuthEnabled[]; +extern const char kAutofillCreditCardFidoAuthOfferCheckboxState[]; extern const char kAutofillCreditCardSigninPromoImpressionCount[]; // Please use kAutofillCreditCardEnabled and kAutofillProfileEnabled instead. extern const char kAutofillEnabledDeprecated[]; -extern const char kAutofillJapanCityFieldMigrated[]; +extern const char kAutofillJapanCityFieldMigratedDeprecated[]; extern const char kAutofillLastVersionDeduped[]; extern const char kAutofillLastVersionValidated[]; extern const char kAutofillLastVersionDisusedAddressesDeleted[]; diff --git a/chromium/components/autofill/core/common/autofill_regex_constants.cc b/chromium/components/autofill/core/common/autofill_regex_constants.cc index 7cb75718ae4..daacd27d66a 100644 --- a/chromium/components/autofill/core/common/autofill_regex_constants.cc +++ b/chromium/components/autofill/core/common/autofill_regex_constants.cc @@ -176,13 +176,14 @@ const char kNameOnCardRe[] = const char kNameOnCardContextualRe[] = "name"; const char kCardNumberRe[] = "(add)?(?:card|cc|acct).?(?:number|#|no|num|field)" - "|(?<!telefon|haus)nummer" // de-DE - "|カード番号" // ja-JP - "|Номер.*карты" // ru - "|信用卡号|信用卡号码" // zh-CN - "|信用卡卡號" // zh-TW - "|카드" // ko-KR - "|(numero|número|numéro)(?!.*(document|fono|phone))"; // es/pt/fr + "|(?<!telefon|haus)nummer" // de-DE + "|カード番号" // ja-JP + "|Номер.*карты" // ru + "|信用卡号|信用卡号码" // zh-CN + "|信用卡卡號" // zh-TW + "|카드" // ko-KR + // es/pt/fr + "|(numero|número|numéro)(?!.*(document|fono|phone|réservation))"; const char kCardCvcRe[] = "verification|card.?identification|security.?code|card.?code" diff --git a/chromium/components/autofill/core/common/autofill_tick_clock.cc b/chromium/components/autofill/core/common/autofill_tick_clock.cc new file mode 100644 index 00000000000..594916e5c6f --- /dev/null +++ b/chromium/components/autofill/core/common/autofill_tick_clock.cc @@ -0,0 +1,33 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/common/autofill_tick_clock.h" + +#include "base/time/default_tick_clock.h" +#include "base/time/tick_clock.h" + +namespace autofill { +namespace { +const base::TickClock* g_autofill_tick_clock = nullptr; +} // namespace + +// static +base::TimeTicks AutofillTickClock::NowTicks() { + if (!g_autofill_tick_clock) + SetTickClock(); + return g_autofill_tick_clock->NowTicks(); +} + +// static +void AutofillTickClock::SetTickClock() { + g_autofill_tick_clock = base::DefaultTickClock::GetInstance(); +} + +// static +void AutofillTickClock::SetTestTickClock(const base::TickClock* tick_clock) { + DCHECK(tick_clock); + g_autofill_tick_clock = tick_clock; +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/common/autofill_tick_clock.h b/chromium/components/autofill/core/common/autofill_tick_clock.h new file mode 100644 index 00000000000..a438604ffed --- /dev/null +++ b/chromium/components/autofill/core/common/autofill_tick_clock.h @@ -0,0 +1,37 @@ +// 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. + +#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_TICK_CLOCK_H_ +#define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_TICK_CLOCK_H_ + +namespace base { +class TickClock; +class TimeTicks; +} // namespace base + +namespace autofill { + +// Handles getting the current time for the Autofill feature. Can be injected +// with a customizable tick clock to facilitate testing. +class AutofillTickClock { + public: + // Returns the current time based last set tick clock. + static base::TimeTicks NowTicks(); + + private: + friend class TestAutofillTickClock; + + // Resets a normal tick clock. + static void SetTickClock(); + + // Sets the tick clock to be used for tests. + static void SetTestTickClock(const base::TickClock* tick_clock); + + AutofillTickClock() = delete; + ~AutofillTickClock() = delete; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_TICK_CLOCK_H_ diff --git a/chromium/components/autofill/core/common/autofill_util.cc b/chromium/components/autofill/core/common/autofill_util.cc index 19ec7815437..36c3a17d912 100644 --- a/chromium/components/autofill/core/common/autofill_util.cc +++ b/chromium/components/autofill/core/common/autofill_util.cc @@ -72,7 +72,7 @@ bool IsKeyboardAccessoryEnabled() { bool IsTouchToFillEnabled() { #if defined(OS_ANDROID) - return base::FeatureList::IsEnabled(features::kTouchToFillAndroid); + return base::FeatureList::IsEnabled(features::kAutofillTouchToFill); #else // !defined(OS_ANDROID) return false; #endif diff --git a/chromium/components/autofill/core/common/form_data.cc b/chromium/components/autofill/core/common/form_data.cc index 5f2f9c95122..e69ae3a8a28 100644 --- a/chromium/components/autofill/core/common/form_data.cc +++ b/chromium/components/autofill/core/common/form_data.cc @@ -12,6 +12,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/common/form_field_data.h" +#include "components/autofill/core/common/logging/log_buffer.h" namespace autofill { @@ -68,29 +69,22 @@ void LogDeserializationError(int version) { } // namespace -FormData::FormData() : is_form_tag(true), is_formless_checkout(false) {} - -FormData::FormData(const FormData& data) - : name(data.name), - button_titles(data.button_titles), - url(data.url), - action(data.action), - main_frame_origin(data.main_frame_origin), - is_form_tag(data.is_form_tag), - is_formless_checkout(data.is_formless_checkout), - unique_renderer_id(data.unique_renderer_id), - submission_event(data.submission_event), - fields(data.fields), - username_predictions(data.username_predictions), - is_gaia_with_skip_save_password_form( - data.is_gaia_with_skip_save_password_form) {} - -FormData::~FormData() { -} +FormData::FormData() = default; + +FormData::FormData(const FormData&) = default; + +FormData& FormData::operator=(const FormData&) = default; + +FormData::FormData(FormData&&) = default; + +FormData& FormData::operator=(FormData&&) = default; + +FormData::~FormData() = default; bool FormData::SameFormAs(const FormData& form) const { - if (name != form.name || url != form.url || action != form.action || - is_form_tag != form.is_form_tag || + if (name != form.name || id_attribute != form.id_attribute || + name_attribute != form.name_attribute || url != form.url || + action != form.action || is_form_tag != form.is_form_tag || is_formless_checkout != form.is_formless_checkout || fields.size() != form.fields.size()) return false; @@ -102,11 +96,14 @@ bool FormData::SameFormAs(const FormData& form) const { } bool FormData::SimilarFormAs(const FormData& form) const { - if (name != form.name || url != form.url || action != form.action || + if (name != form.name || id_attribute != form.id_attribute || + name_attribute != form.name_attribute || url != form.url || + action != form.action || is_action_empty != form.is_action_empty || is_form_tag != form.is_form_tag || is_formless_checkout != form.is_formless_checkout || - fields.size() != form.fields.size()) + fields.size() != form.fields.size()) { return false; + } for (size_t i = 0; i < fields.size(); ++i) { if (!fields[i].SimilarFieldAs(form.fields[i])) return false; @@ -115,7 +112,9 @@ bool FormData::SimilarFormAs(const FormData& form) const { } bool FormData::DynamicallySameFormAs(const FormData& form) const { - if (name != form.name || fields.size() != form.fields.size()) + if (name != form.name || id_attribute != form.id_attribute || + name_attribute != form.name_attribute || + fields.size() != form.fields.size()) return false; for (size_t i = 0; i < fields.size(); ++i) { if (!fields[i].DynamicallySameFieldAs(form.fields[i])) @@ -125,7 +124,9 @@ bool FormData::DynamicallySameFormAs(const FormData& form) const { } bool FormData::operator==(const FormData& form) const { - return name == form.name && url == form.url && action == form.action && + return name == form.name && id_attribute == form.id_attribute && + name_attribute == form.name_attribute && url == form.url && + action == form.action && is_action_empty == form.is_action_empty && unique_renderer_id == form.unique_renderer_id && submission_event == form.submission_event && is_form_tag == form.is_form_tag && @@ -139,10 +140,11 @@ bool FormData::operator!=(const FormData& form) const { } bool FormData::operator<(const FormData& form) const { - return std::tie(name, url, action, is_form_tag, is_formless_checkout, - fields) < std::tie(form.name, form.url, form.action, - form.is_form_tag, - form.is_formless_checkout, form.fields); + return std::tie(name, id_attribute, name_attribute, url, action, is_form_tag, + is_formless_checkout, fields) < + std::tie(form.name, form.id_attribute, form.name_attribute, form.url, + form.action, form.is_form_tag, form.is_formless_checkout, + form.fields); } std::ostream& operator<<(std::ostream& os, const FormData& form) { @@ -167,15 +169,6 @@ void SerializeFormData(const FormData& form_data, base::Pickle* pickle) { pickle->WriteString(form_data.main_frame_origin.Serialize()); } -void SerializeFormDataToBase64String(const FormData& form_data, - std::string* output) { - base::Pickle pickle; - SerializeFormData(form_data, &pickle); - Base64Encode( - base::StringPiece(static_cast<const char*>(pickle.data()), pickle.size()), - output); -} - bool DeserializeFormData(base::PickleIterator* iter, FormData* form_data) { int version; FormData temp_form_data; @@ -239,15 +232,26 @@ bool DeserializeFormData(base::PickleIterator* iter, FormData* form_data) { return true; } -bool DeserializeFormDataFromBase64String(const base::StringPiece& input, - FormData* form_data) { - if (input.empty()) - return false; - std::string pickle_data; - Base64Decode(input, &pickle_data); - base::Pickle pickle(pickle_data.data(), static_cast<int>(pickle_data.size())); - base::PickleIterator iter(pickle); - return DeserializeFormData(&iter, form_data); +LogBuffer& operator<<(LogBuffer& buffer, const FormData& form) { + buffer << Tag{"div"} << Attrib{"class", "form"}; + buffer << Tag{"table"}; + buffer << Tr{} << "Form name:" << form.name; + buffer << Tr{} << "Unique renderer Id:" << form.unique_renderer_id; + buffer << Tr{} << "URL:" << form.url; + buffer << Tr{} << "Action:" << form.action; + buffer << Tr{} << "Is action empty:" << form.is_action_empty; + buffer << Tr{} << "Is <form> tag:" << form.is_form_tag; + for (size_t i = 0; i < form.fields.size(); ++i) { + buffer << Tag{"tr"}; + buffer << Tag{"td"} << "Field " << i << ": " << CTag{}; + buffer << Tag{"td"}; + buffer << Tag{"table"} << form.fields.at(i) << CTag{"table"}; + buffer << CTag{"td"}; + buffer << CTag{"tr"}; + } + buffer << CTag{"table"}; + buffer << CTag{"div"}; + return buffer; } } // namespace autofill diff --git a/chromium/components/autofill/core/common/form_data.h b/chromium/components/autofill/core/common/form_data.h index 639135adbb2..932394bc09e 100644 --- a/chromium/components/autofill/core/common/form_data.h +++ b/chromium/components/autofill/core/common/form_data.h @@ -18,6 +18,8 @@ namespace autofill { +class LogBuffer; + // Pair of a button title (e.g. "Register") and its type (e.g. // INPUT_ELEMENT_SUBMIT_TYPE). using ButtonTitleInfo = std::pair<base::string16, mojom::ButtonTitleType>; @@ -27,11 +29,16 @@ using ButtonTitleList = std::vector<ButtonTitleInfo>; // Holds information about a form to be filled and/or submitted. struct FormData { + // TODO(https://crbug.com/875768): Rename this const to kNotSetRendererId, and + // use it also for not set renderer ids in FormFieldData. static constexpr uint32_t kNotSetFormRendererId = std::numeric_limits<uint32_t>::max(); FormData(); - FormData(const FormData& data); + FormData(const FormData&); + FormData& operator=(const FormData&); + FormData(FormData&&); + FormData& operator=(FormData&&); ~FormData(); // Returns true if two forms are the same, not counting the values of the @@ -71,15 +78,19 @@ struct FormData { GURL url; // The action target of the form. GURL action; + // If the form in the DOM has an empty action attribute, the |action| field in + // the FormData is set to the frame URL of the embedding document. This field + // indicates whether the action attribute is empty in the form in the DOM. + bool is_action_empty = false; // The URL of main frame containing this form. url::Origin main_frame_origin; // True if this form is a form tag. - bool is_form_tag; + bool is_form_tag = true; // True if the form is made of unowned fields (i.e., not within a <form> tag) // in what appears to be a checkout flow. This attribute is only calculated // and used if features::kAutofillRestrictUnownedFieldsToFormlessCheckout is // enabled, to prevent heuristics from running on formless non-checkout. - bool is_formless_checkout; + bool is_formless_checkout = false; // Unique renderer id which is returned by function // WebFormElement::UniqueRendererFormId(). It is not persistant between page // loads, so it is not saved and not used in comparison in SameFormAs(). @@ -111,14 +122,7 @@ void SerializeFormData(const FormData& form_data, base::Pickle* pickle); // the part of a pickle created by SerializeFormData. Returns true on success. bool DeserializeFormData(base::PickleIterator* iter, FormData* form_data); -// Serialize FormData. Used by the PasswordManager to persist FormData -// pertaining to password forms in base64 string. It is useful since in some -// cases we need to store C strings without embedded '\0' symbols. -void SerializeFormDataToBase64String(const FormData& form_data, - std::string* output); -// Deserialize FormData. Returns true on success. -bool DeserializeFormDataFromBase64String(const base::StringPiece& input, - FormData* form_data); +LogBuffer& operator<<(LogBuffer& buffer, const FormData& form); } // namespace autofill diff --git a/chromium/components/autofill/core/common/form_data_predictions.cc b/chromium/components/autofill/core/common/form_data_predictions.cc index 9c71a970b98..bc97e87e381 100644 --- a/chromium/components/autofill/core/common/form_data_predictions.cc +++ b/chromium/components/autofill/core/common/form_data_predictions.cc @@ -6,23 +6,24 @@ namespace autofill { -FormDataPredictions::FormDataPredictions() { -} +FormDataPredictions::FormDataPredictions() = default; -FormDataPredictions::FormDataPredictions(const FormDataPredictions& other) - : data(other.data), - signature(other.signature), - fields(other.fields) { -} +FormDataPredictions::FormDataPredictions(const FormDataPredictions&) = default; -FormDataPredictions::~FormDataPredictions() { -} +FormDataPredictions& FormDataPredictions::operator=( + const FormDataPredictions&) = default; + +FormDataPredictions::FormDataPredictions(FormDataPredictions&&) = default; + +FormDataPredictions& FormDataPredictions::operator=(FormDataPredictions&&) = + default; + +FormDataPredictions::~FormDataPredictions() = default; bool FormDataPredictions::operator==( const FormDataPredictions& predictions) const { return (data.SameFormAs(predictions.data) && - signature == predictions.signature && - fields == predictions.fields); + signature == predictions.signature && fields == predictions.fields); } bool FormDataPredictions::operator!=( diff --git a/chromium/components/autofill/core/common/form_data_predictions.h b/chromium/components/autofill/core/common/form_data_predictions.h index 164778a5b22..cc5f9cf9185 100644 --- a/chromium/components/autofill/core/common/form_data_predictions.h +++ b/chromium/components/autofill/core/common/form_data_predictions.h @@ -23,7 +23,10 @@ struct FormDataPredictions { std::vector<FormFieldDataPredictions> fields; FormDataPredictions(); - FormDataPredictions(const FormDataPredictions& other); + FormDataPredictions(const FormDataPredictions&); + FormDataPredictions& operator=(const FormDataPredictions&); + FormDataPredictions(FormDataPredictions&&); + FormDataPredictions& operator=(FormDataPredictions&&); ~FormDataPredictions(); // Added for the sake of testing. diff --git a/chromium/components/autofill/core/common/form_data_unittest.cc b/chromium/components/autofill/core/common/form_data_unittest.cc index ff36cae9cfb..eae97e5c202 100644 --- a/chromium/components/autofill/core/common/form_data_unittest.cc +++ b/chromium/components/autofill/core/common/form_data_unittest.cc @@ -121,7 +121,7 @@ void FillInDummyFormData(FormData* data) { data->action = GURL("https://example.com/action"); data->main_frame_origin = url::Origin::Create(GURL("https://origin-example.com")); - data->is_form_tag = true; // Default value. + data->is_form_tag = true; // Default value. data->is_formless_checkout = false; // Default value. FormFieldData field_data; @@ -166,20 +166,6 @@ TEST(FormDataTest, SerializeAndDeserialize) { EXPECT_TRUE(actual.SameFormAs(data)); } -TEST(FormDataTest, SerializeAndDeserializeInStrings) { - FormData data; - FillInDummyFormData(&data); - data.is_form_tag = false; - - std::string serialized_data; - SerializeFormDataToBase64String(data, &serialized_data); - - FormData actual; - EXPECT_TRUE(DeserializeFormDataFromBase64String(serialized_data, &actual)); - - EXPECT_TRUE(actual.SameFormAs(data)); -} - TEST(FormDataTest, Serialize_v1_Deserialize_vCurrent) { FormData data; FillInDummyFormData(&data); diff --git a/chromium/components/autofill/core/common/form_field_data.cc b/chromium/components/autofill/core/common/form_field_data.cc index b8c0f13cb30..1a804330c6c 100644 --- a/chromium/components/autofill/core/common/form_field_data.cc +++ b/chromium/components/autofill/core/common/form_field_data.cc @@ -8,6 +8,7 @@ #include "base/strings/string_util.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_util.h" +#include "components/autofill/core/common/logging/log_buffer.h" // TODO(crbug/897756): Clean up the (de)serialization code. @@ -143,9 +144,15 @@ bool HaveSameLabel(const FormFieldData& field1, const FormFieldData& field2) { FormFieldData::FormFieldData() = default; -FormFieldData::FormFieldData(const FormFieldData& other) = default; +FormFieldData::FormFieldData(const FormFieldData&) = default; -FormFieldData::~FormFieldData() {} +FormFieldData& FormFieldData::operator=(const FormFieldData&) = default; + +FormFieldData::FormFieldData(FormFieldData&&) = default; + +FormFieldData& FormFieldData::operator=(FormFieldData&&) = default; + +FormFieldData::~FormFieldData() = default; bool FormFieldData::SameFieldAs(const FormFieldData& field) const { // TODO(crbug.com/896689): On iOS the unique_id member uniquely addresses @@ -205,6 +212,22 @@ bool FormFieldData::IsTextInputElement() const { form_control_type == "url" || form_control_type == "email"; } +bool FormFieldData::IsPasswordInputElement() const { + return form_control_type == "password"; +} + +bool FormFieldData::DidUserType() const { + return properties_mask & USER_TYPED; +} + +bool FormFieldData::HadFocus() const { + return properties_mask & HAD_FOCUS; +} + +bool FormFieldData::WasAutofilled() const { + return properties_mask & AUTOFILLED; +} + bool FormFieldData::operator==(const FormFieldData& field) const { return SameFieldAs(field) && unique_renderer_id == field.unique_renderer_id && form_control_ax_id == field.form_control_ax_id && @@ -468,4 +491,26 @@ std::ostream& operator<<(std::ostream& os, const FormFieldData& field) { << "label_source=" << field.label_source; } +LogBuffer& operator<<(LogBuffer& buffer, const FormFieldData& field) { + buffer << Tag{"table"}; + buffer << Tr{} << "Name:" << field.name; + buffer << Tr{} << "Unique renderer Id:" << field.unique_renderer_id; + buffer << Tr{} << "Name attribute:" << field.name_attribute; + buffer << Tr{} << "Id attribute:" << field.id_attribute; + constexpr size_t kMaxLabelSize = 100; + const base::string16 truncated_label = + field.label.substr(0, std::min(field.label.length(), kMaxLabelSize)); + buffer << Tr{} << "Label:" << truncated_label; + buffer << Tr{} << "Form control type:" << field.form_control_type; + buffer << Tr{} << "Autocomplete attribute:" << field.autocomplete_attribute; + buffer << Tr{} << "Aria label:" << field.aria_label; + buffer << Tr{} << "Aria description:" << field.aria_description; + buffer << Tr{} << "Section:" << field.section; + buffer << Tr{} << "Is focusable:" << field.is_focusable; + buffer << Tr{} << "Is enabled:" << field.is_enabled; + buffer << Tr{} << "Is readonly:" << field.is_readonly; + buffer << CTag{"table"}; + return buffer; +} + } // namespace autofill diff --git a/chromium/components/autofill/core/common/form_field_data.h b/chromium/components/autofill/core/common/form_field_data.h index b9d4f9d6013..605f9e0baad 100644 --- a/chromium/components/autofill/core/common/form_field_data.h +++ b/chromium/components/autofill/core/common/form_field_data.h @@ -18,10 +18,12 @@ namespace base { class Pickle; class PickleIterator; -} +} // namespace base namespace autofill { +class LogBuffer; + // The flags describing form field properties. enum FieldPropertiesFlags { NO_FLAGS = 0u, @@ -59,7 +61,10 @@ struct FormFieldData { std::numeric_limits<uint32_t>::max(); FormFieldData(); - FormFieldData(const FormFieldData& other); + FormFieldData(const FormFieldData&); + FormFieldData& operator=(const FormFieldData&); + FormFieldData(FormFieldData&&); + FormFieldData& operator=(FormFieldData&&); ~FormFieldData(); // Returns true if two form fields are the same, not counting the value. @@ -81,11 +86,19 @@ struct FormFieldData { // a textarea. bool IsTextInputElement() const; + bool IsPasswordInputElement() const; + // Returns true if the field is visible to the user. bool IsVisible() const { return is_focusable && role != RoleAttribute::kPresentation; } + // These functions do not work for Autofill code. + // TODO(https://crbug.com/1006745): Fix this. + bool DidUserType() const; + bool HadFocus() const; + bool WasAutofilled() const; + // Note: operator==() performs a full-field-comparison(byte by byte), this is // different from SameFieldAs(), which ignores comparison for those "values" // not regarded as part of identity of the field, such as is_autofilled and @@ -202,6 +215,9 @@ std::ostream& operator<<(std::ostream& os, const FormFieldData& field); EXPECT_EQ(expected.name_attribute, actual.name_attribute); \ } while (0) +// Produces a <table> element with information about the form. +LogBuffer& operator<<(LogBuffer& buffer, const FormFieldData& form); + } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_COMMON_FORM_FIELD_DATA_H_ diff --git a/chromium/components/autofill/core/common/form_field_data_predictions.cc b/chromium/components/autofill/core/common/form_field_data_predictions.cc index 9109fcfd537..46e8bd2b6e0 100644 --- a/chromium/components/autofill/core/common/form_field_data_predictions.cc +++ b/chromium/components/autofill/core/common/form_field_data_predictions.cc @@ -6,21 +6,21 @@ namespace autofill { -FormFieldDataPredictions::FormFieldDataPredictions() { -} +FormFieldDataPredictions::FormFieldDataPredictions() = default; FormFieldDataPredictions::FormFieldDataPredictions( - const FormFieldDataPredictions& other) - : field(other.field), - signature(other.signature), - heuristic_type(other.heuristic_type), - server_type(other.server_type), - overall_type(other.overall_type), - parseable_name(other.parseable_name), - section(other.section) {} - -FormFieldDataPredictions::~FormFieldDataPredictions() { -} + const FormFieldDataPredictions&) = default; + +FormFieldDataPredictions& FormFieldDataPredictions::operator=( + const FormFieldDataPredictions&) = default; + +FormFieldDataPredictions::FormFieldDataPredictions(FormFieldDataPredictions&&) = + default; + +FormFieldDataPredictions& FormFieldDataPredictions::operator=( + FormFieldDataPredictions&&) = default; + +FormFieldDataPredictions::~FormFieldDataPredictions() = default; bool FormFieldDataPredictions::operator==( const FormFieldDataPredictions& predictions) const { diff --git a/chromium/components/autofill/core/common/form_field_data_predictions.h b/chromium/components/autofill/core/common/form_field_data_predictions.h index baeb68bfba8..1792ddc512e 100644 --- a/chromium/components/autofill/core/common/form_field_data_predictions.h +++ b/chromium/components/autofill/core/common/form_field_data_predictions.h @@ -15,7 +15,10 @@ namespace autofill { // Stores information about a field in a form. struct FormFieldDataPredictions { FormFieldDataPredictions(); - FormFieldDataPredictions(const FormFieldDataPredictions& other); + FormFieldDataPredictions(const FormFieldDataPredictions&); + FormFieldDataPredictions& operator=(const FormFieldDataPredictions&); + FormFieldDataPredictions(FormFieldDataPredictions&&); + FormFieldDataPredictions& operator=(FormFieldDataPredictions&&); ~FormFieldDataPredictions(); FormFieldData field; diff --git a/chromium/components/autofill/core/browser/logging/log_buffer.cc b/chromium/components/autofill/core/common/logging/log_buffer.cc index 8bbd7a9df7b..5abd4daa207 100644 --- a/chromium/components/autofill/core/browser/logging/log_buffer.cc +++ b/chromium/components/autofill/core/common/logging/log_buffer.cc @@ -2,7 +2,7 @@ // 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/logging/log_buffer.h" +#include "components/autofill/core/common/logging/log_buffer.h" #include <string> @@ -40,7 +40,7 @@ void AppendChildToLastNode(std::vector<base::Value>* buffer, DCHECK(!IsTextNode(parent)); if (auto* children = parent.FindListKey("children")) { - children->GetList().push_back(std::move(new_child)); + children->Append(std::move(new_child)); return; } diff --git a/chromium/components/autofill/core/browser/logging/log_buffer.h b/chromium/components/autofill/core/common/logging/log_buffer.h index 2dd9c4c74b4..fc782f4f93d 100644 --- a/chromium/components/autofill/core/browser/logging/log_buffer.h +++ b/chromium/components/autofill/core/common/logging/log_buffer.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_LOGGING_LOG_BUFFER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_LOGGING_LOG_BUFFER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_LOGGING_LOG_BUFFER_H_ +#define COMPONENTS_AUTOFILL_CORE_COMMON_LOGGING_LOG_BUFFER_H_ #include <string> #include <type_traits> @@ -14,7 +14,6 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/values.h" -#include "third_party/protobuf/src/google/protobuf/repeated_field.h" #include "url/gurl.h" // The desired pattern to generate log messages is to pass a scope, a log @@ -154,19 +153,6 @@ LogBuffer& operator<<(LogBuffer& buf, LogBuffer&& buffer); LogBuffer& operator<<(LogBuffer& buf, const GURL& url); template <typename T> -LogBuffer& operator<<(LogBuffer& buf, - const ::google::protobuf::RepeatedField<T>& values) { - buf << "["; - for (int i = 0; i < values.size(); ++i) { - if (i) - buf << ", "; - buf << values.Get(i); - } - buf << "]"; - return buf; -} - -template <typename T> LogBuffer& operator<<(LogBuffer& buf, const std::vector<T>& values) { buf << "["; for (size_t i = 0; i < values.size(); ++i) { @@ -219,4 +205,4 @@ LogBuffer HighlightValue(base::StringPiece16 haystack, } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_LOGGING_LOG_BUFFER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_COMMON_LOGGING_LOG_BUFFER_H_ diff --git a/chromium/components/autofill/core/browser/logging/log_buffer_unittest.cc b/chromium/components/autofill/core/common/logging/log_buffer_unittest.cc index 3b4b6c94ab6..de9126e263b 100644 --- a/chromium/components/autofill/core/browser/logging/log_buffer_unittest.cc +++ b/chromium/components/autofill/core/common/logging/log_buffer_unittest.cc @@ -2,7 +2,7 @@ // 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/logging/log_buffer.h" +#include "components/autofill/core/common/logging/log_buffer.h" #include "base/json/json_writer.h" #include "base/strings/string_piece.h" diff --git a/chromium/components/autofill/core/common/mojom/autofill_types.mojom b/chromium/components/autofill/core/common/mojom/autofill_types.mojom index 8e8a3c3c44d..0879248916c 100644 --- a/chromium/components/autofill/core/common/mojom/autofill_types.mojom +++ b/chromium/components/autofill/core/common/mojom/autofill_types.mojom @@ -153,6 +153,7 @@ struct FormData { array<ButtonTitleInfo> button_titles; url.mojom.Url url; url.mojom.Url action; + bool is_action_empty; url.mojom.Origin main_frame_origin; bool is_form_tag; bool is_formless_checkout; @@ -213,6 +214,7 @@ struct PasswordGenerationUIData { int32 max_length; mojo_base.mojom.String16 generation_element; uint32 generation_element_id; + bool is_generation_element_password_type; mojo_base.mojom.TextDirection text_direction; PasswordForm password_form; }; @@ -295,16 +297,23 @@ struct PasswordForm { bool only_for_fallback; }; -// Note: Even though https://crbug.com/628104 is solved, we still can not use a -// map directly as long as https://crbug.com/914074 is not fixed. -struct PasswordFormFieldPredictionMap { - array<FormFieldData> keys; - array<PasswordFormFieldPredictionType> values; +// autofill::ParsingResult +struct ParsingResult { + uint32 username_renderer_id; + uint32 password_renderer_id; + uint32 new_password_renderer_id; + uint32 confirm_password_renderer_id; }; -// Note: Even though https://crbug.com/628104 is solved, we still can not use a -// map directly as long as https://crbug.com/914074 is not fixed. -struct FormsPredictionsMap { - array<FormData> keys; - array<PasswordFormFieldPredictionMap> values; +// Represents the autofill state. +enum AutofillState { + // There are no available suggestions, neither autofill nor autocomplete, for + // the input. + kNoSuggestions, + // There are available autofill suggestions for the input. Autofill fills in + // an entire form. + kAutofillAvailable, + // There are available autocomplete suggestions for the input. Autocomplete + // only fills in a single input. + kAutocompleteAvailable, }; diff --git a/chromium/components/autofill/core/common/mojom/autofill_types.typemap b/chromium/components/autofill/core/common/mojom/autofill_types.typemap index 6b444c359f4..1531e37fb14 100644 --- a/chromium/components/autofill/core/common/mojom/autofill_types.typemap +++ b/chromium/components/autofill/core/common/mojom/autofill_types.typemap @@ -9,7 +9,6 @@ public_headers = [ "//components/autofill/core/common/form_field_data.h", "//components/autofill/core/common/form_field_data_predictions.h", "//components/autofill/core/common/password_form.h", - "//components/autofill/core/common/password_form_field_prediction_map.h", "//components/autofill/core/common/password_form_fill_data.h", "//components/autofill/core/common/password_form_generation_data.h", "//components/autofill/core/common/password_generation_util.h", @@ -32,6 +31,7 @@ type_mappings = [ "autofill.mojom.FormFieldData=::autofill::FormFieldData", "autofill.mojom.FormFieldDataPredictions=::autofill::FormFieldDataPredictions", "autofill.mojom.FormsPredictionsMap=::autofill::FormsPredictionsMap", + "autofill.mojom.ParsingResult=::autofill::ParsingResult", "autofill.mojom.PasswordAndRealm=::autofill::PasswordAndRealm", "autofill.mojom.PasswordForm=::autofill::PasswordForm", "autofill.mojom.PasswordFormFieldPredictionMap=::autofill::PasswordFormFieldPredictionMap", diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc index 9128a8523fc..3962a512072 100644 --- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc +++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc @@ -107,6 +107,7 @@ bool StructTraits<autofill::mojom::FormDataDataView, autofill::FormData>::Read( return false; if (!data.ReadAction(&out->action)) return false; + out->is_action_empty = data.is_action_empty(); if (!data.ReadMainFrameOrigin(&out->main_frame_origin)) return false; @@ -222,6 +223,8 @@ bool StructTraits<autofill::mojom::PasswordGenerationUIDataDataView, out->max_length = data.max_length(); out->generation_element_id = data.generation_element_id(); + out->is_generation_element_password_type = + data.is_generation_element_password_type(); if (!data.ReadGenerationElement(&out->generation_element) || !data.ReadTextDirection(&out->text_direction) || @@ -298,92 +301,6 @@ bool StructTraits< } // static -std::vector<autofill::FormFieldData> -StructTraits<autofill::mojom::PasswordFormFieldPredictionMapDataView, - autofill::PasswordFormFieldPredictionMap>:: - keys(const autofill::PasswordFormFieldPredictionMap& r) { - std::vector<autofill::FormFieldData> data; - for (const auto& i : r) - data.push_back(i.first); - return data; -} - -// static -std::vector<autofill::mojom::PasswordFormFieldPredictionType> -StructTraits<autofill::mojom::PasswordFormFieldPredictionMapDataView, - autofill::PasswordFormFieldPredictionMap>:: - values(const autofill::PasswordFormFieldPredictionMap& r) { - std::vector<autofill::mojom::PasswordFormFieldPredictionType> types; - for (const auto& i : r) - types.push_back(i.second); - return types; -} - -// static -bool StructTraits<autofill::mojom::PasswordFormFieldPredictionMapDataView, - autofill::PasswordFormFieldPredictionMap>:: - Read(autofill::mojom::PasswordFormFieldPredictionMapDataView data, - autofill::PasswordFormFieldPredictionMap* out) { - // Combines keys vector and values vector to the map. - std::vector<autofill::FormFieldData> keys; - if (!data.ReadKeys(&keys)) - return false; - std::vector<autofill::mojom::PasswordFormFieldPredictionType> values; - if (!data.ReadValues(&values)) - return false; - if (keys.size() != values.size()) - return false; - out->clear(); - for (size_t i = 0; i < keys.size(); ++i) - out->insert({keys[i], values[i]}); - - return true; -} - -// static -std::vector<autofill::FormData> StructTraits< - autofill::mojom::FormsPredictionsMapDataView, - autofill::FormsPredictionsMap>::keys(const autofill::FormsPredictionsMap& - r) { - std::vector<autofill::FormData> data; - for (const auto& i : r) - data.push_back(i.first); - return data; -} - -// static -std::vector<autofill::PasswordFormFieldPredictionMap> StructTraits< - autofill::mojom::FormsPredictionsMapDataView, - autofill::FormsPredictionsMap>::values(const autofill::FormsPredictionsMap& - r) { - std::vector<autofill::PasswordFormFieldPredictionMap> maps; - for (const auto& i : r) - maps.push_back(i.second); - return maps; -} - -// static -bool StructTraits<autofill::mojom::FormsPredictionsMapDataView, - autofill::FormsPredictionsMap>:: - Read(autofill::mojom::FormsPredictionsMapDataView data, - autofill::FormsPredictionsMap* out) { - // Combines keys vector and values vector to the map. - std::vector<autofill::FormData> keys; - if (!data.ReadKeys(&keys)) - return false; - std::vector<autofill::PasswordFormFieldPredictionMap> values; - if (!data.ReadValues(&values)) - return false; - if (keys.size() != values.size()) - return false; - out->clear(); - for (size_t i = 0; i < keys.size(); ++i) - out->insert({keys[i], values[i]}); - - return true; -} - -// static bool StructTraits<autofill::mojom::ValueElementPairDataView, autofill::ValueElementPair>:: Read(autofill::mojom::ValueElementPairDataView data, @@ -394,4 +311,16 @@ bool StructTraits<autofill::mojom::ValueElementPairDataView, return true; } +bool StructTraits< + autofill::mojom::ParsingResultDataView, + autofill::ParsingResult>::Read(autofill::mojom::ParsingResultDataView data, + autofill::ParsingResult* out) { + out->username_renderer_id = data.username_renderer_id(); + out->password_renderer_id = data.password_renderer_id(); + out->new_password_renderer_id = data.new_password_renderer_id(); + out->confirm_password_renderer_id = data.confirm_password_renderer_id(); + + return true; +} + } // namespace mojo diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h index 6a1ca29db05..a26fbd21849 100644 --- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h +++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h @@ -18,7 +18,6 @@ #include "components/autofill/core/common/form_field_data_predictions.h" #include "components/autofill/core/common/mojom/autofill_types.mojom.h" #include "components/autofill/core/common/password_form.h" -#include "components/autofill/core/common/password_form_field_prediction_map.h" #include "components/autofill/core/common/password_form_fill_data.h" #include "components/autofill/core/common/password_form_generation_data.h" #include "components/autofill/core/common/password_generation_util.h" @@ -197,6 +196,10 @@ struct StructTraits<autofill::mojom::FormDataDataView, autofill::FormData> { static const GURL& action(const autofill::FormData& r) { return r.action; } + static bool is_action_empty(const autofill::FormData& r) { + return r.is_action_empty; + } + static const url::Origin& main_frame_origin(const autofill::FormData& r) { return r.main_frame_origin; } @@ -405,6 +408,11 @@ struct StructTraits<autofill::mojom::PasswordGenerationUIDataDataView, return r.generation_element_id; } + static bool is_generation_element_password_type( + const autofill::password_generation::PasswordGenerationUIData& r) { + return r.is_generation_element_password_type; + } + static base::i18n::TextDirection text_direction( const autofill::password_generation::PasswordGenerationUIData& r) { return r.text_direction; @@ -578,32 +586,6 @@ struct StructTraits<autofill::mojom::PasswordFormDataView, }; template <> -struct StructTraits<autofill::mojom::PasswordFormFieldPredictionMapDataView, - autofill::PasswordFormFieldPredictionMap> { - static std::vector<autofill::FormFieldData> keys( - const autofill::PasswordFormFieldPredictionMap& r); - - static std::vector<autofill::mojom::PasswordFormFieldPredictionType> values( - const autofill::PasswordFormFieldPredictionMap& r); - - static bool Read(autofill::mojom::PasswordFormFieldPredictionMapDataView data, - autofill::PasswordFormFieldPredictionMap* out); -}; - -template <> -struct StructTraits<autofill::mojom::FormsPredictionsMapDataView, - autofill::FormsPredictionsMap> { - static std::vector<autofill::FormData> keys( - const autofill::FormsPredictionsMap& r); - - static std::vector<autofill::PasswordFormFieldPredictionMap> values( - const autofill::FormsPredictionsMap& r); - - static bool Read(autofill::mojom::FormsPredictionsMapDataView data, - autofill::FormsPredictionsMap* out); -}; - -template <> struct StructTraits<autofill::mojom::ValueElementPairDataView, autofill::ValueElementPair> { static base::string16 value(const autofill::ValueElementPair& r) { @@ -618,6 +600,30 @@ struct StructTraits<autofill::mojom::ValueElementPairDataView, autofill::ValueElementPair* out); }; +template <> +struct StructTraits<autofill::mojom::ParsingResultDataView, + autofill::ParsingResult> { + static uint32_t username_renderer_id(const autofill::ParsingResult& r) { + return r.username_renderer_id; + } + + static uint32_t password_renderer_id(const autofill::ParsingResult& r) { + return r.password_renderer_id; + } + + static uint32_t new_password_renderer_id(const autofill::ParsingResult& r) { + return r.new_password_renderer_id; + } + + static uint32_t confirm_password_renderer_id( + const autofill::ParsingResult& r) { + return r.confirm_password_renderer_id; + } + + static bool Read(autofill::mojom::ParsingResultDataView data, + autofill::ParsingResult* out); +}; + } // namespace mojo #endif // COMPONENTS_AUTOFILL_CORE_COMMON_MOJOM_AUTOFILL_TYPES_MOJOM_TRAITS_H_ diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc index 37c68ad829a..1fd64be2cfc 100644 --- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc +++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc @@ -9,13 +9,15 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/task_environment.h" #include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" #include "components/autofill/core/common/mojom/test_autofill_types.mojom.h" #include "components/autofill/core/common/password_generation_util.h" #include "components/autofill/core/common/signatures_util.h" -#include "mojo/public/cpp/bindings/binding_set.h" -#include "mojo/public/cpp/bindings/interface_request.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "mojo/public/cpp/bindings/remote.h" #include "testing/gtest/include/gtest/gtest.h" namespace autofill { @@ -90,8 +92,8 @@ void CreateTestPasswordForm(PasswordForm* form) { form->new_password_marked_by_site = false; form->new_password_element = base::ASCIIToUTF16("confirmation_password"); form->preferred = false; - form->date_created = base::Time::Now(); - form->date_synced = base::Time::Now(); + form->date_created = AutofillClock::Now(); + form->date_synced = AutofillClock::Now(); form->blacklisted_by_user = false; form->type = PasswordForm::Type::kGenerated; form->times_used = 999; @@ -109,45 +111,13 @@ void CreateTestPasswordForm(PasswordForm* form) { mojom::SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; } -void CreateTestFormsPredictionsMap(FormsPredictionsMap* predictions) { - FormsPredictionsMap& result_map = *predictions; - // 1st element. - FormData form_data; - test::CreateTestAddressFormData(&form_data); - ASSERT_TRUE(form_data.fields.size() >= 4); - result_map[form_data][form_data.fields[0]] = - PasswordFormFieldPredictionType::kUsername; - result_map[form_data][form_data.fields[1]] = - PasswordFormFieldPredictionType::kCurrentPassword; - result_map[form_data][form_data.fields[2]] = - PasswordFormFieldPredictionType::kNewPassword; - result_map[form_data][form_data.fields[3]] = - PasswordFormFieldPredictionType::kNotPassword; - - // 2nd element. - form_data.fields.clear(); - result_map[form_data] = {}; - - // 3rd element. - FormFieldData field_data; - test::CreateTestSelectField("TestLabel1", "TestName1", "TestValue1", kOptions, - kOptions, 4, &field_data); - form_data.fields.push_back(field_data); - test::CreateTestSelectField("TestLabel2", "TestName2", "TestValue2", kOptions, - kOptions, 4, &field_data); - form_data.fields.push_back(field_data); - result_map[form_data][form_data.fields[0]] = - PasswordFormFieldPredictionType::kNewPassword; - result_map[form_data][form_data.fields[1]] = - PasswordFormFieldPredictionType::kCurrentPassword; -} - void CreatePasswordGenerationUIData( password_generation::PasswordGenerationUIData* data) { data->bounds = gfx::RectF(1, 1, 200, 100); data->max_length = 20; data->generation_element = base::ASCIIToUTF16("generation_element"); data->text_direction = base::i18n::RIGHT_TO_LEFT; + data->is_generation_element_password_type = false; CreateTestPasswordForm(&data->password_form); } @@ -185,6 +155,8 @@ void CheckEqualPassPasswordGenerationUIData( EXPECT_EQ(expected.bounds, actual.bounds); EXPECT_EQ(expected.max_length, actual.max_length); EXPECT_EQ(expected.generation_element, actual.generation_element); + EXPECT_EQ(expected.is_generation_element_password_type, + actual.is_generation_element_password_type); EXPECT_EQ(expected.text_direction, actual.text_direction); EXPECT_EQ(expected.password_form, actual.password_form); } @@ -196,10 +168,10 @@ class AutofillTypeTraitsTestImpl : public testing::Test, public: AutofillTypeTraitsTestImpl() {} - mojom::TypeTraitsTestPtr GetTypeTraitsTestProxy() { - mojom::TypeTraitsTestPtr proxy; - bindings_.AddBinding(this, mojo::MakeRequest(&proxy)); - return proxy; + mojo::PendingRemote<mojom::TypeTraitsTest> GetTypeTraitsTestRemote() { + mojo::PendingRemote<mojom::TypeTraitsTest> remote; + receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver()); + return remote; } // mojom::TypeTraitsTest: @@ -247,16 +219,10 @@ class AutofillTypeTraitsTestImpl : public testing::Test, std::move(callback).Run(s); } - void PassFormsPredictionsMap( - const FormsPredictionsMap& s, - PassFormsPredictionsMapCallback callback) override { - std::move(callback).Run(s); - } - private: base::test::TaskEnvironment task_environment_; - mojo::BindingSet<TypeTraitsTest> bindings_; + mojo::ReceiverSet<TypeTraitsTest> receivers_; }; void ExpectFormFieldData(const FormFieldData& expected, @@ -321,13 +287,6 @@ void ExpectPasswordForm(const PasswordForm& expected, std::move(closure).Run(); } -void ExpectFormsPredictionsMap(const FormsPredictionsMap& expected, - base::OnceClosure closure, - const FormsPredictionsMap& passed) { - EXPECT_EQ(expected, passed); - std::move(closure).Run(); -} - TEST_F(AutofillTypeTraitsTestImpl, PassFormFieldData) { FormFieldData input; test::CreateTestSelectField("TestLabel", "TestName", "TestValue", kOptions, @@ -350,8 +309,8 @@ TEST_F(AutofillTypeTraitsTestImpl, PassFormFieldData) { input.typed_value = base::ASCIIToUTF16("TestTypedValue"); base::RunLoop loop; - mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy(); - proxy->PassFormFieldData( + mojo::Remote<mojom::TypeTraitsTest> remote(GetTypeTraitsTestRemote()); + remote->PassFormFieldData( input, base::BindOnce(&ExpectFormFieldData, input, loop.QuitClosure())); loop.Run(); } @@ -365,8 +324,8 @@ TEST_F(AutofillTypeTraitsTestImpl, PassFormData) { mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)); base::RunLoop loop; - mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy(); - proxy->PassFormData( + mojo::Remote<mojom::TypeTraitsTest> remote(GetTypeTraitsTestRemote()); + remote->PassFormData( input, base::BindOnce(&ExpectFormData, input, loop.QuitClosure())); loop.Run(); } @@ -376,8 +335,8 @@ TEST_F(AutofillTypeTraitsTestImpl, PassFormFieldDataPredictions) { CreateTestFieldDataPredictions("TestSignature", &input); base::RunLoop loop; - mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy(); - proxy->PassFormFieldDataPredictions( + mojo::Remote<mojom::TypeTraitsTest> remote(GetTypeTraitsTestRemote()); + remote->PassFormFieldDataPredictions( input, base::BindOnce(&ExpectFormFieldDataPredictions, input, loop.QuitClosure())); loop.Run(); @@ -397,8 +356,8 @@ TEST_F(AutofillTypeTraitsTestImpl, PassFormDataPredictions) { input.fields.push_back(field_predict); base::RunLoop loop; - mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy(); - proxy->PassFormDataPredictions( + mojo::Remote<mojom::TypeTraitsTest> remote(GetTypeTraitsTestRemote()); + remote->PassFormDataPredictions( input, base::BindOnce(&ExpectFormDataPredictions, input, loop.QuitClosure())); loop.Run(); @@ -409,8 +368,8 @@ TEST_F(AutofillTypeTraitsTestImpl, PassPasswordFormFillData) { CreateTestPasswordFormFillData(&input); base::RunLoop loop; - mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy(); - proxy->PassPasswordFormFillData( + mojo::Remote<mojom::TypeTraitsTest> remote(GetTypeTraitsTestRemote()); + remote->PassPasswordFormFillData( input, base::BindOnce(&ExpectPasswordFormFillData, input, loop.QuitClosure())); loop.Run(); @@ -422,8 +381,8 @@ TEST_F(AutofillTypeTraitsTestImpl, PasswordFormGenerationData) { input.confirmation_password_renderer_id = 5789u; base::RunLoop loop; - mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy(); - proxy->PassPasswordFormGenerationData( + mojo::Remote<mojom::TypeTraitsTest> remote(GetTypeTraitsTestRemote()); + remote->PassPasswordFormGenerationData( input, base::BindOnce(&ExpectPasswordFormGenerationData, input, loop.QuitClosure())); loop.Run(); @@ -434,8 +393,8 @@ TEST_F(AutofillTypeTraitsTestImpl, PassPasswordGenerationUIData) { CreatePasswordGenerationUIData(&input); base::RunLoop loop; - mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy(); - proxy->PassPasswordGenerationUIData( + mojo::Remote<mojom::TypeTraitsTest> remote(GetTypeTraitsTestRemote()); + remote->PassPasswordGenerationUIData( input, base::BindOnce(&ExpectPasswordGenerationUIData, input, loop.QuitClosure())); loop.Run(); @@ -446,22 +405,10 @@ TEST_F(AutofillTypeTraitsTestImpl, PassPasswordForm) { CreateTestPasswordForm(&input); base::RunLoop loop; - mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy(); - proxy->PassPasswordForm( + mojo::Remote<mojom::TypeTraitsTest> remote(GetTypeTraitsTestRemote()); + remote->PassPasswordForm( input, base::BindOnce(&ExpectPasswordForm, input, loop.QuitClosure())); loop.Run(); } -TEST_F(AutofillTypeTraitsTestImpl, PassFormsPredictionsMap) { - FormsPredictionsMap input; - CreateTestFormsPredictionsMap(&input); - - base::RunLoop loop; - mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy(); - proxy->PassFormsPredictionsMap( - input, - base::BindOnce(&ExpectFormsPredictionsMap, input, loop.QuitClosure())); - loop.Run(); -} - } // namespace autofill diff --git a/chromium/components/autofill/core/common/mojom/test_autofill_types.mojom b/chromium/components/autofill/core/common/mojom/test_autofill_types.mojom index 9f5be9e3b81..dd1392662f1 100644 --- a/chromium/components/autofill/core/common/mojom/test_autofill_types.mojom +++ b/chromium/components/autofill/core/common/mojom/test_autofill_types.mojom @@ -16,8 +16,6 @@ interface TypeTraitsTest { PassPasswordForm(PasswordForm s) => (PasswordForm passed); PassPasswordFormFillData(PasswordFormFillData s) => (PasswordFormFillData passed); - PassFormsPredictionsMap(FormsPredictionsMap s) => - (FormsPredictionsMap passed); PassPasswordFormGenerationData(PasswordFormGenerationData s) => (PasswordFormGenerationData passed); PassPasswordGenerationUIData(PasswordGenerationUIData s) => diff --git a/chromium/components/autofill/core/common/password_form.cc b/chromium/components/autofill/core/common/password_form.cc index fc34f742b52..d6f0044c8ea 100644 --- a/chromium/components/autofill/core/common/password_form.cc +++ b/chromium/components/autofill/core/common/password_form.cc @@ -26,6 +26,17 @@ std::string ToString(const T& obj) { return ostream.str(); } +std::string StoreToString(PasswordForm::Store from_store) { + switch (from_store) { + case PasswordForm::Store::kNotSet: + return "Not Set"; + case PasswordForm::Store::kProfileStore: + return "Profile Store"; + case PasswordForm::Store::kAccountStore: + return "Account Store"; + } +} + // Serializes a PasswordForm to a JSON object. Used only for logging in tests. void PasswordFormToJSON(const PasswordForm& form, base::DictionaryValue* target) { @@ -85,6 +96,7 @@ void PasswordFormToJSON(const PasswordForm& form, target->SetBoolean("is_gaia_with_skip_save_password_form", form.form_data.is_gaia_with_skip_save_password_form); target->SetBoolean("is_new_password_reliable", form.is_new_password_reliable); + target->SetString("from_store", StoreToString(form.from_store)); } } // namespace @@ -136,6 +148,10 @@ bool PasswordForm::IsSingleUsername() const { !HasNewPasswordElement(); } +bool PasswordForm::IsUsingAccountStore() const { + return from_store == Store::kAccountStore; +} + bool PasswordForm::operator==(const PasswordForm& form) const { return scheme == form.scheme && signon_realm == form.signon_realm && origin == form.origin && action == form.action && @@ -180,7 +196,8 @@ bool PasswordForm::operator==(const PasswordForm& form) const { app_icon_url == form.app_icon_url && submission_event == form.submission_event && only_for_fallback == form.only_for_fallback && - is_new_password_reliable == form.is_new_password_reliable; + is_new_password_reliable == form.is_new_password_reliable && + from_store == form.from_store; } bool PasswordForm::operator!=(const PasswordForm& form) const { @@ -196,28 +213,6 @@ bool ArePasswordFormUniqueKeysEqual(const PasswordForm& left, left.password_element == right.password_element); } -bool LessThanUniqueKey::operator()( - const std::unique_ptr<PasswordForm>& left, - const std::unique_ptr<PasswordForm>& right) const { - int result = left->signon_realm.compare(right->signon_realm); - if (result) - return result < 0; - - result = left->username_element.compare(right->username_element); - if (result) - return result < 0; - - result = left->username_value.compare(right->username_value); - if (result) - return result < 0; - - result = left->password_element.compare(right->password_element); - if (result) - return result < 0; - - return left->origin < right->origin; -} - base::string16 ValueElementVectorToString( const ValueElementVector& value_element_pairs) { std::vector<base::string16> pairs(value_element_pairs.size()); @@ -228,12 +223,6 @@ base::string16 ValueElementVectorToString( return base::JoinString(pairs, base::ASCIIToUTF16(", ")); } -bool IsHttpAuthScheme(PasswordForm::Scheme scheme) { - return scheme == PasswordForm::Scheme::kBasic || - scheme == PasswordForm::Scheme::kDigest || - scheme == PasswordForm::Scheme::kOther; -} - std::ostream& operator<<(std::ostream& os, const PasswordForm& form) { base::DictionaryValue form_json; PasswordFormToJSON(form, &form_json); diff --git a/chromium/components/autofill/core/common/password_form.h b/chromium/components/autofill/core/common/password_form.h index 348900b8212..48e63390f8b 100644 --- a/chromium/components/autofill/core/common/password_form.h +++ b/chromium/components/autofill/core/common/password_form.h @@ -303,6 +303,16 @@ struct PasswordForm { // as signal for password generation eligibility. bool is_new_password_reliable = false; + enum class Store { + // Default value. + kNotSet, + // Credential came from the profile (i.e. local) storage. + kProfileStore, + // Credential came from the Gaia-account-scoped storage. + kAccountStore + }; + Store from_store = Store::kNotSet; + // Return true if we consider this form to be a change password form. // We use only client heuristics, so it could include signup forms. bool IsPossibleChangePasswordForm() const; @@ -328,6 +338,10 @@ struct PasswordForm { // not set. bool IsSingleUsername() const; + // Returns whether this form is stored in the account-scoped store, i.e. + // whether |from_store == Store::kAccountStore|. + bool IsUsingAccountStore() const; + // Equality operators for testing. bool operator==(const PasswordForm& form) const; bool operator!=(const PasswordForm& form) const; @@ -346,19 +360,10 @@ struct PasswordForm { bool ArePasswordFormUniqueKeysEqual(const PasswordForm& left, const PasswordForm& right); -// A comparator for the unique key. -struct LessThanUniqueKey { - bool operator()(const std::unique_ptr<PasswordForm>& left, - const std::unique_ptr<PasswordForm>& right) const; -}; - // Converts a vector of ValueElementPair to string. base::string16 ValueElementVectorToString( const ValueElementVector& value_element_pairs); -// Returns true if |scheme| corresponds to http auth scheme. -bool IsHttpAuthScheme(PasswordForm::Scheme scheme); - // For testing. std::ostream& operator<<(std::ostream& os, const PasswordForm& form); std::ostream& operator<<(std::ostream& os, PasswordForm* form); diff --git a/chromium/components/autofill/core/common/password_form_field_prediction_map.h b/chromium/components/autofill/core/common/password_form_field_prediction_map.h deleted file mode 100644 index b0d149c092c..00000000000 --- a/chromium/components/autofill/core/common/password_form_field_prediction_map.h +++ /dev/null @@ -1,22 +0,0 @@ -// 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. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_FORM_FIELD_PREDICTION_MAP_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_FORM_FIELD_PREDICTION_MAP_H_ - -#include "base/containers/flat_map.h" -#include "components/autofill/core/common/form_data.h" -#include "components/autofill/core/common/form_field_data.h" -#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h" - -namespace autofill { - -using PasswordFormFieldPredictionMap = - base::flat_map<FormFieldData, mojom::PasswordFormFieldPredictionType>; -using FormsPredictionsMap = - base::flat_map<FormData, PasswordFormFieldPredictionMap>; - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_FORM_FIELD_PREDICTION_MAP_H_ diff --git a/chromium/components/autofill/core/common/password_form_fill_data.cc b/chromium/components/autofill/core/common/password_form_fill_data.cc index db08ce036bb..06b7eb4de26 100644 --- a/chromium/components/autofill/core/common/password_form_fill_data.cc +++ b/chromium/components/autofill/core/common/password_form_fill_data.cc @@ -24,7 +24,7 @@ PasswordFormFillData::PasswordFormFillData() = default; PasswordFormFillData::PasswordFormFillData( const PasswordForm& form_on_page, - const std::map<base::string16, const PasswordForm*>& matches, + const std::vector<const PasswordForm*>& matches, const PasswordForm& preferred_match, bool wait_for_username) : form_renderer_id(form_on_page.form_data.unique_renderer_id), @@ -65,17 +65,25 @@ PasswordFormFillData::PasswordFormFillData( preferred_realm = preferred_match.signon_realm; // Copy additional username/value pairs. - for (const auto& it : matches) { - if (it.second != &preferred_match) { - PasswordAndRealm& value = additional_logins[it.first]; - value.password = it.second->password_value; - if (IsPublicSuffixMatchOrAffiliationBasedMatch(*it.second)) - value.realm = it.second->signon_realm; - } + for (const PasswordForm* match : matches) { + if (match == &preferred_match) + continue; + PasswordAndRealm& value = additional_logins[match->username_value]; + value.password = match->password_value; + if (IsPublicSuffixMatchOrAffiliationBasedMatch(*match)) + value.realm = match->signon_realm; } } -PasswordFormFillData::PasswordFormFillData(const PasswordFormFillData& other) = +PasswordFormFillData::PasswordFormFillData(const PasswordFormFillData&) = + default; + +PasswordFormFillData& PasswordFormFillData::operator=( + const PasswordFormFillData&) = default; + +PasswordFormFillData::PasswordFormFillData(PasswordFormFillData&&) = default; + +PasswordFormFillData& PasswordFormFillData::operator=(PasswordFormFillData&&) = default; PasswordFormFillData::~PasswordFormFillData() = default; diff --git a/chromium/components/autofill/core/common/password_form_fill_data.h b/chromium/components/autofill/core/common/password_form_fill_data.h index dfe6586ffbb..a94a1aeeb28 100644 --- a/chromium/components/autofill/core/common/password_form_fill_data.h +++ b/chromium/components/autofill/core/common/password_form_fill_data.h @@ -6,12 +6,21 @@ #define COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_FILL_DATA_H_ #include <map> +#include <vector> #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/password_form.h" namespace autofill { +// Contains renderer ids of password related elements found by the form parser. +struct ParsingResult { + uint32_t username_renderer_id; + uint32_t password_renderer_id; + uint32_t new_password_renderer_id; + uint32_t confirm_password_renderer_id; +}; + struct PasswordAndRealm { base::string16 password; std::string realm; @@ -32,14 +41,15 @@ struct PasswordFormFillData { // not autofill anything until the user typed in a valid username and blurred // the field. If |enable_possible_usernames| is true, we will populate // possible_usernames. - PasswordFormFillData( - const PasswordForm& form_on_page, - const std::map<base::string16, const PasswordForm*>& matches, - const PasswordForm& preferred_match, - bool wait_for_username); - - PasswordFormFillData(const PasswordFormFillData& other); - + PasswordFormFillData(const PasswordForm& form_on_page, + const std::vector<const PasswordForm*>& matches, + const PasswordForm& preferred_match, + bool wait_for_username); + + PasswordFormFillData(const PasswordFormFillData&); + PasswordFormFillData& operator=(const PasswordFormFillData&); + PasswordFormFillData(PasswordFormFillData&&); + PasswordFormFillData& operator=(PasswordFormFillData&&); ~PasswordFormFillData(); // If |has_renderer_ids| == true then |form_renderer_id| contains the unique @@ -89,7 +99,6 @@ struct PasswordFormFillData { // TODO(https://crbug.com/831123): Remove this field when old parsing is // removed and filling by renderer ids is by default. bool has_renderer_ids = false; - }; // If |data.wait_for_username| is set, the renderer does not need to receive diff --git a/chromium/components/autofill/core/common/password_form_fill_data_unittest.cc b/chromium/components/autofill/core/common/password_form_fill_data_unittest.cc index b794cc1115f..2c863d433dd 100644 --- a/chromium/components/autofill/core/common/password_form_fill_data_unittest.cc +++ b/chromium/components/autofill/core/common/password_form_fill_data_unittest.cc @@ -47,7 +47,7 @@ TEST(PasswordFormFillDataTest, TestSinglePreferredMatch) { preferred_match.preferred = true; preferred_match.scheme = PasswordForm::Scheme::kHtml; - std::map<base::string16, const PasswordForm*> matches; + std::vector<const PasswordForm*> matches; PasswordFormFillData result(form_on_page, matches, preferred_match, true); @@ -127,10 +127,8 @@ TEST(PasswordFormFillDataTest, TestPublicSuffixDomainMatching) { public_suffix_match.scheme = PasswordForm::Scheme::kHtml; // Add one exact match and one public suffix match. - std::map<base::string16, const PasswordForm*> matches; - matches.insert(std::make_pair(exact_match.username_value, &exact_match)); - matches.insert( - std::make_pair(public_suffix_match.username_value, &public_suffix_match)); + std::vector<const PasswordForm*> matches = {&exact_match, + &public_suffix_match}; PasswordFormFillData result(form_on_page, matches, preferred_match, true); EXPECT_TRUE(result.wait_for_username); @@ -202,10 +200,7 @@ TEST(PasswordFormFillDataTest, TestAffiliationMatch) { affiliated_match.scheme = PasswordForm::Scheme::kHtml; // Add one exact match and one affiliation based match. - std::map<base::string16, const PasswordForm*> matches; - matches.insert(std::make_pair(exact_match.username_value, &exact_match)); - matches.insert( - std::make_pair(affiliated_match.username_value, &affiliated_match)); + std::vector<const PasswordForm*> matches = {&exact_match, &affiliated_match}; PasswordFormFillData result(form_on_page, matches, preferred_match, false); EXPECT_FALSE(result.wait_for_username); @@ -249,9 +244,7 @@ TEST(PasswordFormFillDataTest, RendererIDs) { form_on_page.username_element_renderer_id = 123; form_on_page.password_element_renderer_id = 456; - std::map<base::string16, const PasswordForm*> matches; - - PasswordFormFillData result(form_on_page, matches, preferred_match, true); + PasswordFormFillData result(form_on_page, {}, preferred_match, true); EXPECT_EQ(form_data.unique_renderer_id, result.form_renderer_id); EXPECT_EQ(form_on_page.has_renderer_ids, result.has_renderer_ids); diff --git a/chromium/components/autofill/core/common/password_generation_util.cc b/chromium/components/autofill/core/common/password_generation_util.cc index 8bab183bf31..6f89ed2622d 100644 --- a/chromium/components/autofill/core/common/password_generation_util.cc +++ b/chromium/components/autofill/core/common/password_generation_util.cc @@ -17,12 +17,14 @@ PasswordGenerationUIData::PasswordGenerationUIData( int max_length, const base::string16& generation_element, uint32_t generation_element_id, + bool is_generation_element_password_type, base::i18n::TextDirection text_direction, const autofill::PasswordForm& password_form) : bounds(bounds), max_length(max_length), generation_element(generation_element), generation_element_id(generation_element_id), + is_generation_element_password_type(is_generation_element_password_type), text_direction(text_direction), password_form(password_form) {} diff --git a/chromium/components/autofill/core/common/password_generation_util.h b/chromium/components/autofill/core/common/password_generation_util.h index e3da088110b..c2143d13476 100644 --- a/chromium/components/autofill/core/common/password_generation_util.h +++ b/chromium/components/autofill/core/common/password_generation_util.h @@ -109,6 +109,7 @@ struct PasswordGenerationUIData { int max_length, const base::string16& generation_element, uint32_t generation_element_id, + bool is_generation_element_password_type, base::i18n::TextDirection text_direction, const autofill::PasswordForm& password_form); PasswordGenerationUIData(); @@ -132,6 +133,9 @@ struct PasswordGenerationUIData { // Renderer ID of the generation element. uint32_t generation_element_id; + // Is the generation element |type=password|. + bool is_generation_element_password_type; + // Direction of the text for |generation_element|. base::i18n::TextDirection text_direction; @@ -141,10 +145,6 @@ struct PasswordGenerationUIData { void LogPasswordGenerationEvent(PasswordGenerationEvent event); -// Returns true if Password Generation is enabled according to the field -// trial result and the flags. -bool IsPasswordGenerationEnabled(); - } // namespace password_generation } // namespace autofill diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.cc b/chromium/components/autofill/core/common/save_password_progress_logger.cc index 91807e55dce..b4bd692a753 100644 --- a/chromium/components/autofill/core/common/save_password_progress_logger.cc +++ b/chromium/components/autofill/core/common/save_password_progress_logger.cc @@ -275,16 +275,8 @@ std::string SavePasswordProgressLogger::GetStringFromID( return "provisionally_saved_forms_[form_frame]"; case SavePasswordProgressLogger::STRING_PROVISIONALLY_SAVE_FORM_METHOD: return "PasswordManager::ProvisionallySaveForm"; - case SavePasswordProgressLogger::STRING_IS_SAVING_ENABLED: - return "IsSavingAndFillingEnabled"; case SavePasswordProgressLogger::STRING_EMPTY_PASSWORD: return "Empty password"; - case SavePasswordProgressLogger::STRING_EXACT_MATCH: - return "Form manager found, exact match"; - case SavePasswordProgressLogger::STRING_MATCH_WITHOUT_ACTION: - return "Form manager found, match except for action"; - case SavePasswordProgressLogger::STRING_ORIGINS_MATCH: - return "Form manager found, only origins match"; case SavePasswordProgressLogger::STRING_MATCHING_NOT_COMPLETE: return "No form manager has completed matching"; case SavePasswordProgressLogger::STRING_FORM_BLACKLISTED: @@ -295,8 +287,6 @@ std::string SavePasswordProgressLogger::GetStringFromID( return "Credential is used for syncing passwords"; case STRING_BLOCK_PASSWORD_SAME_ORIGIN_INSECURE_SCHEME: return "Blocked password due to same origin but insecure scheme"; - case SavePasswordProgressLogger::STRING_PROVISIONALLY_SAVED_FORM: - return "provisionally_saved_form"; case SavePasswordProgressLogger::STRING_ON_PASSWORD_FORMS_RENDERED_METHOD: return "PasswordManager::OnPasswordFormsRendered"; case SavePasswordProgressLogger::STRING_ON_SAME_DOCUMENT_NAVIGATION: @@ -323,8 +313,6 @@ std::string SavePasswordProgressLogger::GetStringFromID( return "Show password prompt"; case SavePasswordProgressLogger::STRING_PASSWORDMANAGER_AUTOFILL: return "PasswordManager::Autofill"; - case SavePasswordProgressLogger::STRING_PASSWORDMANAGER_AUTOFILLHTTPAUTH: - return "PasswordManager::AutofillHttpAuth"; case SavePasswordProgressLogger:: STRING_PASSWORDMANAGER_SHOW_INITIAL_PASSWORD_ACCOUNT_SUGGESTIONS: return "PasswordManager::ShowInitialPasswordAccountSuggestions"; @@ -338,10 +326,6 @@ std::string SavePasswordProgressLogger::GetStringFromID( case SavePasswordProgressLogger:: STRING_PROVISIONALLY_SAVED_FORM_IS_NOT_HTML: return "Provisionally saved form is not HTML"; - case SavePasswordProgressLogger::STRING_ON_FETCH_COMPLETED_METHOD: - return "PasswordFormManager::OnFetchCompleted"; - case SavePasswordProgressLogger::STRING_BEST_SCORE: - return "best_score"; case SavePasswordProgressLogger::STRING_ON_GET_STORE_RESULTS_METHOD: return "FormFetcherImpl::OnGetPasswordStoreResults"; case SavePasswordProgressLogger::STRING_NUMBER_RESULTS: @@ -352,8 +336,6 @@ std::string SavePasswordProgressLogger::GetStringFromID( return "PasswordStore is not available"; case SavePasswordProgressLogger::STRING_CREATE_LOGIN_MANAGERS_METHOD: return "PasswordManager::CreatePendingLoginManagers"; - case SavePasswordProgressLogger::STRING_NEW_NUMBER_LOGIN_MANAGERS: - return "Number of pending login managers (after)"; case SavePasswordProgressLogger:: STRING_PASSWORD_MANAGEMENT_ENABLED_FOR_CURRENT_PAGE: return "IsPasswordManagementEnabledForCurrentPage"; @@ -361,12 +343,6 @@ std::string SavePasswordProgressLogger::GetStringFromID( return "ShowLoginPrompt"; case SavePasswordProgressLogger::STRING_NEW_UI_STATE: return "The new state of the UI"; - case SavePasswordProgressLogger::STRING_FORM_NOT_AUTOFILLED: - return "The observed form will not be autofilled"; - case SavePasswordProgressLogger::STRING_CHANGE_PASSWORD_FORM: - return "Not saving password for a change password form"; - case SavePasswordProgressLogger::STRING_PROCESS_FRAME_METHOD: - return "PasswordFormManager::ProcessFrame"; case SavePasswordProgressLogger::STRING_FORM_SIGNATURE: return "Signature of form"; case SavePasswordProgressLogger::STRING_FORM_FETCHER_STATE: @@ -405,8 +381,6 @@ std::string SavePasswordProgressLogger::GetStringFromID( return "Form name"; case SavePasswordProgressLogger::STRING_FIELDS: return "Form fields"; - case SavePasswordProgressLogger::STRING_FORM_VOTES: - return "Form votes"; case SavePasswordProgressLogger::STRING_FIRSTUSE_FORM_VOTE: return "FirstUse vote"; case SavePasswordProgressLogger::STRING_PASSWORD_FORM_VOTE: @@ -417,26 +391,6 @@ std::string SavePasswordProgressLogger::GetStringFromID( return "Generation disabled: saving disabled"; case SavePasswordProgressLogger::STRING_GENERATION_DISABLED_NO_SYNC: return "Generation disabled: no sync"; - case STRING_GENERATION_RENDERER_INVALID_PASSWORD_FORM: - return "Generation invalid PasswordForm"; - case STRING_GENERATION_RENDERER_POSSIBLE_ACCOUNT_CREATION_FORMS: - return "Generation possible account creation forms"; - case STRING_GENERATION_RENDERER_NO_PASSWORD_MANAGER_ACCESS: - return "Generation: no PasswordManager access"; - case STRING_GENERATION_RENDERER_FORM_ALREADY_FOUND: - return "Generation: account creation form already found"; - case STRING_GENERATION_RENDERER_NO_POSSIBLE_CREATION_FORMS: - return "Generation: no possible account creation forms"; - case STRING_GENERATION_RENDERER_NOT_BLACKLISTED: - return "Generation: no non-blacklisted confirmation"; - case STRING_GENERATION_RENDERER_AUTOCOMPLETE_ATTRIBUTE: - return "Generation: autocomplete attributes found"; - case STRING_GENERATION_RENDERER_NO_SERVER_SIGNAL: - return "Generation: no server signal"; - case STRING_GENERATION_RENDERER_ELIGIBLE_FORM_FOUND: - return "Generation: eligible form found"; - case STRING_GENERATION_RENDERER_NO_FIELD_FOUND: - return "Generation: fields for generation are not found"; case STRING_GENERATION_RENDERER_AUTOMATIC_GENERATION_AVAILABLE: return "Generation: automatic generation is available"; case STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP: @@ -463,8 +417,6 @@ std::string SavePasswordProgressLogger::GetStringFromID( "exists whose username matches the prefilled value"; case STRING_FAILED_TO_FILL_FOUND_NO_PASSWORD_FOR_USERNAME: return "Failed to fill: No credential matching found"; - case SavePasswordProgressLogger::STRING_HTTPAUTH_OBSERVER_PRESENT: - return "Instances of HttpAuthObserver are present"; case SavePasswordProgressLogger:: STRING_HTTPAUTH_ON_ASK_USER_OR_SAVE_PASSWORD: return "HttpAuthManager::AskUserOrSavePassword"; @@ -476,26 +428,22 @@ std::string SavePasswordProgressLogger::GetStringFromID( return "HttpAuthManager::DetachObserver"; case SavePasswordProgressLogger::STRING_SHOW_ONBOARDING: return "Show onboarding experience and offer to save password"; + case STRING_LEAK_DETECTION_DISABLED_FEATURE: + return "Leak detection disabled in settings"; + case STRING_LEAK_DETECTION_DISABLED_SAFE_BROWSING: + return "Leak detection is off as the safe browsing is disabled"; case STRING_LEAK_DETECTION_FINISHED: return "Leak detection finished with result"; case STRING_LEAK_DETECTION_SIGNED_OUT_ERROR: return "Leak detection failed: signed out"; case STRING_LEAK_DETECTION_TOKEN_REQUEST_ERROR: return "Leak detection failed: can't get a token"; - case STRING_LEAK_DETECTION_ENCRYPTION_ERROR: - return "Leak detection failed: encryption"; case STRING_LEAK_DETECTION_INVALID_SERVER_RESPONSE_ERROR: return "Leak detection failed: invalid server response"; case SavePasswordProgressLogger:: STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_LOWERCASE: return "Uploading password requirements vote for using lowercase letters"; case SavePasswordProgressLogger:: - STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_UPPERCASE: - return "Uploading password requirements vote for using lowercase letters"; - case SavePasswordProgressLogger:: - STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_NUMERICS: - return "Uploading password requirements vote for using numbers"; - case SavePasswordProgressLogger:: STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_SPECIAL_SYMBOL: return "Uploading password requirements vote for using special symbols"; case SavePasswordProgressLogger:: @@ -504,9 +452,6 @@ std::string SavePasswordProgressLogger::GetStringFromID( case SavePasswordProgressLogger:: STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_PASSWORD_LENGTH: return "Uploading password requirements vote for password length"; - case SavePasswordProgressLogger:: - STRING_PASSWORD_REQUIREMENTS_VOTE_NO_PASSWORD_ATTRIBUTES: - return "No password requirements attributed set"; case STRING_SAVE_PASSWORD_HASH: return "Password hash is saved"; case STRING_DID_NAVIGATE_MAIN_FRAME: @@ -515,6 +460,8 @@ std::string SavePasswordProgressLogger::GetStringFromID( return "Navigation to New Tab page"; case STRING_SERVER_PREDICTIONS: return "Server predictions"; + case STRING_USERNAME_FIRST_FLOW_VOTE: + return "Username first flow vote"; case SavePasswordProgressLogger::STRING_INVALID: return "INVALID"; // Intentionally no default: clause here -- all IDs need to get covered. diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.h b/chromium/components/autofill/core/common/save_password_progress_logger.h index f1899def840..f6f4a681b76 100644 --- a/chromium/components/autofill/core/common/save_password_progress_logger.h +++ b/chromium/components/autofill/core/common/save_password_progress_logger.h @@ -78,17 +78,12 @@ class SavePasswordProgressLogger { STRING_FRAME_NOT_MAIN_FRAME, STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME, STRING_PROVISIONALLY_SAVE_FORM_METHOD, - STRING_IS_SAVING_ENABLED, STRING_EMPTY_PASSWORD, - STRING_EXACT_MATCH, - STRING_MATCH_WITHOUT_ACTION, - STRING_ORIGINS_MATCH, STRING_MATCHING_NOT_COMPLETE, STRING_FORM_BLACKLISTED, STRING_INVALID_FORM, STRING_SYNC_CREDENTIAL, STRING_BLOCK_PASSWORD_SAME_ORIGIN_INSECURE_SCHEME, - STRING_PROVISIONALLY_SAVED_FORM, STRING_ON_PASSWORD_FORMS_RENDERED_METHOD, STRING_ON_SAME_DOCUMENT_NAVIGATION, STRING_ON_ASK_USER_OR_SAVE_PASSWORD, @@ -102,26 +97,19 @@ class SavePasswordProgressLogger { STRING_ONLY_VISIBLE, STRING_SHOW_PASSWORD_PROMPT, STRING_PASSWORDMANAGER_AUTOFILL, - STRING_PASSWORDMANAGER_AUTOFILLHTTPAUTH, STRING_PASSWORDMANAGER_SHOW_INITIAL_PASSWORD_ACCOUNT_SUGGESTIONS, STRING_WAIT_FOR_USERNAME, STRING_WAS_LAST_NAVIGATION_HTTP_ERROR_METHOD, STRING_HTTP_STATUS_CODE, STRING_PROVISIONALLY_SAVED_FORM_IS_NOT_HTML, - STRING_ON_FETCH_COMPLETED_METHOD, - STRING_BEST_SCORE, STRING_ON_GET_STORE_RESULTS_METHOD, STRING_NUMBER_RESULTS, STRING_FETCH_METHOD, STRING_NO_STORE, STRING_CREATE_LOGIN_MANAGERS_METHOD, - STRING_NEW_NUMBER_LOGIN_MANAGERS, STRING_PASSWORD_MANAGEMENT_ENABLED_FOR_CURRENT_PAGE, STRING_SHOW_LOGIN_PROMPT_METHOD, STRING_NEW_UI_STATE, - STRING_FORM_NOT_AUTOFILLED, - STRING_CHANGE_PASSWORD_FORM, - STRING_PROCESS_FRAME_METHOD, STRING_FORM_SIGNATURE, STRING_FORM_FETCHER_STATE, STRING_UNOWNED_INPUTS_VISIBLE, @@ -140,22 +128,11 @@ class SavePasswordProgressLogger { STRING_PASSWORD_FILLED, STRING_FORM_NAME, STRING_FIELDS, - STRING_FORM_VOTES, STRING_FIRSTUSE_FORM_VOTE, STRING_PASSWORD_FORM_VOTE, STRING_REUSE_FOUND, STRING_GENERATION_DISABLED_SAVING_DISABLED, STRING_GENERATION_DISABLED_NO_SYNC, - STRING_GENERATION_RENDERER_INVALID_PASSWORD_FORM, - STRING_GENERATION_RENDERER_POSSIBLE_ACCOUNT_CREATION_FORMS, - STRING_GENERATION_RENDERER_NO_PASSWORD_MANAGER_ACCESS, - STRING_GENERATION_RENDERER_FORM_ALREADY_FOUND, - STRING_GENERATION_RENDERER_NO_POSSIBLE_CREATION_FORMS, - STRING_GENERATION_RENDERER_NOT_BLACKLISTED, - STRING_GENERATION_RENDERER_AUTOCOMPLETE_ATTRIBUTE, - STRING_GENERATION_RENDERER_NO_SERVER_SIGNAL, - STRING_GENERATION_RENDERER_ELIGIBLE_FORM_FOUND, - STRING_GENERATION_RENDERER_NO_FIELD_FOUND, STRING_GENERATION_RENDERER_AUTOMATIC_GENERATION_AVAILABLE, STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP, STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED, @@ -168,28 +145,26 @@ class SavePasswordProgressLogger { STRING_FAILED_TO_FILL_NO_AUTOCOMPLETEABLE_ELEMENT, STRING_FAILED_TO_FILL_PREFILLED_USERNAME, STRING_FAILED_TO_FILL_FOUND_NO_PASSWORD_FOR_USERNAME, - STRING_HTTPAUTH_OBSERVER_PRESENT, STRING_HTTPAUTH_ON_ASK_USER_OR_SAVE_PASSWORD, STRING_HTTPAUTH_ON_PROMPT_USER, STRING_HTTPAUTH_ON_SET_OBSERVER, STRING_HTTPAUTH_ON_DETACH_OBSERVER, STRING_SHOW_ONBOARDING, + STRING_LEAK_DETECTION_DISABLED_FEATURE, + STRING_LEAK_DETECTION_DISABLED_SAFE_BROWSING, STRING_LEAK_DETECTION_FINISHED, STRING_LEAK_DETECTION_SIGNED_OUT_ERROR, STRING_LEAK_DETECTION_TOKEN_REQUEST_ERROR, - STRING_LEAK_DETECTION_ENCRYPTION_ERROR, STRING_LEAK_DETECTION_INVALID_SERVER_RESPONSE_ERROR, STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_LOWERCASE, - STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_UPPERCASE, - STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_NUMERICS, STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_SPECIAL_SYMBOL, STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_SPECIFIC_SPECIAL_SYMBOL, STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_PASSWORD_LENGTH, - STRING_PASSWORD_REQUIREMENTS_VOTE_NO_PASSWORD_ATTRIBUTES, STRING_SAVE_PASSWORD_HASH, STRING_DID_NAVIGATE_MAIN_FRAME, STRING_NAVIGATION_NTP, STRING_SERVER_PREDICTIONS, + STRING_USERNAME_FIRST_FLOW_VOTE, STRING_INVALID, // Represents a string returned in a case of an error. STRING_MAX = STRING_INVALID }; |