diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-03-11 11:32:04 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-03-18 13:40:17 +0000 |
commit | 31ccca0778db85c159634478b4ec7997f6704860 (patch) | |
tree | 3d33fc3afd9d5ec95541e1bbe074a9cf8da12a0e /chromium/components/autofill/core/common | |
parent | 248b70b82a40964d5594eb04feca0fa36716185d (diff) | |
download | qtwebengine-chromium-31ccca0778db85c159634478b4ec7997f6704860.tar.gz |
BASELINE: Update Chromium to 80.0.3987.136
Change-Id: I98e1649aafae85ba3a83e67af00bb27ef301db7b
Reviewed-by: Jüri Valdmann <juri.valdmann@qt.io>
Diffstat (limited to 'chromium/components/autofill/core/common')
28 files changed, 274 insertions, 356 deletions
diff --git a/chromium/components/autofill/core/common/BUILD.gn b/chromium/components/autofill/core/common/BUILD.gn index 2f096cab5d5..98837b9f690 100644 --- a/chromium/components/autofill/core/common/BUILD.gn +++ b/chromium/components/autofill/core/common/BUILD.gn @@ -67,6 +67,7 @@ jumbo_static_library("common") { "//components/prefs", "//components/variations", "//crypto", + "//google_apis:google_apis", "//ui/base", "//ui/gfx/geometry", "//url", @@ -99,6 +100,7 @@ source_set("unit_tests") { "//components/pref_registry", "//components/prefs", "//components/prefs:test_support", + "//google_apis:google_apis", "//testing/gmock", "//testing/gtest", "//url", diff --git a/chromium/components/autofill/core/common/DEPS b/chromium/components/autofill/core/common/DEPS index 41f0daa03c5..163b88c9576 100644 --- a/chromium/components/autofill/core/common/DEPS +++ b/chromium/components/autofill/core/common/DEPS @@ -1,3 +1,4 @@ include_rules = [ "+crypto/sha2.h", + "+google_apis/gaia/core_account_id.h", ] diff --git a/chromium/components/autofill/core/common/autofill_features.cc b/chromium/components/autofill/core/common/autofill_features.cc index 7f4ca82a5bf..627d4a9d267 100644 --- a/chromium/components/autofill/core/common/autofill_features.cc +++ b/chromium/components/autofill/core/common/autofill_features.cc @@ -54,6 +54,10 @@ const base::Feature kAutofillEnableAccountWalletStorage{ const base::Feature kAutofillEnableCompanyName{ "AutofillEnableCompanyName", base::FEATURE_ENABLED_BY_DEFAULT}; +// Controls whether we show "Hide suggestions" item in the suggestions menu. +const base::Feature kAutofillEnableHideSuggestionsUI{ + "AutofillEnableHideSuggestionsUI", base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether or not a minimum number of fields is required before // heuristic field type prediction is run for a form. const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics{ diff --git a/chromium/components/autofill/core/common/autofill_features.h b/chromium/components/autofill/core/common/autofill_features.h index 78a8bfcbbbc..1306a9f82bf 100644 --- a/chromium/components/autofill/core/common/autofill_features.h +++ b/chromium/components/autofill/core/common/autofill_features.h @@ -29,6 +29,7 @@ extern const base::Feature kAutofillCreateDataForTest; extern const base::Feature kAutofillCreditCardAssist; extern const base::Feature kAutofillEnableAccountWalletStorage; extern const base::Feature kAutofillEnableCompanyName; +extern const base::Feature kAutofillEnableHideSuggestionsUI; extern const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics; extern const base::Feature kAutofillEnforceMinRequiredFieldsForQuery; extern const base::Feature kAutofillEnforceMinRequiredFieldsForUpload; 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 a7232ce6cbb..8f4eb5f6a59 100644 --- a/chromium/components/autofill/core/common/autofill_internals/log_message.h +++ b/chromium/components/autofill/core/common/autofill_internals/log_message.h @@ -28,7 +28,9 @@ class LogBuffer; "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.") + "Abort parsing form: Form has no text field.") \ + T(FunnelMetrics, "Funnel Metrics") \ + T(KeyMetrics, "Key Metrics") // Log messages for chrome://autofill-internals. #define AUTOFILL_TEMPLATE(NAME, MESSAGE) k##NAME, 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 5684511f84e..f9f8339ae3b 100644 --- a/chromium/components/autofill/core/common/autofill_internals/logging_scope.h +++ b/chromium/components/autofill/core/common/autofill_internals/logging_scope.h @@ -25,7 +25,9 @@ class LogBuffer; /* Log messages related to the submission of forms. */ \ T(Submission) \ /* Log messages related to communication with autofill server. */ \ - T(AutofillServer) + T(AutofillServer) \ + /* Log messages related to metrics collection. */ \ + T(Metrics) // Define a bunch of logging scopes: kContext, kParsing, ... #define AUTOFILL_TEMPLATE(NAME) k##NAME, diff --git a/chromium/components/autofill/core/common/autofill_payments_features.cc b/chromium/components/autofill/core/common/autofill_payments_features.cc index d5a33bdaa85..6063755cd24 100644 --- a/chromium/components/autofill/core/common/autofill_payments_features.cc +++ b/chromium/components/autofill/core/common/autofill_payments_features.cc @@ -20,20 +20,6 @@ namespace autofill { namespace features { -const char kAutofillSaveCreditCardUsesImprovedMessagingParamName[] = - "AutofillSaveCreditCardUsesImprovedMessaging"; - -const char kAutofillSaveCreditCardUsesImprovedMessagingParamValueStoreCard[] = - "Store Card"; -const char - kAutofillSaveCreditCardUsesImprovedMessagingParamValueStoreBillingDetails - [] = "Store Billing Details"; -const char kAutofillSaveCreditCardUsesImprovedMessagingParamValueAddCard[] = - "Add Card"; -const char - kAutofillSaveCreditCardUsesImprovedMessagingParamValueConfirmAndSaveCard[] = - "Confirm & Save Card"; - // Features // Controls whether or not Autofill client will populate form with CPAN and @@ -56,10 +42,6 @@ const base::Feature kAutofillCreditCardAuthentication{ const base::Feature kAutofillCreditCardUploadFeedback{ "AutofillCreditCardUploadFeedback", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillDoNotMigrateUnsupportedLocalCards{ - "AutofillDoNotMigrateUnsupportedLocalCards", - base::FEATURE_ENABLED_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{ @@ -71,11 +53,10 @@ const base::Feature kAutofillEnableLocalCardMigrationForNonSyncUser{ const base::Feature kAutofillEnableToolbarStatusChip{ "AutofillEnableToolbarStatusChip", base::FEATURE_DISABLED_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_ENABLED_BY_DEFAULT}; +// When enabled, the option of using cloud token virtual card will be offered +// when all requirements are met. +const base::Feature kAutofillEnableVirtualCard{ + "AutofillEnableVirtualCard", base::FEATURE_DISABLED_BY_DEFAULT}; // When enabled, will remove the option to save unmasked server cards as // FULL_SERVER_CARDs upon successful unmask. @@ -92,22 +73,9 @@ const base::Feature kAutofillNoLocalSaveOnUploadSuccess{ 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_ENABLED_BY_DEFAULT}; - -// Controls what title and bubble label for the credit card upload bubble are -// shown to users. -const base::Feature kAutofillSaveCreditCardUsesImprovedMessaging{ - "AutofillSaveCreditCardUsesImprovedMessaging", - base::FEATURE_DISABLED_BY_DEFAULT}; - -// Controls whether to show updated UI for the card unmask prompt. -const base::Feature kAutofillUpdatedCardUnmaskPromptUi{ - "AutofillUpdatedCardUnmaskPromptUi", base::FEATURE_DISABLED_BY_DEFAULT}; +// When enabled, the Save Card infobar supports editing before submitting. +const base::Feature kAutofillSaveCardInfobarEditSupport{ + "AutofillSaveCardInfobarEditSupport", base::FEATURE_DISABLED_BY_DEFAULT}; // Controls offering credit card upload to Google Payments. Cannot ever be // ENABLED_BY_DEFAULT because it's a country-specific whitelist. There are diff --git a/chromium/components/autofill/core/common/autofill_payments_features.h b/chromium/components/autofill/core/common/autofill_payments_features.h index 6dc8e2faa2d..2309c6eb011 100644 --- a/chromium/components/autofill/core/common/autofill_payments_features.h +++ b/chromium/components/autofill/core/common/autofill_payments_features.h @@ -23,16 +23,13 @@ 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 kAutofillEnableLocalCardMigrationForNonSyncUser; extern const base::Feature kAutofillEnableToolbarStatusChip; -extern const base::Feature kAutofillLocalCardMigrationUsesStrikeSystemV2; +extern const base::Feature kAutofillEnableVirtualCard; 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; +extern const base::Feature kAutofillSaveCardInfobarEditSupport; extern const base::Feature kAutofillUpstream; extern const base::Feature kAutofillUpstreamAllowAllEmailDomains; extern const base::Feature kAutofillUpstreamAlwaysRequestCardholderName; @@ -40,16 +37,6 @@ extern const base::Feature kAutofillUpstreamBlankCardholderNameField; extern const base::Feature kAutofillUpstreamEditableCardholderName; extern const base::Feature kAutofillUpstreamEditableExpirationDate; -extern const char kAutofillSaveCreditCardUsesImprovedMessagingParamName[]; -extern const char - kAutofillSaveCreditCardUsesImprovedMessagingParamValueStoreCard[]; -extern const char - kAutofillSaveCreditCardUsesImprovedMessagingParamValueStoreBillingDetails[]; -extern const char - kAutofillSaveCreditCardUsesImprovedMessagingParamValueAddCard[]; -extern const char - kAutofillSaveCreditCardUsesImprovedMessagingParamValueConfirmAndSaveCard[]; - // Return whether a [No thanks] button and new messaging is shown in the save // card bubbles. This will be called only on desktop platforms. bool ShouldShowImprovedUserConsentForCreditCardSave(); diff --git a/chromium/components/autofill/core/common/autofill_prefs.cc b/chromium/components/autofill/core/common/autofill_prefs.cc index 1607b0d7274..1296451e132 100644 --- a/chromium/components/autofill/core/common/autofill_prefs.cc +++ b/chromium/components/autofill/core/common/autofill_prefs.cc @@ -84,11 +84,6 @@ const char kAutofillLastVersionDisusedAddressesDeleted[] = const char kAutofillLastVersionDisusedCreditCardsDeleted[] = "autofill.last_version_disused_credit_cards_deleted"; -// Boolean that is set to denote whether user cancelled/rejected local card -// migration prompt. -const char kAutofillMigrateLocalCardsCancelledPrompt[] = - "autofill.migrate_local_card_cancelled_state"; - // Boolean that is true if the orphan rows in the autofill table were removed. const char kAutofillOrphanRowsRemoved[] = "autofill.orphan_rows_removed"; @@ -175,8 +170,6 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { prefs::kAutofillLastVersionDisusedCreditCardsDeleted, 0); registry->RegisterIntegerPref(prefs::kAutocompleteLastVersionRetentionPolicy, 0); - registry->RegisterBooleanPref( - prefs::kAutofillMigrateLocalCardsCancelledPrompt, false); registry->RegisterBooleanPref(prefs::kAutofillOrphanRowsRemoved, false); registry->RegisterStringPref(prefs::kAutofillUploadEncodingSeed, ""); registry->RegisterDictionaryPref(prefs::kAutofillUploadEvents); @@ -223,16 +216,7 @@ void MigrateDeprecatedAutofillPrefs(PrefService* prefs) { } bool IsAutocompleteEnabled(const PrefService* prefs) { - return IsProfileAutofillEnabled(prefs); -} - -bool IsAutofillEnabled(const PrefService* prefs) { - return IsProfileAutofillEnabled(prefs) || IsCreditCardAutofillEnabled(prefs); -} - -void SetAutofillEnabled(PrefService* prefs, bool enabled) { - SetProfileAutofillEnabled(prefs, enabled); - SetCreditCardAutofillEnabled(prefs, enabled); + return IsAutofillProfileEnabled(prefs); } bool IsCreditCardFIDOAuthEnabled(PrefService* prefs) { @@ -243,11 +227,11 @@ void SetCreditCardFIDOAuthEnabled(PrefService* prefs, bool enabled) { prefs->SetBoolean(kAutofillCreditCardFidoAuthEnabled, enabled); } -bool IsCreditCardAutofillEnabled(const PrefService* prefs) { +bool IsAutofillCreditCardEnabled(const PrefService* prefs) { return prefs->GetBoolean(kAutofillCreditCardEnabled); } -void SetCreditCardAutofillEnabled(PrefService* prefs, bool enabled) { +void SetAutofillCreditCardEnabled(PrefService* prefs, bool enabled) { prefs->SetBoolean(kAutofillCreditCardEnabled, enabled); } @@ -255,31 +239,22 @@ bool IsAutofillManaged(const PrefService* prefs) { return prefs->IsManagedPreference(kAutofillEnabledDeprecated); } -bool IsProfileAutofillManaged(const PrefService* prefs) { +bool IsAutofillProfileManaged(const PrefService* prefs) { return prefs->IsManagedPreference(kAutofillProfileEnabled); } -bool IsCreditCardAutofillManaged(const PrefService* prefs) { +bool IsAutofillCreditCardManaged(const PrefService* prefs) { return prefs->IsManagedPreference(kAutofillCreditCardEnabled); } -bool IsProfileAutofillEnabled(const PrefService* prefs) { +bool IsAutofillProfileEnabled(const PrefService* prefs) { return prefs->GetBoolean(kAutofillProfileEnabled); } -void SetProfileAutofillEnabled(PrefService* prefs, bool enabled) { +void SetAutofillProfileEnabled(PrefService* prefs, bool enabled) { prefs->SetBoolean(kAutofillProfileEnabled, enabled); } -bool IsLocalCardMigrationPromptPreviouslyCancelled(const PrefService* prefs) { - return prefs->GetBoolean(kAutofillMigrateLocalCardsCancelledPrompt); -} - -void SetLocalCardMigrationPromptPreviouslyCancelled(PrefService* prefs, - bool enabled) { - prefs->SetBoolean(kAutofillMigrateLocalCardsCancelledPrompt, enabled); -} - bool IsPaymentsIntegrationEnabled(const PrefService* prefs) { return prefs->GetBoolean(kAutofillWalletImportEnabled); } @@ -296,13 +271,14 @@ std::string GetAllProfilesValidityMapsEncodedString(const PrefService* prefs) { } void SetUserOptedInWalletSyncTransport(PrefService* prefs, - const std::string& account_id, + const CoreAccountId& account_id, bool opted_in) { // Get the hash of the account id. The hashing here is only a secondary bit of // obfuscation. The primary privacy guarantees are handled by clearing this // whenever cookies are cleared. std::string account_hash; - base::Base64Encode(crypto::SHA256HashString(account_id), &account_hash); + base::Base64Encode(crypto::SHA256HashString(account_id.ToString()), + &account_hash); DictionaryPrefUpdate update(prefs, prefs::kAutofillSyncTransportOptIn); int value = GetSyncTransportOptInBitFieldForAccount(prefs, account_hash); @@ -325,10 +301,11 @@ void SetUserOptedInWalletSyncTransport(PrefService* prefs, } bool IsUserOptedInWalletSyncTransport(const PrefService* prefs, - const std::string& account_id) { + const CoreAccountId& account_id) { // Get the hash of the account id. std::string account_hash; - base::Base64Encode(crypto::SHA256HashString(account_id), &account_hash); + base::Base64Encode(crypto::SHA256HashString(account_id.ToString()), + &account_hash); // Return whether the wallet opt-in bit is set. return GetSyncTransportOptInBitFieldForAccount(prefs, account_hash) & diff --git a/chromium/components/autofill/core/common/autofill_prefs.h b/chromium/components/autofill/core/common/autofill_prefs.h index 7558441a2ac..369f3fde5eb 100644 --- a/chromium/components/autofill/core/common/autofill_prefs.h +++ b/chromium/components/autofill/core/common/autofill_prefs.h @@ -7,6 +7,8 @@ #include <string> +#include "google_apis/gaia/core_account_id.h" + class PrefService; namespace user_prefs { @@ -31,7 +33,6 @@ extern const char kAutofillLastVersionDeduped[]; extern const char kAutofillLastVersionValidated[]; extern const char kAutofillLastVersionDisusedAddressesDeleted[]; extern const char kAutofillLastVersionDisusedCreditCardsDeleted[]; -extern const char kAutofillMigrateLocalCardsCancelledPrompt[]; extern const char kAutofillOrphanRowsRemoved[]; // Do not get/set the value of this pref directly. Use provided getter/setter. extern const char kAutofillProfileEnabled[]; @@ -67,32 +68,23 @@ void MigrateDeprecatedAutofillPrefs(PrefService* prefs); bool IsAutocompleteEnabled(const PrefService* prefs); -bool IsAutofillEnabled(const PrefService* prefs); - -void SetAutofillEnabled(PrefService* prefs, bool enabled); - bool IsCreditCardFIDOAuthEnabled(PrefService* prefs); void SetCreditCardFIDOAuthEnabled(PrefService* prefs, bool enabled); -bool IsCreditCardAutofillEnabled(const PrefService* prefs); +bool IsAutofillCreditCardEnabled(const PrefService* prefs); -void SetCreditCardAutofillEnabled(PrefService* prefs, bool enabled); +void SetAutofillCreditCardEnabled(PrefService* prefs, bool enabled); bool IsAutofillManaged(const PrefService* prefs); -bool IsProfileAutofillManaged(const PrefService* prefs); - -bool IsCreditCardAutofillManaged(const PrefService* prefs); - -bool IsProfileAutofillEnabled(const PrefService* prefs); +bool IsAutofillProfileManaged(const PrefService* prefs); -void SetProfileAutofillEnabled(PrefService* prefs, bool enabled); +bool IsAutofillCreditCardManaged(const PrefService* prefs); -bool IsLocalCardMigrationPromptPreviouslyCancelled(const PrefService* prefs); +bool IsAutofillProfileEnabled(const PrefService* prefs); -void SetLocalCardMigrationPromptPreviouslyCancelled(PrefService* prefs, - bool enabled); +void SetAutofillProfileEnabled(PrefService* prefs, bool enabled); bool IsPaymentsIntegrationEnabled(const PrefService* prefs); @@ -101,11 +93,11 @@ void SetPaymentsIntegrationEnabled(PrefService* prefs, bool enabled); std::string GetAllProfilesValidityMapsEncodedString(const PrefService* prefs); void SetUserOptedInWalletSyncTransport(PrefService* prefs, - const std::string& account_id, + const CoreAccountId& account_id, bool opted_in); bool IsUserOptedInWalletSyncTransport(const PrefService* prefs, - const std::string& account_id); + const CoreAccountId& account_id); void ClearSyncTransportOptIns(PrefService* prefs); diff --git a/chromium/components/autofill/core/common/autofill_prefs_unittest.cc b/chromium/components/autofill/core/common/autofill_prefs_unittest.cc index 085c6e23437..f3d93b25453 100644 --- a/chromium/components/autofill/core/common/autofill_prefs_unittest.cc +++ b/chromium/components/autofill/core/common/autofill_prefs_unittest.cc @@ -78,8 +78,8 @@ TEST_F(AutofillPrefsTest, MigrateDeprecatedAutofillPrefs) { // Tests that setting and getting the AutofillSyncTransportOptIn works as // expected. TEST_F(AutofillPrefsTest, WalletSyncTransportPref_GetAndSet) { - const std::string account1 = "account1"; - const std::string account2 = "account2"; + const CoreAccountId account1("account1"); + const CoreAccountId account2("account2"); // There should be no opt-in recorded at first. ASSERT_FALSE(IsUserOptedInWalletSyncTransport(pref_service(), account1)); @@ -129,7 +129,7 @@ TEST_F(AutofillPrefsTest, WalletSyncTransportPref_GetAndSet) { // Tests that AutofillSyncTransportOptIn is not stored using the plain text // account id. TEST_F(AutofillPrefsTest, WalletSyncTransportPref_UsesHashAccountId) { - const std::string account1 = "account1"; + const CoreAccountId account1("account1"); // There should be no opt-in recorded at first. EXPECT_TRUE(pref_service() @@ -145,14 +145,14 @@ TEST_F(AutofillPrefsTest, WalletSyncTransportPref_UsesHashAccountId) { // Make sure that the dictionary keys don't contain the account id. auto* dictionary = pref_service()->GetDictionary(prefs::kAutofillSyncTransportOptIn); - EXPECT_EQ(NULL, - dictionary->FindKeyOfType(account1, base::Value::Type::INTEGER)); + EXPECT_EQ(nullptr, dictionary->FindKeyOfType(account1.ToString(), + base::Value::Type::INTEGER)); } // Tests that clearing the AutofillSyncTransportOptIn works as expected. TEST_F(AutofillPrefsTest, WalletSyncTransportPref_Clear) { - const std::string account1 = "account1"; - const std::string account2 = "account2"; + const CoreAccountId account1("account1"); + const CoreAccountId account2("account2"); // There should be no opt-in recorded at first. EXPECT_TRUE(pref_service() @@ -181,7 +181,7 @@ TEST_F(AutofillPrefsTest, WalletSyncTransportPref_Clear) { // Tests that the account id hash that we generate can be written and read from // JSON properly. TEST_F(AutofillPrefsTest, WalletSyncTransportPref_CanBeSetAndReadFromJSON) { - const std::string account1 = "account1"; + const CoreAccountId account1("account1"); // Set the opt-in for the first account. SetUserOptedInWalletSyncTransport(pref_service(), account1, true); diff --git a/chromium/components/autofill/core/common/form_data.cc b/chromium/components/autofill/core/common/form_data.cc index e69ae3a8a28..df05fe6e072 100644 --- a/chromium/components/autofill/core/common/form_data.cc +++ b/chromium/components/autofill/core/common/form_data.cc @@ -123,28 +123,23 @@ bool FormData::DynamicallySameFormAs(const FormData& form) const { return true; } -bool FormData::operator==(const FormData& form) const { - 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 && - is_formless_checkout == form.is_formless_checkout && - fields == form.fields && - username_predictions == form.username_predictions; -} - -bool FormData::operator!=(const FormData& form) const { - return !(*this == form); -} - -bool FormData::operator<(const FormData& form) const { - 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); +bool FormData::IdentityComparator::operator()(const FormData& a, + const FormData& b) const { + // |unique_renderer_id| uniquely identifies the form, if and only if it is + // set; the other members compared below together uniquely identify the form + // as well. + auto tie = [](const FormData& f) { + return std::tie(f.unique_renderer_id, f.name, f.id_attribute, + f.name_attribute, f.url, f.action, f.is_form_tag, + f.is_formless_checkout); + }; + if (tie(a) < tie(b)) + return true; + if (tie(b) < tie(a)) + return false; + return std::lexicographical_compare(a.fields.begin(), a.fields.end(), + b.fields.begin(), b.fields.end(), + FormFieldData::IdentityComparator()); } std::ostream& operator<<(std::ostream& os, const FormData& form) { @@ -254,4 +249,9 @@ LogBuffer& operator<<(LogBuffer& buffer, const FormData& form) { return buffer; } +bool FormDataEqualForTesting(const FormData& lhs, const FormData& rhs) { + FormData::IdentityComparator less; + return !less(lhs, rhs) && !less(rhs, lhs); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/common/form_data.h b/chromium/components/autofill/core/common/form_data.h index 932394bc09e..1e84cec2998 100644 --- a/chromium/components/autofill/core/common/form_data.h +++ b/chromium/components/autofill/core/common/form_data.h @@ -29,6 +29,12 @@ using ButtonTitleList = std::vector<ButtonTitleInfo>; // Holds information about a form to be filled and/or submitted. struct FormData { + // Less-than relation for STL containers. Compares only members needed to + // uniquely identify a form. + struct IdentityComparator { + bool operator()(const FormData& a, const FormData& b) const; + }; + // 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 = @@ -52,11 +58,6 @@ struct FormData { // If |form| is the same as this from the POV of dynamic refills. bool DynamicallySameFormAs(const FormData& form) const; - // Note: operator==() performs a full-field-comparison(byte by byte), this is - // different from SameFormAs(), which ignores comparison for those "values" of - // all form fields, just like what FormFieldData::SameFieldAs() ignores. - bool operator==(const FormData& form) const; - bool operator!=(const FormData& form) const; // Allow FormData to be a key in STL containers. bool operator<(const FormData& form) const; @@ -66,6 +67,11 @@ struct FormData { // The name attribute of the form. base::string16 name_attribute; + // NOTE: update IdentityComparator when adding new a member. + // NOTE: update SameFormAs() if needed when adding new a member. + // NOTE: update SimilarFormAs() if needed when adding new a member. + // NOTE: update DynamicallySameFormAs() if needed when adding new a member. + // The name by which autofill knows this form. This is generally either the // name attribute or the id_attribute value, which-ever is non-empty with // priority given to the name_attribute. This value is used when computing @@ -91,9 +97,9 @@ struct FormData { // and used if features::kAutofillRestrictUnownedFieldsToFormlessCheckout is // enabled, to prevent heuristics from running on formless non-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(). + // Unique renderer id returned by WebFormElement::UniqueRendererFormId(). It + // is not persistent between page loads, so it is not saved and not used in + // comparison in SameFormAs(). uint32_t unique_renderer_id = kNotSetFormRendererId; // The type of the event that was taken as an indication that this form is // being or has already been submitted. This field is filled only in Password @@ -124,6 +130,8 @@ bool DeserializeFormData(base::PickleIterator* iter, FormData* form_data); LogBuffer& operator<<(LogBuffer& buffer, const FormData& form); +bool FormDataEqualForTesting(const FormData& lhs, const FormData& rhs); + } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_COMMON_FORM_DATA_H_ diff --git a/chromium/components/autofill/core/common/form_field_data.cc b/chromium/components/autofill/core/common/form_field_data.cc index 1a804330c6c..2f233ce7478 100644 --- a/chromium/components/autofill/core/common/form_field_data.cc +++ b/chromium/components/autofill/core/common/form_field_data.cc @@ -4,7 +4,11 @@ #include "components/autofill/core/common/form_field_data.h" +#include <algorithm> +#include <tuple> + #include "base/pickle.h" +#include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_util.h" @@ -126,18 +130,71 @@ bool DeserializeSection11(base::PickleIterator* iter, return iter->ReadString16(&field_data->name_attribute); } -bool HaveSameLabel(const FormFieldData& field1, const FormFieldData& field2) { - if (field1.label == field2.label) - return true; - - // Assume the labels same if they come from same source but not LABEL tag - // when kAutofillSkipComparingInferredLabels is enabled. - if (base::FeatureList::IsEnabled( - features::kAutofillSkipComparingInferredLabels)) { - return field1.label_source == field2.label_source && - field1.label_source != FormFieldData::LabelSource::kLabelTag; +// LabelInfo is used to implement that "a.label == b.label" can be weakened to +// "a.label == b.label OR a certain feature is enabled and {a,b}.label_source != +// kLabelTag and a.label_source == b.label_source". +// Beware of the StringPiece member and resulting lifetime issues. Deleted copy +// and move ctors/operators to reduce risk potential. +struct LabelInfo { + explicit LabelInfo(const FormFieldData& f) + : label(f.label), source(f.label_source) {} + LabelInfo(const LabelInfo&) = delete; + LabelInfo& operator=(const LabelInfo&) = delete; + LabelInfo(LabelInfo&&) = default; + LabelInfo& operator=(LabelInfo&&) = default; + + bool operator==(const LabelInfo& that) const { + if (label == that.label) + return true; + + // Feature |kAutofillSkipComparingInferredLabels| weakens equivalence of + // labels: two labels are equivalent if they were inferred from the same + // type of tag other than a LABEL tag. + return base::FeatureList::IsEnabled( + features::kAutofillSkipComparingInferredLabels) && + source != FormFieldData::LabelSource::kLabelTag && + source == that.source; } - return false; + + bool operator<(const LabelInfo& that) const { return label < that.label; } + + base::StringPiece16 label; + FormFieldData::LabelSource source = FormFieldData::LabelSource::kLabelTag; +}; + +// CommonTuple(), SimilarityTuple(), DynamicIdentityTuple(), IdentityTuple() +// return values should be used as temporaries only because they include a +// StringPiece. + +auto CommonTuple(const FormFieldData& f) { + return std::tuple_cat( + std::make_tuple(LabelInfo(f)), + std::tie(f.name, f.name_attribute, f.id_attribute, f.form_control_type)); +} + +auto SimilarityTuple(const FormFieldData& f) { + return std::tuple_cat(CommonTuple(f), + std::make_tuple(IsCheckable(f.check_status))); +} + +auto DynamicIdentityTuple(const FormFieldData& f) { + return std::tuple_cat(CommonTuple(f), std::make_tuple(f.IsVisible())); +} + +auto IdentityTuple(const FormFieldData& f) { + // |unique_renderer_id| uniquely identifies the field, if and only if it is + // set; the other members compared below (excluding label_source) together + // uniquely identify the field as well. + return std::tuple_cat( + SimilarityTuple(f), + std::tie( +// TODO(crbug.com/896689): On iOS the unique_id member uniquely addresses +// this field in the DOM. +#if defined(OS_IOS) + f.unique_id, +#endif + f.autocomplete_attribute, f.placeholder, f.max_length, f.css_classes, + f.is_focusable, f.should_autocomplete, f.role, f.text_direction)); } } // namespace @@ -155,55 +212,21 @@ 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 -// this field in the DOM. -#if defined(OS_IOS) - if (unique_id != field.unique_id) - return false; -#endif - - // A FormFieldData stores a value, but the value is not part of the identity - // of the field, so we don't want to compare the values. - // Similarly, flags like is_enabled, which are only used for parsing but are - // not stored persistently, are not used for comparison. - // is_autofilled and section are also secondary properties of a field. Two - // fields could be the same, and have different sections, because the section - // is updated for one, but not for the other. - return name == field.name && id_attribute == field.id_attribute && - name_attribute == field.name_attribute && - form_control_type == field.form_control_type && - autocomplete_attribute == field.autocomplete_attribute && - placeholder == field.placeholder && max_length == field.max_length && - css_classes == field.css_classes && - // is_checked and is_autofilled counts as "value" since these change - // when we fill things in. - IsCheckable(check_status) == IsCheckable(field.check_status) && - is_focusable == field.is_focusable && - should_autocomplete == field.should_autocomplete && - role == field.role && text_direction == field.text_direction && - HaveSameLabel(*this, field); - // The option values/contents which are the list of items in the list - // of a drop-down are currently not considered part of the identity of - // a form element. This is debatable, since one might base heuristics - // on the types of elements that are available. Alternatively, one - // could imagine some forms that dynamically change the element - // contents (say, insert years starting from the current year) that - // should not be considered changes in the structure of the form. + return IdentityTuple(*this) == IdentityTuple(field); } bool FormFieldData::SimilarFieldAs(const FormFieldData& field) const { - return HaveSameLabel(*this, field) && name == field.name && - id_attribute == field.id_attribute && - name_attribute == field.name_attribute && - form_control_type == field.form_control_type && - IsCheckable(check_status) == IsCheckable(field.check_status); + return SimilarityTuple(*this) == SimilarityTuple(field); } bool FormFieldData::DynamicallySameFieldAs(const FormFieldData& field) const { - return name == field.name && id_attribute == field.id_attribute && - name_attribute == field.name_attribute && - HaveSameLabel(*this, field) && IsVisible() == field.IsVisible() && - form_control_type == field.form_control_type; + return DynamicIdentityTuple(*this) == DynamicIdentityTuple(field); +} + +bool FormFieldData::IdentityComparator::operator()( + const FormFieldData& a, + const FormFieldData& b) const { + return IdentityTuple(a) < IdentityTuple(b); } bool FormFieldData::IsTextInputElement() const { @@ -228,99 +251,6 @@ 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 && - is_autofilled == field.is_autofilled && - check_status == field.check_status && - option_values == field.option_values && - option_contents == field.option_contents && - properties_mask == field.properties_mask; -} - -bool FormFieldData::operator!=(const FormFieldData& field) const { - return !(*this == field); -} - -bool FormFieldData::operator<(const FormFieldData& field) const { - // This does not use std::tie() as that generates more implicit variables - // than the max-vartrack-size for var-tracking-assignments when compiling - // for Android, producing build warnings. (See https://crbug.com/555171 for - // context.) - - // Like SameFieldAs this ignores the value. - if (label < field.label) - return true; - if (label > field.label) - return false; - if (name < field.name) - return true; - if (name > field.name) - return false; - -// TODO(crbug.com/896689): On iOS the unique_id member uniquely addresses -// this field in the DOM. -#if defined(OS_IOS) - if (unique_id < field.unique_id) - return true; - if (unique_id < field.unique_id) - return false; -#endif - - if (id_attribute < field.id_attribute) - return true; - if (id_attribute > field.id_attribute) - return false; - if (name_attribute < field.name_attribute) - return true; - if (name_attribute > field.name_attribute) - return false; - if (form_control_type < field.form_control_type) - return true; - if (form_control_type > field.form_control_type) - return false; - if (autocomplete_attribute < field.autocomplete_attribute) - return true; - if (autocomplete_attribute > field.autocomplete_attribute) - return false; - if (placeholder < field.placeholder) - return true; - if (placeholder > field.placeholder) - return false; - if (max_length < field.max_length) - return true; - if (max_length > field.max_length) - return false; - if (css_classes < field.css_classes) - return true; - if (css_classes > field.css_classes) - return false; - // Skip |is_checked| and |is_autofilled| as in SameFieldAs. - if (IsCheckable(check_status) < IsCheckable(field.check_status)) - return true; - if (IsCheckable(check_status) > IsCheckable(field.check_status)) - return false; - if (is_focusable < field.is_focusable) - return true; - if (is_focusable > field.is_focusable) - return false; - if (should_autocomplete < field.should_autocomplete) - return true; - if (should_autocomplete > field.should_autocomplete) - return false; - if (role < field.role) - return true; - if (role > field.role) - return false; - if (text_direction < field.text_direction) - return true; - if (text_direction > field.text_direction) - return false; - // See SameFieldAs above for why we don't check option_values/contents and - // flags like is_enabled. - return false; -} - void SerializeFormFieldData(const FormFieldData& field_data, base::Pickle* pickle) { pickle->WriteInt(kFormFieldDataPickleVersion); diff --git a/chromium/components/autofill/core/common/form_field_data.h b/chromium/components/autofill/core/common/form_field_data.h index 605f9e0baad..e1c8198c5c7 100644 --- a/chromium/components/autofill/core/common/form_field_data.h +++ b/chromium/components/autofill/core/common/form_field_data.h @@ -57,6 +57,12 @@ struct FormFieldData { using RoleAttribute = mojom::FormFieldData_RoleAttribute; using LabelSource = mojom::FormFieldData_LabelSource; + // Less-than relation for STL containers. Compares only members needed to + // uniquely identify a field. + struct IdentityComparator { + bool operator()(const FormFieldData& a, const FormFieldData& b) const; + }; + static constexpr uint32_t kNotSetFormControlRendererId = std::numeric_limits<uint32_t>::max(); @@ -67,20 +73,22 @@ struct FormFieldData { FormFieldData& operator=(FormFieldData&&); ~FormFieldData(); - // Returns true if two form fields are the same, not counting the value. + // Returns true if both fields are identical, ignoring value- and + // parsing related members. + // See also SimilarFieldAs(), DynamicallySameFieldAs(). bool SameFieldAs(const FormFieldData& field) const; - // SameFieldAs() is a little restricted when field's style changed - // dynamically, like css. - // This method only compares critical attributes of field to check whether - // they are similar enough to be considered as same field if form's - // other information isn't changed. + // Returns true if both fields are identical, ignoring members that + // are typically changed dynamically. + // Strictly weaker than SameFieldAs(). bool SimilarFieldAs(const FormFieldData& field) const; - // If |field| is the same as this from the POV of dynamic refills. + // Returns true if both forms are equivalent from the POV of dynamic refills. + // Strictly weaker than SameFieldAs(): replaces equality of |is_focusable| and + // |role| with equality of IsVisible(). bool DynamicallySameFieldAs(const FormFieldData& field) const; - // Returns true for all of textfield-looking types such as text, password, + // Returns true for all of textfield-looking types: text, password, // search, email, url, and number. It must work the same way as Blink function // WebInputElement::IsTextField(), and it returns false if |*this| represents // a textarea. @@ -99,15 +107,6 @@ struct FormFieldData { 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 - // the option_values/contents etc. - bool operator==(const FormFieldData& field) const; - bool operator!=(const FormFieldData& field) const; - // Comparison operator exposed for STL map. Uses label, then name to sort. - bool operator<(const FormFieldData& field) const; - #if defined(OS_IOS) // The identifier which uniquely addresses this field in the DOM. This is an // ephemeral value which is not guaranteed to be stable across page loads. It @@ -122,6 +121,11 @@ struct FormFieldData { #define EXPECT_EQ_UNIQUE_ID(expected, actual) #endif + // NOTE: update IdentityComparator when adding new a member. + // NOTE: update SameFieldAs() if needed when adding new a member. + // NOTE: update SimilarFieldAs() if needed when adding new a member. + // NOTE: update DynamicallySameFieldAs() if needed when adding new a member. + // The name by which autofill knows this field. This is generally either the // name attribute or the id_attribute value, which-ever is non-empty with // priority given to the name_attribute. This value is used when computing @@ -129,8 +133,6 @@ struct FormFieldData { // TODO(crbug/896689): remove this and use attributes/unique_id instead. base::string16 name; - // If you add more, be sure to update the comparison operators, SameFieldAs, - // serializing functions (in the .cc file) and the constructor. base::string16 id_attribute; base::string16 name_attribute; base::string16 label; @@ -142,10 +144,9 @@ struct FormFieldData { base::string16 aria_label; base::string16 aria_description; - // Unique renderer id which is returned by function - // WebFormControlElement::UniqueRendererFormControlId(). It is not persistant - // between page loads, so it is not saved and not used in comparison in - // SameFieldAs(). + // Unique renderer id returned by WebFormElement::UniqueRendererFormId(). It + // is not persistent between page loads, so it is not saved and not used in + // comparison in SameFieldAs(). uint32_t unique_renderer_id = kNotSetFormControlRendererId; // The ax node id of the form control in the accessibility tree. diff --git a/chromium/components/autofill/core/common/logging/log_buffer.cc b/chromium/components/autofill/core/common/logging/log_buffer.cc index 5abd4daa207..0f9e6c349d5 100644 --- a/chromium/components/autofill/core/common/logging/log_buffer.cc +++ b/chromium/components/autofill/core/common/logging/log_buffer.cc @@ -101,11 +101,10 @@ base::Value LogBuffer::RetrieveResult() { if (!children || children->GetList().empty()) return base::Value(); - // If the fragment has a single child, return that directly. + // If the fragment has a single child, remove it from |children| and return + // that directly. if (children->GetList().size() == 1) { - base::Value result = std::move(children->GetList().back()); - children->GetList().pop_back(); - return result; + return std::move(children->TakeList().back()); } return std::exchange(buffer_.back(), CreateEmptyFragment()); diff --git a/chromium/components/autofill/core/common/mojom/BUILD.gn b/chromium/components/autofill/core/common/mojom/BUILD.gn index f3ca8036267..2301e4a6ca8 100644 --- a/chromium/components/autofill/core/common/mojom/BUILD.gn +++ b/chromium/components/autofill/core/common/mojom/BUILD.gn @@ -5,6 +5,7 @@ import("//mojo/public/tools/bindings/mojom.gni") mojom("mojo_types") { + generate_java = true sources = [ "autofill_types.mojom", ] diff --git a/chromium/components/autofill/core/common/mojom/autofill_types.mojom b/chromium/components/autofill/core/common/mojom/autofill_types.mojom index 0879248916c..94502751d94 100644 --- a/chromium/components/autofill/core/common/mojom/autofill_types.mojom +++ b/chromium/components/autofill/core/common/mojom/autofill_types.mojom @@ -182,10 +182,11 @@ struct FormDataPredictions { array<FormFieldDataPredictions> fields; }; -// autofill::PasswordAndRealm -struct PasswordAndRealm { +// autofill::PasswordAndMetadata +struct PasswordAndMetadata { mojo_base.mojom.String16 password; string realm; + bool uses_account_store; }; // autofill::PasswordFormFillData @@ -197,7 +198,8 @@ struct PasswordFormFillData { FormFieldData password_field; bool username_may_use_prefilled_placeholder; string preferred_realm; - map<mojo_base.mojom.String16, PasswordAndRealm> additional_logins; + bool uses_account_store; + map<mojo_base.mojom.String16, PasswordAndMetadata> additional_logins; bool wait_for_username; bool has_renderer_ids; }; diff --git a/chromium/components/autofill/core/common/mojom/autofill_types.typemap b/chromium/components/autofill/core/common/mojom/autofill_types.typemap index 1531e37fb14..d04ee335165 100644 --- a/chromium/components/autofill/core/common/mojom/autofill_types.typemap +++ b/chromium/components/autofill/core/common/mojom/autofill_types.typemap @@ -32,7 +32,7 @@ type_mappings = [ "autofill.mojom.FormFieldDataPredictions=::autofill::FormFieldDataPredictions", "autofill.mojom.FormsPredictionsMap=::autofill::FormsPredictionsMap", "autofill.mojom.ParsingResult=::autofill::ParsingResult", - "autofill.mojom.PasswordAndRealm=::autofill::PasswordAndRealm", + "autofill.mojom.PasswordAndMetadata=::autofill::PasswordAndMetadata", "autofill.mojom.PasswordForm=::autofill::PasswordForm", "autofill.mojom.PasswordFormFieldPredictionMap=::autofill::PasswordFormFieldPredictionMap", "autofill.mojom.PasswordFormFillData=::autofill::PasswordFormFillData", 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 3962a512072..0c1d1f4a3db 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 @@ -169,15 +169,17 @@ bool StructTraits<autofill::mojom::FormDataPredictionsDataView, } // static -bool StructTraits<autofill::mojom::PasswordAndRealmDataView, - autofill::PasswordAndRealm>:: - Read(autofill::mojom::PasswordAndRealmDataView data, - autofill::PasswordAndRealm* out) { +bool StructTraits<autofill::mojom::PasswordAndMetadataDataView, + autofill::PasswordAndMetadata>:: + Read(autofill::mojom::PasswordAndMetadataDataView data, + autofill::PasswordAndMetadata* out) { if (!data.ReadPassword(&out->password)) return false; if (!data.ReadRealm(&out->realm)) return false; + out->uses_account_store = data.uses_account_store(); + return true; } @@ -193,6 +195,7 @@ bool StructTraits<autofill::mojom::PasswordFormFillDataDataView, !data.ReadAdditionalLogins(&out->additional_logins)) return false; + out->uses_account_store = data.uses_account_store(); out->form_renderer_id = data.form_renderer_id(); out->wait_for_username = data.wait_for_username(); out->has_renderer_ids = data.has_renderer_ids(); 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 a26fbd21849..28b4d24052e 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 @@ -302,18 +302,23 @@ struct StructTraits<autofill::mojom::FormDataPredictionsDataView, }; template <> -struct StructTraits<autofill::mojom::PasswordAndRealmDataView, - autofill::PasswordAndRealm> { - static const base::string16& password(const autofill::PasswordAndRealm& r) { +struct StructTraits<autofill::mojom::PasswordAndMetadataDataView, + autofill::PasswordAndMetadata> { + static const base::string16& password( + const autofill::PasswordAndMetadata& r) { return r.password; } - static const std::string& realm(const autofill::PasswordAndRealm& r) { + static const std::string& realm(const autofill::PasswordAndMetadata& r) { return r.realm; } - static bool Read(autofill::mojom::PasswordAndRealmDataView data, - autofill::PasswordAndRealm* out); + static bool uses_account_store(const autofill::PasswordAndMetadata& r) { + return r.uses_account_store; + } + + static bool Read(autofill::mojom::PasswordAndMetadataDataView data, + autofill::PasswordAndMetadata* out); }; template <> @@ -351,7 +356,11 @@ struct StructTraits<autofill::mojom::PasswordFormFillDataDataView, return r.preferred_realm; } - static const std::map<base::string16, autofill::PasswordAndRealm>& + static bool uses_account_store(const autofill::PasswordFormFillData& r) { + return r.uses_account_store; + } + + static const std::map<base::string16, autofill::PasswordAndMetadata>& additional_logins(const autofill::PasswordFormFillData& r) { return r.additional_logins; } 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 1fd64be2cfc..8b54588598a 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 @@ -28,6 +28,12 @@ const std::vector<const char*> kOptions = {"Option1", "Option2", "Option3", "Option4"}; namespace { +template <typename T> +bool EquivalentData(const T& a, const T& b) { + typename T::IdentityComparator less; + return !less(a, b) && !less(b, a); +} + void CreateTestFieldDataPredictions(const std::string& signature, FormFieldDataPredictions* field_predict) { test::CreateTestSelectField("TestLabel", "TestName", "TestValue", kOptions, @@ -51,16 +57,19 @@ void CreateTestPasswordFormFillData(PasswordFormFillData* fill_data) { "TestPasswordFieldValue", kOptions, kOptions, 4, &fill_data->password_field); fill_data->preferred_realm = "https://foo.com/"; + fill_data->uses_account_store = true; base::string16 name; - PasswordAndRealm pr; + PasswordAndMetadata pr; name = base::ASCIIToUTF16("Tom"); pr.password = base::ASCIIToUTF16("Tom_Password"); pr.realm = "https://foo.com/"; + pr.uses_account_store = false; fill_data->additional_logins[name] = pr; name = base::ASCIIToUTF16("Jerry"); pr.password = base::ASCIIToUTF16("Jerry_Password"); pr.realm = "https://bar.com/"; + pr.uses_account_store = true; fill_data->additional_logins[name] = pr; fill_data->wait_for_username = true; @@ -126,9 +135,10 @@ void CheckEqualPasswordFormFillData(const PasswordFormFillData& expected, EXPECT_EQ(expected.form_renderer_id, actual.form_renderer_id); EXPECT_EQ(expected.origin, actual.origin); EXPECT_EQ(expected.action, actual.action); - EXPECT_EQ(expected.username_field, actual.username_field); - EXPECT_EQ(expected.password_field, actual.password_field); + EXPECT_TRUE(EquivalentData(expected.username_field, actual.username_field)); + EXPECT_TRUE(EquivalentData(expected.password_field, actual.password_field)); EXPECT_EQ(expected.preferred_realm, actual.preferred_realm); + EXPECT_EQ(expected.uses_account_store, actual.uses_account_store); { EXPECT_EQ(expected.additional_logins.size(), @@ -141,6 +151,8 @@ void CheckEqualPasswordFormFillData(const PasswordFormFillData& expected, EXPECT_EQ(iter1->first, iter2->first); EXPECT_EQ(iter1->second.password, iter2->second.password); EXPECT_EQ(iter1->second.realm, iter2->second.realm); + EXPECT_EQ(iter1->second.uses_account_store, + iter2->second.uses_account_store); } ASSERT_EQ(iter1, end1); ASSERT_EQ(iter2, end2); @@ -228,7 +240,7 @@ class AutofillTypeTraitsTestImpl : public testing::Test, void ExpectFormFieldData(const FormFieldData& expected, base::OnceClosure closure, const FormFieldData& passed) { - EXPECT_EQ(expected, passed); + EXPECT_TRUE(EquivalentData(expected, passed)); EXPECT_EQ(expected.value, passed.value); EXPECT_EQ(expected.typed_value, passed.typed_value); std::move(closure).Run(); @@ -237,7 +249,7 @@ void ExpectFormFieldData(const FormFieldData& expected, void ExpectFormData(const FormData& expected, base::OnceClosure closure, const FormData& passed) { - EXPECT_EQ(expected, passed); + EXPECT_TRUE(EquivalentData(expected, passed)); std::move(closure).Run(); } diff --git a/chromium/components/autofill/core/common/password_form.cc b/chromium/components/autofill/core/common/password_form.cc index d6f0044c8ea..f4ba9d4495b 100644 --- a/chromium/components/autofill/core/common/password_form.cc +++ b/chromium/components/autofill/core/common/password_form.cc @@ -26,8 +26,8 @@ std::string ToString(const T& obj) { return ostream.str(); } -std::string StoreToString(PasswordForm::Store from_store) { - switch (from_store) { +std::string StoreToString(PasswordForm::Store in_store) { + switch (in_store) { case PasswordForm::Store::kNotSet: return "Not Set"; case PasswordForm::Store::kProfileStore: @@ -96,7 +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)); + target->SetString("in_store", StoreToString(form.in_store)); } } // namespace @@ -149,7 +149,11 @@ bool PasswordForm::IsSingleUsername() const { } bool PasswordForm::IsUsingAccountStore() const { - return from_store == Store::kAccountStore; + return in_store == Store::kAccountStore; +} + +bool PasswordForm::HasNonEmptyPasswordValue() const { + return !password_value.empty() || !new_password_value.empty(); } bool PasswordForm::operator==(const PasswordForm& form) const { @@ -197,7 +201,7 @@ bool PasswordForm::operator==(const PasswordForm& form) const { submission_event == form.submission_event && only_for_fallback == form.only_for_fallback && is_new_password_reliable == form.is_new_password_reliable && - from_store == form.from_store; + in_store == form.in_store; } bool PasswordForm::operator!=(const PasswordForm& form) const { diff --git a/chromium/components/autofill/core/common/password_form.h b/chromium/components/autofill/core/common/password_form.h index 48e63390f8b..6e2192094c6 100644 --- a/chromium/components/autofill/core/common/password_form.h +++ b/chromium/components/autofill/core/common/password_form.h @@ -311,7 +311,7 @@ struct PasswordForm { // Credential came from the Gaia-account-scoped storage. kAccountStore }; - Store from_store = Store::kNotSet; + Store in_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. @@ -339,9 +339,12 @@ struct PasswordForm { bool IsSingleUsername() const; // Returns whether this form is stored in the account-scoped store, i.e. - // whether |from_store == Store::kAccountStore|. + // whether |in_store == Store::kAccountStore|. bool IsUsingAccountStore() const; + // Returns true when |password_value| or |new_password_value| are non-empty. + bool HasNonEmptyPasswordValue() const; + // Equality operators for testing. bool operator==(const PasswordForm& form) const; bool operator!=(const PasswordForm& form) const; 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 06b7eb4de26..e6b2189c4fb 100644 --- a/chromium/components/autofill/core/common/password_form_fill_data.cc +++ b/chromium/components/autofill/core/common/password_form_fill_data.cc @@ -31,6 +31,7 @@ PasswordFormFillData::PasswordFormFillData( name(form_on_page.form_data.name), origin(form_on_page.origin), action(form_on_page.action), + uses_account_store(preferred_match.IsUsingAccountStore()), wait_for_username(wait_for_username), has_renderer_ids(form_on_page.has_renderer_ids) { // Note that many of the |FormFieldData| members are not initialized for @@ -68,8 +69,9 @@ PasswordFormFillData::PasswordFormFillData( for (const PasswordForm* match : matches) { if (match == &preferred_match) continue; - PasswordAndRealm& value = additional_logins[match->username_value]; + PasswordAndMetadata& value = additional_logins[match->username_value]; value.password = match->password_value; + value.uses_account_store = match->IsUsingAccountStore(); if (IsPublicSuffixMatchOrAffiliationBasedMatch(*match)) value.realm = match->signon_realm; } 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 a94a1aeeb28..49d1a4041e4 100644 --- a/chromium/components/autofill/core/common/password_form_fill_data.h +++ b/chromium/components/autofill/core/common/password_form_fill_data.h @@ -21,16 +21,17 @@ struct ParsingResult { uint32_t confirm_password_renderer_id; }; -struct PasswordAndRealm { +struct PasswordAndMetadata { base::string16 password; std::string realm; + bool uses_account_store = false; }; // Structure used for autofilling password forms. Note that the realms in this // struct are only set when the password's realm differs from the realm of the // form that we are filling. struct PasswordFormFillData { - using LoginCollection = std::map<base::string16, PasswordAndRealm>; + using LoginCollection = std::map<base::string16, PasswordAndMetadata>; PasswordFormFillData(); @@ -85,7 +86,11 @@ struct PasswordFormFillData { // The signon realm of the preferred user/pass pair. std::string preferred_realm; - // A list of other matching username->PasswordAndRealm pairs for the form. + // True iff the password originated from the account store rather than the + // local password store. + bool uses_account_store = false; + + // A list of other matching username->PasswordAndMetadata pairs for the form. LoginCollection additional_logins; // Tells us whether we need to wait for the user to enter a valid username 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 b4bd692a753..9826f0825bf 100644 --- a/chromium/components/autofill/core/common/save_password_progress_logger.cc +++ b/chromium/components/autofill/core/common/save_password_progress_logger.cc @@ -434,12 +434,14 @@ std::string SavePasswordProgressLogger::GetStringFromID( 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_HASH_ERROR: + return "Leak detection failed: hashing/encryption error"; + case STRING_LEAK_DETECTION_INVALID_SERVER_RESPONSE_ERROR: + return "Leak detection failed: invalid server response"; 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_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"; 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 f6f4a681b76..945c41b9f0e 100644 --- a/chromium/components/autofill/core/common/save_password_progress_logger.h +++ b/chromium/components/autofill/core/common/save_password_progress_logger.h @@ -153,9 +153,10 @@ class SavePasswordProgressLogger { STRING_LEAK_DETECTION_DISABLED_FEATURE, STRING_LEAK_DETECTION_DISABLED_SAFE_BROWSING, STRING_LEAK_DETECTION_FINISHED, + STRING_LEAK_DETECTION_HASH_ERROR, + STRING_LEAK_DETECTION_INVALID_SERVER_RESPONSE_ERROR, STRING_LEAK_DETECTION_SIGNED_OUT_ERROR, STRING_LEAK_DETECTION_TOKEN_REQUEST_ERROR, - STRING_LEAK_DETECTION_INVALID_SERVER_RESPONSE_ERROR, STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_LOWERCASE, STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_SPECIAL_SYMBOL, STRING_PASSWORD_REQUIREMENTS_VOTE_FOR_SPECIFIC_SPECIAL_SYMBOL, |