summaryrefslogtreecommitdiff
path: root/chromium/components/password_manager
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/components/password_manager
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-85-based.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/password_manager')
-rw-r--r--chromium/components/password_manager/content/browser/bad_message.cc2
-rw-r--r--chromium/components/password_manager/content/browser/content_credential_manager.cc2
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver.cc15
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver.h3
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc3
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc18
-rw-r--r--chromium/components/password_manager/content/browser/password_manager_log_router_factory_unittest.cc2
-rw-r--r--chromium/components/password_manager/content/browser/password_requirements_service_factory.cc3
-rw-r--r--chromium/components/password_manager/core/browser/BUILD.gn18
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc24
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc9
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc20
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_database.cc10
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc8
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_unittest.cc15
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc14
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc17
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc7
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.h2
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc6
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_api.cc3
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_fetcher.cc3
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc2
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.cc3
-rw-r--r--chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc2
-rw-r--r--chromium/components/password_manager/core/browser/bulk_leak_check_service.cc12
-rw-r--r--chromium/components/password_manager/core/browser/bulk_leak_check_service.h57
-rw-r--r--chromium/components/password_manager/core/browser/bulk_leak_check_service_interface.cc13
-rw-r--r--chromium/components/password_manager/core/browser/bulk_leak_check_service_interface.h90
-rw-r--r--chromium/components/password_manager/core/browser/bulk_leak_check_service_unittest.cc26
-rw-r--r--chromium/components/password_manager/core/browser/compromised_credentials_observer_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/compromised_credentials_table_unittest.cc6
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl.cc56
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl.h4
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc147
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_logger.cc21
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_logger.h8
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_logger_unittest.cc12
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc6
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc4
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h7
-rw-r--r--chromium/components/password_manager/core/browser/export/OWNERS4
-rw-r--r--chromium/components/password_manager/core/browser/export/csv_writer_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/export/password_csv_writer.cc4
-rw-r--r--chromium/components/password_manager/core/browser/export/password_csv_writer_unittest.cc8
-rw-r--r--chromium/components/password_manager/core/browser/export/password_manager_exporter.cc14
-rw-r--r--chromium/components/password_manager/core/browser/export/password_manager_exporter.h3
-rw-r--r--chromium/components/password_manager/core/browser/export/password_manager_exporter_unittest.cc10
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher_impl.cc14
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher_impl.h12
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc120
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/form_parser.cc35
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/form_parser.h2
-rw-r--r--chromium/components/password_manager/core/browser/form_saver.h6
-rw-r--r--chromium/components/password_manager/core/browser/form_saver_impl_unittest.cc12
-rw-r--r--chromium/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc9
-rw-r--r--chromium/components/password_manager/core/browser/hsts_query.cc6
-rw-r--r--chromium/components/password_manager/core/browser/hsts_query.h8
-rw-r--r--chromium/components/password_manager/core/browser/hsts_query_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/http_auth_manager_impl.cc6
-rw-r--r--chromium/components/password_manager/core/browser/http_auth_manager_unittest.cc58
-rw-r--r--chromium/components/password_manager/core/browser/http_credentials_cleaner.cc4
-rw-r--r--chromium/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc6
-rw-r--r--chromium/components/password_manager/core/browser/http_password_store_migrator.cc19
-rw-r--r--chromium/components/password_manager/core/browser/http_password_store_migrator.h6
-rw-r--r--chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc57
-rw-r--r--chromium/components/password_manager/core/browser/import/csv_password.cc2
-rw-r--r--chromium/components/password_manager/core/browser/import/csv_password_sequence_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/import/csv_password_unittest.cc8
-rw-r--r--chromium/components/password_manager/core/browser/import/password_importer_unittest.cc11
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection/leak_detection_check_factory_impl_unittest.cc3
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_delegate.cc44
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_delegate_helper.cc2
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_delegate_helper_unittest.cc12
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_delegate_unittest.cc65
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_dialog_utils.cc35
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_dialog_utils.h3
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc66
-rw-r--r--chromium/components/password_manager/core/browser/login_database.cc222
-rw-r--r--chromium/components/password_manager/core/browser/login_database.h38
-rw-r--r--chromium/components/password_manager/core/browser/login_database_ios.cc63
-rw-r--r--chromium/components/password_manager/core/browser/login_database_ios_unittest.cc10
-rw-r--r--chromium/components/password_manager/core/browser/login_database_unittest.cc208
-rw-r--r--chromium/components/password_manager/core/browser/mock_bulk_leak_check_service.cc14
-rw-r--r--chromium/components/password_manager/core/browser/mock_bulk_leak_check_service.h38
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_feature_manager.cc2
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_feature_manager.h2
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_form_manager_for_ui.h3
-rw-r--r--chromium/components/password_manager/core/browser/multi_store_form_fetcher.cc55
-rw-r--r--chromium/components/password_manager/core/browser/multi_store_form_fetcher.h10
-rw-r--r--chromium/components/password_manager/core/browser/multi_store_form_fetcher_unittest.cc41
-rw-r--r--chromium/components/password_manager/core/browser/multi_store_password_save_manager.cc55
-rw-r--r--chromium/components/password_manager/core/browser/multi_store_password_save_manager.h3
-rw-r--r--chromium/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc83
-rw-r--r--chromium/components/password_manager/core/browser/origin_credential_store.cc5
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager.cc67
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager.h5
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc571
-rw-r--r--chromium/components/password_manager/core/browser/password_bubble_experiment_unittest.cc8
-rw-r--r--chromium/components/password_manager/core/browser/password_feature_manager.h11
-rw-r--r--chromium/components/password_manager/core/browser/password_feature_manager_impl.cc6
-rw-r--r--chromium/components/password_manager/core/browser/password_feature_manager_impl.h2
-rw-r--r--chromium/components/password_manager/core/browser/password_form_filling.cc19
-rw-r--r--chromium/components/password_manager/core/browser/password_form_filling_unittest.cc90
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.cc81
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.h19
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager_for_ui.h7
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager_unittest.cc131
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc104
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder.h114
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc486
-rw-r--r--chromium/components/password_manager/core/browser/password_generation_frame_helper.cc6
-rw-r--r--chromium/components/password_manager/core/browser/password_generation_frame_helper_unittest.cc20
-rw-r--r--chromium/components/password_manager/core/browser/password_generation_manager.cc12
-rw-r--r--chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc16
-rw-r--r--chromium/components/password_manager/core/browser/password_list_sorter.cc6
-rw-r--r--chromium/components/password_manager/core/browser/password_list_sorter.h8
-rw-r--r--chromium/components/password_manager/core/browser/password_list_sorter_unittest.cc18
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.cc141
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.h29
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.cc17
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.h38
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client_helper.cc19
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client_helper.h6
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client_helper_unittest.cc36
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_driver.h7
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_features_util.cc73
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_features_util.h33
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_features_util_unittest.cc131
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc10
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h13
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_recorder_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.cc48
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.h52
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_onboarding_unittest.cc15
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_test_utils.cc14
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_unittest.cc711
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util.cc39
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util_unittest.cc40
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc2
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detector_consumer.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_save_manager.h9
-rw-r--r--chromium/components/password_manager/core/browser/password_save_manager_impl.cc8
-rw-r--r--chromium/components/password_manager/core/browser/password_save_manager_impl.h7
-rw-r--r--chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc112
-rw-r--r--chromium/components/password_manager/core/browser/password_store.cc80
-rw-r--r--chromium/components/password_manager/core/browser/password_store.h41
-rw-r--r--chromium/components/password_manager/core/browser/password_store_change.h2
-rw-r--r--chromium/components/password_manager/core/browser/password_store_consumer.cc8
-rw-r--r--chromium/components/password_manager/core/browser/password_store_consumer.h12
-rw-r--r--chromium/components/password_manager/core/browser/password_store_default.cc16
-rw-r--r--chromium/components/password_manager/core/browser/password_store_default_unittest.cc7
-rw-r--r--chromium/components/password_manager/core/browser/password_store_signin_notifier.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_store_sync.h19
-rw-r--r--chromium/components/password_manager/core/browser/password_store_unittest.cc14
-rw-r--r--chromium/components/password_manager/core/browser/password_sync_util.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_ui_utils.cc8
-rw-r--r--chromium/components/password_manager/core/browser/password_ui_utils.h4
-rw-r--r--chromium/components/password_manager/core/browser/password_ui_utils_unittest.cc7
-rw-r--r--chromium/components/password_manager/core/browser/psl_matching_helper.cc19
-rw-r--r--chromium/components/password_manager/core/browser/psl_matching_helper_unittest.cc20
-rw-r--r--chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc1
-rw-r--r--chromium/components/password_manager/core/browser/statistics_table.cc2
-rw-r--r--chromium/components/password_manager/core/browser/statistics_table_unittest.cc5
-rw-r--r--chromium/components/password_manager/core/browser/store_metrics_reporter.cc200
-rw-r--r--chromium/components/password_manager/core/browser/store_metrics_reporter.h16
-rw-r--r--chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc136
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.cc14
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.h7
-rw-r--r--chromium/components/password_manager/core/browser/sync/password_model_type_controller.cc39
-rw-r--r--chromium/components/password_manager/core/browser/sync/password_model_type_controller.h5
-rw-r--r--chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc13
-rw-r--r--chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc46
-rw-r--r--chromium/components/password_manager/core/browser/sync_credentials_filter.cc2
-rw-r--r--chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc10
-rw-r--r--chromium/components/password_manager/core/browser/sync_username_test_base.cc2
-rw-r--r--chromium/components/password_manager/core/browser/sync_username_test_base.h6
-rw-r--r--chromium/components/password_manager/core/browser/test_password_store.cc32
-rw-r--r--chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.cc10
-rw-r--r--chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h8
-rw-r--r--chromium/components/password_manager/core/browser/ui/compromised_credentials_manager.cc269
-rw-r--r--chromium/components/password_manager/core/browser/ui/compromised_credentials_manager.h190
-rw-r--r--chromium/components/password_manager/core/browser/ui/compromised_credentials_manager_unittest.cc (renamed from chromium/components/password_manager/core/browser/ui/compromised_credentials_provider_unittest.cc)233
-rw-r--r--chromium/components/password_manager/core/browser/ui/compromised_credentials_provider.cc151
-rw-r--r--chromium/components/password_manager/core/browser/ui/compromised_credentials_provider.h105
-rw-r--r--chromium/components/password_manager/core/browser/ui/credential_utils.h25
-rw-r--r--chromium/components/password_manager/core/browser/ui/post_save_compromised_helper.cc66
-rw-r--r--chromium/components/password_manager/core/browser/ui/post_save_compromised_helper.h80
-rw-r--r--chromium/components/password_manager/core/browser/ui/post_save_compromised_helper_unittest.cc169
-rw-r--r--chromium/components/password_manager/core/browser/votes_uploader.cc4
-rw-r--r--chromium/components/password_manager/core/browser/votes_uploader.h7
-rw-r--r--chromium/components/password_manager/core/browser/votes_uploader_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/common/credential_manager_types.cc13
-rw-r--r--chromium/components/password_manager/core/common/credential_manager_types.h2
-rw-r--r--chromium/components/password_manager/core/common/credential_manager_types_unittest.cc10
-rw-r--r--chromium/components/password_manager/core/common/password_manager_features.cc22
-rw-r--r--chromium/components/password_manager/core/common/password_manager_features.h8
-rw-r--r--chromium/components/password_manager/core/common/password_manager_pref_names.cc5
-rw-r--r--chromium/components/password_manager/core/common/password_manager_pref_names.h5
-rw-r--r--chromium/components/password_manager/core/common/password_manager_ui.h9
-rw-r--r--chromium/components/password_manager/ios/account_select_fill_data.cc2
-rw-r--r--chromium/components/password_manager/ios/account_select_fill_data_unittest.cc2
-rw-r--r--chromium/components/password_manager/ios/js_password_manager.h35
-rw-r--r--chromium/components/password_manager/ios/js_password_manager.mm142
-rw-r--r--chromium/components/password_manager/ios/password_form_helper.h5
-rw-r--r--chromium/components/password_manager/ios/password_form_helper.mm64
-rw-r--r--chromium/components/password_manager/ios/password_form_helper_unittest.mm28
-rw-r--r--chromium/components/password_manager/ios/resources/password_controller.js34
-rw-r--r--chromium/components/password_manager/ios/test_helpers.cc4
209 files changed, 5451 insertions, 2704 deletions
diff --git a/chromium/components/password_manager/content/browser/bad_message.cc b/chromium/components/password_manager/content/browser/bad_message.cc
index 764e9333468..73b6e360b4c 100644
--- a/chromium/components/password_manager/content/browser/bad_message.cc
+++ b/chromium/components/password_manager/content/browser/bad_message.cc
@@ -59,7 +59,7 @@ bool CheckChildProcessSecurityPolicy(
content::RenderFrameHost* frame,
const autofill::PasswordForm& password_form,
BadMessageReason reason) {
- return CheckChildProcessSecurityPolicyForURL(frame, password_form.origin,
+ return CheckChildProcessSecurityPolicyForURL(frame, password_form.url,
reason) &&
CheckChildProcessSecurityPolicyForURL(
frame, GURL(password_form.signon_realm), reason) &&
diff --git a/chromium/components/password_manager/content/browser/content_credential_manager.cc b/chromium/components/password_manager/content/browser/content_credential_manager.cc
index d857c92b044..67e3569a931 100644
--- a/chromium/components/password_manager/content/browser/content_credential_manager.cc
+++ b/chromium/components/password_manager/content/browser/content_credential_manager.cc
@@ -16,7 +16,7 @@ ContentCredentialManager::ContentCredentialManager(
PasswordManagerClient* client)
: impl_(client) {}
-ContentCredentialManager::~ContentCredentialManager() {}
+ContentCredentialManager::~ContentCredentialManager() = default;
void ContentCredentialManager::BindRequest(
mojo::PendingReceiver<blink::mojom::CredentialManager> receiver) {
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
index 108a095999e..cfda4606ff5 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -111,9 +111,11 @@ void ContentPasswordManagerDriver::FillPasswordForm(
autofill::MaybeClearPasswordValues(form_data));
}
-void ContentPasswordManagerDriver::InformNoSavedCredentials() {
+void ContentPasswordManagerDriver::InformNoSavedCredentials(
+ bool should_show_popup_without_passwords) {
GetPasswordAutofillManager()->OnNoCredentialsFound();
- GetPasswordAutofillAgent()->InformNoSavedCredentials();
+ GetPasswordAutofillAgent()->InformNoSavedCredentials(
+ should_show_popup_without_passwords);
}
void ContentPasswordManagerDriver::FormEligibleForGenerationFound(
@@ -256,10 +258,11 @@ void ContentPasswordManagerDriver::ShowManualFallbackForSaving(
GetPasswordManager()->ShowManualFallbackForSaving(this, form_data);
if (client_->IsIsolationForPasswordSitesEnabled()) {
- // This function signals that the user is typing a password into
- // password form. Use this as a heuristic to start site-isolating the
- // form's site. This is intended to be used primarily when full site
- // isolation is not used, such as on Android.
+ // This function signals that a password field has been filled (whether by
+ // the user, JS, autofill, or some other means) or a password form has been
+ // submitted. Use this as a heuristic to start site-isolating the form's
+ // site. This is intended to be used primarily when full site isolation is
+ // not used, such as on Android.
content::SiteInstance::StartIsolatingSite(
render_frame_host_->GetSiteInstance()->GetBrowserContext(),
form_data.url);
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver.h b/chromium/components/password_manager/content/browser/content_password_manager_driver.h
index de351accb5e..5aa51d0f3a7 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver.h
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver.h
@@ -53,7 +53,8 @@ class ContentPasswordManagerDriver
int GetId() const override;
void FillPasswordForm(
const autofill::PasswordFormFillData& form_data) override;
- void InformNoSavedCredentials() override;
+ void InformNoSavedCredentials(
+ bool should_show_popup_without_passwords) override;
void FormEligibleForGenerationFound(
const autofill::PasswordFormGenerationData& form) override;
void GeneratedPasswordAccepted(const base::string16& password) override;
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc
index 1a595a784c6..1d309b25f3a 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc
@@ -56,7 +56,8 @@ ContentPasswordManagerDriverFactory::ContentPasswordManagerDriverFactory(
password_client_(password_client),
autofill_client_(autofill_client) {}
-ContentPasswordManagerDriverFactory::~ContentPasswordManagerDriverFactory() {}
+ContentPasswordManagerDriverFactory::~ContentPasswordManagerDriverFactory() =
+ default;
// static
ContentPasswordManagerDriverFactory*
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
index d89a7483d02..66ca88b17ce 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
@@ -61,13 +61,6 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
class FakePasswordAutofillAgent
: public autofill::mojom::PasswordAutofillAgent {
public:
- FakePasswordAutofillAgent()
- : called_set_logging_state_(false),
- logging_state_active_(false),
- receiver_(this) {}
-
- ~FakePasswordAutofillAgent() override {}
-
void BindPendingReceiver(mojo::ScopedInterfaceEndpointHandle handle) {
receiver_.Bind(
mojo::PendingAssociatedReceiver<autofill::mojom::PasswordAutofillAgent>(
@@ -85,7 +78,7 @@ class FakePasswordAutofillAgent
// autofill::mojom::PasswordAutofillAgent:
MOCK_METHOD1(FillPasswordForm, void(const PasswordFormFillData&));
- MOCK_METHOD0(InformNoSavedCredentials, void());
+ MOCK_METHOD1(InformNoSavedCredentials, void(bool));
MOCK_METHOD2(FillIntoFocusedField, void(bool, const base::string16&));
MOCK_METHOD1(TouchToFillClosed, void(bool));
MOCK_METHOD1(AnnotateFieldsWithParsingResult, void(const ParsingResult&));
@@ -99,17 +92,18 @@ class FakePasswordAutofillAgent
}
// Records whether SetLoggingState() gets called.
- bool called_set_logging_state_;
+ bool called_set_logging_state_ = false;
// Records data received via SetLoggingState() call.
- bool logging_state_active_;
+ bool logging_state_active_ = false;
- mojo::AssociatedReceiver<autofill::mojom::PasswordAutofillAgent> receiver_;
+ mojo::AssociatedReceiver<autofill::mojom::PasswordAutofillAgent> receiver_{
+ this};
};
PasswordFormFillData GetTestPasswordFormFillData() {
// Create the current form on the page.
PasswordForm form_on_page;
- form_on_page.origin = GURL("https://foo.com/");
+ form_on_page.url = GURL("https://foo.com/");
form_on_page.action = GURL("https://foo.com/login");
form_on_page.signon_realm = "https://foo.com/";
form_on_page.scheme = PasswordForm::Scheme::kHtml;
diff --git a/chromium/components/password_manager/content/browser/password_manager_log_router_factory_unittest.cc b/chromium/components/password_manager/content/browser/password_manager_log_router_factory_unittest.cc
index eae9faafab7..9e407ecc252 100644
--- a/chromium/components/password_manager/content/browser/password_manager_log_router_factory_unittest.cc
+++ b/chromium/components/password_manager/content/browser/password_manager_log_router_factory_unittest.cc
@@ -21,8 +21,6 @@ const char kTestText[] = "abcd1234";
class MockLogReceiver : public autofill::LogReceiver {
public:
- MockLogReceiver() {}
-
MOCK_METHOD1(LogEntry, void(const base::Value&));
};
diff --git a/chromium/components/password_manager/content/browser/password_requirements_service_factory.cc b/chromium/components/password_manager/content/browser/password_requirements_service_factory.cc
index 07f4b0665a7..72f194508e0 100644
--- a/chromium/components/password_manager/content/browser/password_requirements_service_factory.cc
+++ b/chromium/components/password_manager/content/browser/password_requirements_service_factory.cc
@@ -36,7 +36,8 @@ PasswordRequirementsServiceFactory::PasswordRequirementsServiceFactory()
"PasswordRequirementsServiceFactory",
BrowserContextDependencyManager::GetInstance()) {}
-PasswordRequirementsServiceFactory::~PasswordRequirementsServiceFactory() {}
+PasswordRequirementsServiceFactory::~PasswordRequirementsServiceFactory() =
+ default;
KeyedService* PasswordRequirementsServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
diff --git a/chromium/components/password_manager/core/browser/BUILD.gn b/chromium/components/password_manager/core/browser/BUILD.gn
index 6732d2b25b2..f642161af5f 100644
--- a/chromium/components/password_manager/core/browser/BUILD.gn
+++ b/chromium/components/password_manager/core/browser/BUILD.gn
@@ -58,6 +58,8 @@ jumbo_static_library("browser") {
"browser_save_password_progress_logger.h",
"bulk_leak_check_service.cc",
"bulk_leak_check_service.h",
+ "bulk_leak_check_service_interface.cc",
+ "bulk_leak_check_service_interface.h",
"compromised_credentials_consumer.cc",
"compromised_credentials_consumer.h",
"compromised_credentials_observer.cc",
@@ -216,8 +218,8 @@ jumbo_static_library("browser") {
"sync_credentials_filter.h",
"ui/bulk_leak_check_service_adapter.cc",
"ui/bulk_leak_check_service_adapter.h",
- "ui/compromised_credentials_provider.cc",
- "ui/compromised_credentials_provider.h",
+ "ui/compromised_credentials_manager.cc",
+ "ui/compromised_credentials_manager.h",
"ui/credential_provider_interface.h",
"ui/credential_utils.h",
"ui/export_flow.h",
@@ -226,6 +228,8 @@ jumbo_static_library("browser") {
"ui/password_check_referrer.cc",
"ui/password_check_referrer.h",
"ui/plaintext_reason.h",
+ "ui/post_save_compromised_helper.cc",
+ "ui/post_save_compromised_helper.h",
"ui/saved_passwords_presenter.cc",
"ui/saved_passwords_presenter.h",
"votes_uploader.cc",
@@ -261,6 +265,7 @@ jumbo_static_library("browser") {
":proto",
"//base",
"//base:i18n",
+ "//base/util/ranges:ranges",
"//components/autofill/core/browser",
"//components/autofill/core/browser/proto",
"//components/autofill/core/common",
@@ -427,6 +432,8 @@ jumbo_static_library("test_support") {
"android_affiliation/mock_affiliation_consumer.h",
"fake_form_fetcher.cc",
"fake_form_fetcher.h",
+ "mock_bulk_leak_check_service.cc",
+ "mock_bulk_leak_check_service.h",
"mock_password_feature_manager.cc",
"mock_password_feature_manager.h",
"mock_password_form_manager_for_ui.cc",
@@ -451,11 +458,13 @@ jumbo_static_library("test_support") {
":browser",
":hash_password_manager",
"//components/autofill/core/browser:test_support",
+ "//components/keyed_service/core",
+ "//components/password_manager/core/browser/leak_detection",
"//components/safe_browsing:buildflags",
"//components/ukm",
"//services/network/public/cpp",
"//testing/gmock",
- "//url:url",
+ "//url",
]
deps = [
":affiliation",
@@ -584,7 +593,8 @@ source_set("unit_tests") {
"sync_username_test_base.cc",
"sync_username_test_base.h",
"ui/bulk_leak_check_service_adapter_unittest.cc",
- "ui/compromised_credentials_provider_unittest.cc",
+ "ui/compromised_credentials_manager_unittest.cc",
+ "ui/post_save_compromised_helper_unittest.cc",
"ui/saved_passwords_presenter_unittest.cc",
"vote_uploads_test_matchers.h",
"votes_uploader_unittest.cc",
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
index 03e2b1d891b..27a948266b3 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
@@ -12,6 +12,7 @@
#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_mock_time_message_loop_task_runner.h"
@@ -34,8 +35,6 @@ class MockAffiliationService : public testing::StrictMock<AffiliationService> {
testing::DefaultValue<AffiliatedFacets>::Set(AffiliatedFacets());
}
- ~MockAffiliationService() override {}
-
MOCK_METHOD2(OnGetAffiliationsAndBrandingCalled,
AffiliatedFacets(const FacetURI&, StrategyOnCacheMiss));
MOCK_METHOD2(Prefetch, void(const FacetURI&, const base::Time&));
@@ -173,9 +172,7 @@ PasswordStore::FormDigest GetTestObservedWebForm(const char* signon_realm,
class AffiliatedMatchHelperTest : public testing::Test {
public:
- AffiliatedMatchHelperTest()
- : expecting_result_callback_(false), mock_affiliation_service_(nullptr) {}
- ~AffiliatedMatchHelperTest() override {}
+ AffiliatedMatchHelperTest() = default;
protected:
void RunDeferredInitialization() {
@@ -329,15 +326,13 @@ class AffiliatedMatchHelperTest : public testing::Test {
// testing::Test:
void SetUp() override {
- std::unique_ptr<MockAffiliationService> service(
- new MockAffiliationService());
+ auto service = std::make_unique<MockAffiliationService>();
mock_affiliation_service_ = service.get();
- password_store_ = new TestPasswordStore;
password_store_->Init(nullptr);
- match_helper_.reset(
- new AffiliatedMatchHelper(password_store_.get(), std::move(service)));
+ match_helper_ = std::make_unique<AffiliatedMatchHelper>(
+ password_store_.get(), std::move(service));
}
void TearDown() override {
@@ -353,13 +348,14 @@ class AffiliatedMatchHelperTest : public testing::Test {
std::vector<std::string> last_result_realms_;
std::vector<std::unique_ptr<autofill::PasswordForm>> last_result_forms_;
- bool expecting_result_callback_;
+ bool expecting_result_callback_ = false;
- scoped_refptr<TestPasswordStore> password_store_;
+ scoped_refptr<TestPasswordStore> password_store_ =
+ base::MakeRefCounted<TestPasswordStore>();
std::unique_ptr<AffiliatedMatchHelper> match_helper_;
// Owned by |match_helper_|.
- MockAffiliationService* mock_affiliation_service_;
+ MockAffiliationService* mock_affiliation_service_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(AffiliatedMatchHelperTest);
};
@@ -505,7 +501,7 @@ TEST_F(AffiliatedMatchHelperTest, InjectAffiliationAndBrandingInformation) {
autofill::PasswordForm web_form;
web_form.scheme = digest.scheme;
web_form.signon_realm = digest.signon_realm;
- web_form.origin = digest.origin;
+ web_form.url = digest.url;
forms.push_back(std::make_unique<autofill::PasswordForm>(web_form));
size_t expected_form_count = forms.size();
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc
index 7f785e8659e..dea78886d63 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc
@@ -37,8 +37,7 @@ AffiliationBackend::AffiliationBackend(
DETACH_FROM_SEQUENCE(sequence_checker_);
}
-AffiliationBackend::~AffiliationBackend() {
-}
+AffiliationBackend::~AffiliationBackend() = default;
void AffiliationBackend::Initialize(
std::unique_ptr<network::PendingSharedURLLoaderFactory>
@@ -47,14 +46,14 @@ void AffiliationBackend::Initialize(
const base::FilePath& db_path) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!throttler_);
- throttler_.reset(new AffiliationFetchThrottler(
- this, task_runner_, network_connection_tracker, tick_clock_));
+ throttler_ = std::make_unique<AffiliationFetchThrottler>(
+ this, task_runner_, network_connection_tracker, tick_clock_);
// TODO(engedy): Currently, when Init() returns false, it always poisons the
// DB, so subsequent operations will silently fail. Consider either fully
// committing to this approach and making Init() a void, or handling the
// return value here. See: https://crbug.com/478831.
- cache_.reset(new AffiliationDatabase());
+ cache_ = std::make_unique<AffiliationDatabase>();
cache_->Init(db_path);
DCHECK(pending_url_loader_factory);
DCHECK(!url_loader_factory_);
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
index 339bf8f8540..c3a264a5e6f 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
@@ -12,6 +12,7 @@
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
#include "base/test/task_environment.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/test/test_simple_task_runner.h"
@@ -160,11 +161,7 @@ base::TimeDelta Epsilon() {
class AffiliationBackendTest : public testing::Test {
public:
- AffiliationBackendTest()
- : backend_task_runner_(new base::TestMockTimeTaskRunner),
- consumer_task_runner_(new base::TestSimpleTaskRunner),
- mock_fetch_throttler_(nullptr) {}
- ~AffiliationBackendTest() override {}
+ AffiliationBackendTest() = default;
protected:
void GetAffiliationsAndBranding(MockAffiliationConsumer* consumer,
@@ -341,9 +338,9 @@ class AffiliationBackendTest : public testing::Test {
// testing::Test:
void SetUp() override {
ASSERT_TRUE(CreateTemporaryFile(&db_path_));
- backend_.reset(new AffiliationBackend(
+ backend_ = std::make_unique<AffiliationBackend>(
backend_task_runner_, backend_task_runner_->GetMockClock(),
- backend_task_runner_->GetMockTickClock()));
+ backend_task_runner_->GetMockTickClock());
auto test_shared_loader_factory =
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_);
@@ -364,15 +361,18 @@ class AffiliationBackendTest : public testing::Test {
}
base::test::TaskEnvironment task_environment_;
- scoped_refptr<base::TestMockTimeTaskRunner> backend_task_runner_;
- scoped_refptr<base::TestSimpleTaskRunner> consumer_task_runner_;
+ scoped_refptr<base::TestMockTimeTaskRunner> backend_task_runner_ =
+ base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+ scoped_refptr<base::TestSimpleTaskRunner> consumer_task_runner_ =
+ base::MakeRefCounted<base::TestSimpleTaskRunner>();
base::FilePath db_path_;
ScopedFakeAffiliationAPI fake_affiliation_api_;
MockAffiliationConsumer mock_consumer_;
std::unique_ptr<AffiliationBackend> backend_;
network::TestURLLoaderFactory test_url_loader_factory_;
- MockAffiliationFetchThrottler* mock_fetch_throttler_; // Owned by |backend_|.
+ // Owned by |backend_|.
+ MockAffiliationFetchThrottler* mock_fetch_throttler_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(AffiliationBackendTest);
};
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_database.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_database.cc
index b08bbdf3794..30ae8a92936 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_database.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_database.cc
@@ -6,6 +6,8 @@
#include <stdint.h>
+#include <memory>
+
#include <vector>
#include "base/bind.h"
@@ -30,14 +32,12 @@ const int kCompatibleVersion = 1;
} // namespace
-AffiliationDatabase::AffiliationDatabase() {
-}
+AffiliationDatabase::AffiliationDatabase() = default;
-AffiliationDatabase::~AffiliationDatabase() {
-}
+AffiliationDatabase::~AffiliationDatabase() = default;
bool AffiliationDatabase::Init(const base::FilePath& path) {
- sql_connection_.reset(new sql::Database);
+ sql_connection_ = std::make_unique<sql::Database>();
sql_connection_->set_histogram_tag("Affiliation");
sql_connection_->set_error_callback(base::BindRepeating(
&AffiliationDatabase::SQLErrorCallback, base::Unretained(this)));
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc
index 56d311b6a53..724756ce390 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc
@@ -6,8 +6,11 @@
#include <stdint.h>
+#include <memory>
+
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/path_service.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
@@ -80,8 +83,7 @@ AffiliatedFacetsWithUpdateTime TestEquivalenceClass3() {
class AffiliationDatabaseTest : public testing::Test {
public:
- AffiliationDatabaseTest() {}
- ~AffiliationDatabaseTest() override {}
+ AffiliationDatabaseTest() = default;
void SetUp() override {
ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
@@ -89,7 +91,7 @@ class AffiliationDatabaseTest : public testing::Test {
}
void OpenDatabase() {
- db_.reset(new AffiliationDatabase);
+ db_ = std::make_unique<AffiliationDatabase>();
ASSERT_TRUE(db_->Init(db_path()));
}
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_unittest.cc
index 8dba0afeca3..a931dbc7a0b 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_unittest.cc
@@ -13,6 +13,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
#include "base/numerics/safe_math.h"
#include "base/test/task_environment.h"
#include "base/test/test_mock_time_task_runner.h"
@@ -63,13 +64,7 @@ class MockAffiliationFetchThrottlerDelegate
class AffiliationFetchThrottlerTest : public testing::Test {
public:
- AffiliationFetchThrottlerTest()
- : task_runner_(new base::TestMockTimeTaskRunner),
- mock_delegate_(task_runner_->GetMockTickClock()) {
- SimulateHasNetworkConnectivity(true);
- }
-
- ~AffiliationFetchThrottlerTest() override {}
+ AffiliationFetchThrottlerTest() { SimulateHasNetworkConnectivity(true); }
std::unique_ptr<AffiliationFetchThrottler> CreateThrottler() {
return std::make_unique<AffiliationFetchThrottler>(
@@ -128,8 +123,10 @@ class AffiliationFetchThrottlerTest : public testing::Test {
// Needed because NetworkConnectionTracker uses base::ObserverList, which
// notifies observers on the sequence from which they have registered.
base::test::TaskEnvironment task_environment_;
- scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
- MockAffiliationFetchThrottlerDelegate mock_delegate_;
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_ =
+ base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+ MockAffiliationFetchThrottlerDelegate mock_delegate_{
+ task_runner_->GetMockTickClock()};
DISALLOW_COPY_AND_ASSIGN(AffiliationFetchThrottlerTest);
};
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
index 95701792649..b3bbda151e9 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
@@ -35,8 +35,7 @@ const char kExampleWebFacet2URI[] = "https://www.example.org";
class MockAffiliationFetcherDelegate
: public testing::StrictMock<AffiliationFetcherDelegate> {
public:
- MockAffiliationFetcherDelegate() {}
- ~MockAffiliationFetcherDelegate() {}
+ MockAffiliationFetcherDelegate() = default;
MOCK_METHOD0(OnFetchSucceededProxy, void());
MOCK_METHOD0(OnFetchFailed, void());
@@ -59,10 +58,7 @@ class MockAffiliationFetcherDelegate
class AffiliationFetcherTest : public testing::Test {
public:
- AffiliationFetcherTest()
- : test_shared_loader_factory_(
- base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
- &test_url_loader_factory_)) {
+ AffiliationFetcherTest() {
test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
[&](const network::ResourceRequest& request) {
intercepted_body_ = network::GetUploadData(request);
@@ -70,8 +66,6 @@ class AffiliationFetcherTest : public testing::Test {
}));
}
- ~AffiliationFetcherTest() override {}
-
protected:
void VerifyRequestPayload(const std::vector<FacetURI>& expected_facet_uris) {
affiliation_pb::LookupAffiliationRequest request;
@@ -121,7 +115,9 @@ class AffiliationFetcherTest : public testing::Test {
private:
base::test::TaskEnvironment task_environment_;
network::TestURLLoaderFactory test_url_loader_factory_;
- scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
+ scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_ =
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ &test_url_loader_factory_);
std::string intercepted_body_;
net::HttpRequestHeaders intercepted_headers_;
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc
index 36c337b3145..686f51f8c0a 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc
@@ -13,6 +13,7 @@
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
#include "base/test/task_environment.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/test/test_simple_task_runner.h"
@@ -49,12 +50,7 @@ AffiliatedFacets GetTestEquivalenceClassAlpha() {
class AffiliationServiceTest : public testing::Test {
public:
- AffiliationServiceTest()
- : background_task_runner_(new base::TestMockTimeTaskRunner()),
- test_shared_loader_factory_(
- base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
- &test_url_loader_factory_)) {}
- ~AffiliationServiceTest() override {}
+ AffiliationServiceTest() = default;
protected:
void DestroyService() { service_.reset(); }
@@ -81,7 +77,7 @@ class AffiliationServiceTest : public testing::Test {
network::TestNetworkConnectionTracker::GetInstance();
network_connection_tracker->SetConnectionType(
network::mojom::ConnectionType::CONNECTION_ETHERNET);
- service_.reset(new AffiliationService(background_task_runner()));
+ service_ = std::make_unique<AffiliationService>(background_task_runner());
service_->Initialize(test_shared_loader_factory_,
network_connection_tracker, database_path);
// Note: the background task runner is purposely not pumped here, so that
@@ -98,9 +94,12 @@ class AffiliationServiceTest : public testing::Test {
background_task_runner_->RunUntilIdle();
}
- scoped_refptr<base::TestMockTimeTaskRunner> background_task_runner_;
+ scoped_refptr<base::TestMockTimeTaskRunner> background_task_runner_ =
+ base::MakeRefCounted<base::TestMockTimeTaskRunner>();
network::TestURLLoaderFactory test_url_loader_factory_;
- scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
+ scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_ =
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ &test_url_loader_factory_);
ScopedFakeAffiliationAPI fake_affiliation_api_;
MockAffiliationConsumer mock_consumer_;
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc
index 74904c302f5..a073adb0bc6 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc
@@ -268,15 +268,12 @@ FacetURI::FacetURI(const std::string& canonical_spec, bool is_valid)
// AffiliatedFacetsWithUpdateTime ---------------------------------------------
-AffiliatedFacetsWithUpdateTime::AffiliatedFacetsWithUpdateTime() {
-}
+AffiliatedFacetsWithUpdateTime::AffiliatedFacetsWithUpdateTime() = default;
AffiliatedFacetsWithUpdateTime::AffiliatedFacetsWithUpdateTime(
const AffiliatedFacetsWithUpdateTime& other) = default;
-AffiliatedFacetsWithUpdateTime::~AffiliatedFacetsWithUpdateTime() {
-}
-
+AffiliatedFacetsWithUpdateTime::~AffiliatedFacetsWithUpdateTime() = default;
// Helpers --------------------------------------------------------------------
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.h b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.h
index 65a3ee0f2eb..cebec0a3215 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.h
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.h
@@ -49,7 +49,7 @@
#include <string>
#include <vector>
-#include "base/logging.h"
+#include "base/check.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "url/gurl.h"
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc
index a6b7bd9c68e..9e9bd6afcdd 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc
@@ -83,9 +83,7 @@ class TestFacetManagerNotifier {
class MockFacetManagerHost : public FacetManagerHost {
public:
explicit MockFacetManagerHost(TestFacetManagerNotifier* notifier)
- : notifier_(notifier), signaled_need_network_request_(false) {}
-
- ~MockFacetManagerHost() override {}
+ : notifier_(notifier) {}
// Sets the |facet_uri| that will be expected to appear in calls coming from
// the FacetManager under test.
@@ -144,7 +142,7 @@ class MockFacetManagerHost : public FacetManagerHost {
FacetURI expected_facet_uri_;
AffiliatedFacetsWithUpdateTime fake_database_content_;
- bool signaled_need_network_request_;
+ bool signaled_need_network_request_ = false;
DISALLOW_COPY_AND_ASSIGN(MockFacetManagerHost);
};
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_api.cc b/chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_api.cc
index c926b0bb5a5..672f55f64f9 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_api.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_api.cc
@@ -12,8 +12,7 @@
namespace password_manager {
-ScopedFakeAffiliationAPI::ScopedFakeAffiliationAPI() {
-}
+ScopedFakeAffiliationAPI::ScopedFakeAffiliationAPI() = default;
ScopedFakeAffiliationAPI::~ScopedFakeAffiliationAPI() {
// Note that trying to provide details of dangling fetchers would be unwise,
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_fetcher.cc b/chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_fetcher.cc
index 8fa599f63f7..c723cf173d8 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_fetcher.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_fetcher.cc
@@ -15,8 +15,7 @@ password_manager::FakeAffiliationFetcher::FakeAffiliationFetcher(
AffiliationFetcherDelegate* delegate)
: AffiliationFetcher(std::move(url_loader_factory), facet_ids, delegate) {}
-password_manager::FakeAffiliationFetcher::~FakeAffiliationFetcher() {
-}
+password_manager::FakeAffiliationFetcher::~FakeAffiliationFetcher() = default;
void password_manager::FakeAffiliationFetcher::SimulateSuccess(
std::unique_ptr<AffiliationFetcherDelegate::Result> fake_result) {
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc b/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc
index d0691be56da..ec21d9d5c83 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc
@@ -16,7 +16,7 @@ namespace password_manager {
MockAffiliatedMatchHelper::MockAffiliatedMatchHelper()
: AffiliatedMatchHelper(nullptr, nullptr) {}
-MockAffiliatedMatchHelper::~MockAffiliatedMatchHelper() {}
+MockAffiliatedMatchHelper::~MockAffiliatedMatchHelper() = default;
void MockAffiliatedMatchHelper::ExpectCallToGetAffiliatedAndroidRealms(
const PasswordStore::FormDigest& expected_observed_form,
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.cc b/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.cc
index f55a883799c..5b86f99380b 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.cc
@@ -13,8 +13,7 @@ MockAffiliationConsumer::MockAffiliationConsumer() {
EXPECT_CALL(*this, OnResultCallback(testing::_, testing::_)).Times(0);
}
-MockAffiliationConsumer::~MockAffiliationConsumer() {
-}
+MockAffiliationConsumer::~MockAffiliationConsumer() = default;
void MockAffiliationConsumer::ExpectSuccessWithResult(
const AffiliatedFacets& expected_result) {
diff --git a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
index 88c18f259f4..4452b7f1e8a 100644
--- a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
+++ b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
@@ -285,7 +285,7 @@ void BrowserSavePasswordProgressLogger::LogPasswordForm(
GetStringFromID(FormSchemeToStringID(form.scheme)));
log.SetString(GetStringFromID(STRING_SIGNON_REALM),
ScrubURL(GURL(form.signon_realm)));
- log.SetString(GetStringFromID(STRING_ORIGIN), ScrubURL(form.origin));
+ log.SetString(GetStringFromID(STRING_ORIGIN), ScrubURL(form.url));
log.SetString(GetStringFromID(STRING_ACTION), ScrubURL(form.action));
log.SetString(GetStringFromID(STRING_USERNAME_ELEMENT),
ScrubElementID(form.username_element));
diff --git a/chromium/components/password_manager/core/browser/bulk_leak_check_service.cc b/chromium/components/password_manager/core/browser/bulk_leak_check_service.cc
index 7870a318b1b..4d29976be2c 100644
--- a/chromium/components/password_manager/core/browser/bulk_leak_check_service.cc
+++ b/chromium/components/password_manager/core/browser/bulk_leak_check_service.cc
@@ -134,6 +134,18 @@ size_t BulkLeakCheckService::GetPendingChecksCount() const {
return bulk_leak_check_ ? bulk_leak_check_->GetPendingChecksCount() : 0;
}
+BulkLeakCheckService::State BulkLeakCheckService::GetState() const {
+ return state_;
+}
+
+void BulkLeakCheckService::AddObserver(Observer* obs) {
+ observers_.AddObserver(obs);
+}
+
+void BulkLeakCheckService::RemoveObserver(Observer* obs) {
+ observers_.RemoveObserver(obs);
+}
+
void BulkLeakCheckService::Shutdown() {
observers_.Clear();
metrics_reporter_.reset();
diff --git a/chromium/components/password_manager/core/browser/bulk_leak_check_service.h b/chromium/components/password_manager/core/browser/bulk_leak_check_service.h
index 04229822a96..29130923861 100644
--- a/chromium/components/password_manager/core/browser/bulk_leak_check_service.h
+++ b/chromium/components/password_manager/core/browser/bulk_leak_check_service.h
@@ -11,7 +11,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
-#include "components/keyed_service/core/keyed_service.h"
+#include "components/password_manager/core/browser/bulk_leak_check_service_interface.h"
#include "components/password_manager/core/browser/leak_detection/bulk_leak_check.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_check_factory.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_delegate_interface.h"
@@ -26,68 +26,32 @@ class IdentityManager;
namespace password_manager {
-class BulkLeakCheck;
-
// The service that allows to check arbitrary number of passwords against the
// database of leaked credentials.
-class BulkLeakCheckService : public KeyedService,
- public BulkLeakCheckDelegateInterface {
+class BulkLeakCheckService : public BulkLeakCheckDelegateInterface,
+ public BulkLeakCheckServiceInterface {
public:
- enum class State {
- // The service is idle and there was no previous error.
- kIdle,
- // The service is checking some credentials.
- kRunning,
-
- // Those below are error states. On any error the current job is aborted.
- // The error is sticky until next CheckUsernamePasswordPairs() call.
-
- // Cancel() aborted the running check.
- kCanceled,
- // The user isn't signed-in to Chrome.
- kSignedOut,
- // Error obtaining an access token.
- kTokenRequestFailure,
- // Error in hashing/encrypting for the request.
- kHashingFailure,
- // Error related to network.
- kNetworkError,
- // Error related to the password leak Google service.
- kServiceError,
- // Error related to the quota limit of the password leak Google service.
- kQuotaLimit,
- };
-
- class Observer : public base::CheckedObserver {
- public:
- // BulkLeakCheckService changed its state.
- virtual void OnStateChanged(State state) = 0;
-
- // Called when |credential| is analyzed.
- virtual void OnCredentialDone(const LeakCheckCredential& credential,
- IsLeaked is_leaked) = 0;
- };
-
BulkLeakCheckService(
signin::IdentityManager* identity_manager,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
~BulkLeakCheckService() override;
// Starts the checks or appends |credentials| to the existing queue.
- void CheckUsernamePasswordPairs(std::vector<LeakCheckCredential> credentials);
+ void CheckUsernamePasswordPairs(
+ std::vector<LeakCheckCredential> credentials) override;
// Stops all the current checks immediately.
- void Cancel();
+ void Cancel() override;
// Returns number of pending passwords to be checked.
- size_t GetPendingChecksCount() const;
+ size_t GetPendingChecksCount() const override;
// Returns the current state of the service.
- State state() const { return state_; }
+ State GetState() const override;
- void AddObserver(Observer* obs) { observers_.AddObserver(obs); }
+ void AddObserver(Observer* obs) override;
- void RemoveObserver(Observer* obs) { observers_.RemoveObserver(obs); }
+ void RemoveObserver(Observer* obs) override;
// KeyedService:
void Shutdown() override;
@@ -124,6 +88,7 @@ class BulkLeakCheckService : public KeyedService,
std::unique_ptr<MetricsReporter> metrics_reporter_;
State state_ = State::kIdle;
+
base::ObserverList<Observer> observers_;
};
diff --git a/chromium/components/password_manager/core/browser/bulk_leak_check_service_interface.cc b/chromium/components/password_manager/core/browser/bulk_leak_check_service_interface.cc
new file mode 100644
index 00000000000..9cc9c70308e
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/bulk_leak_check_service_interface.cc
@@ -0,0 +1,13 @@
+// Copyright 2020 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/password_manager/core/browser/bulk_leak_check_service_interface.h"
+
+namespace password_manager {
+
+BulkLeakCheckServiceInterface::BulkLeakCheckServiceInterface() = default;
+
+BulkLeakCheckServiceInterface::~BulkLeakCheckServiceInterface() = default;
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/bulk_leak_check_service_interface.h b/chromium/components/password_manager/core/browser/bulk_leak_check_service_interface.h
new file mode 100644
index 00000000000..f471ef9e089
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/bulk_leak_check_service_interface.h
@@ -0,0 +1,90 @@
+// Copyright 2020 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_PASSWORD_MANAGER_CORE_BROWSER_BULK_LEAK_CHECK_SERVICE_INTERFACE_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_BULK_LEAK_CHECK_SERVICE_INTERFACE_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/observer_list_types.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/password_manager/core/browser/leak_detection/bulk_leak_check.h"
+#include "components/password_manager/core/browser/leak_detection/leak_detection_delegate_interface.h"
+
+namespace password_manager {
+
+// The interface for a service that allows to check arbitrary number of
+// passwords against the database of leaked credentials.
+class BulkLeakCheckServiceInterface : public KeyedService {
+ public:
+ // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.password_check
+ // GENERATED_JAVA_CLASS_NAME_OVERRIDE: BulkLeakCheckServiceState
+ enum class State {
+ // The service is idle and there was no previous error.
+ kIdle,
+ // The service is checking some credentials.
+ kRunning,
+
+ // Those below are error states. On any error the current job is aborted.
+ // The error is sticky until next CheckUsernamePasswordPairs() call.
+
+ // Cancel() aborted the running check.
+ kCanceled,
+ // The user isn't signed-in to Chrome.
+ kSignedOut,
+ // Error obtaining an access token.
+ kTokenRequestFailure,
+ // Error in hashing/encrypting for the request.
+ kHashingFailure,
+ // Error related to network.
+ kNetworkError,
+ // Error related to the password leak Google service.
+ kServiceError,
+ // Error related to the quota limit of the password leak Google service.
+ kQuotaLimit,
+ };
+
+ class Observer : public base::CheckedObserver {
+ public:
+ // BulkLeakCheckService changed its state.
+ virtual void OnStateChanged(State state) = 0;
+
+ // Called when |credential| is analyzed.
+ virtual void OnCredentialDone(const LeakCheckCredential& credential,
+ IsLeaked is_leaked) = 0;
+ };
+
+ BulkLeakCheckServiceInterface();
+ ~BulkLeakCheckServiceInterface() override;
+
+ // Not copyable or movable
+ BulkLeakCheckServiceInterface(const BulkLeakCheckServiceInterface&) = delete;
+ BulkLeakCheckServiceInterface& operator=(
+ const BulkLeakCheckServiceInterface&) = delete;
+ BulkLeakCheckServiceInterface(BulkLeakCheckServiceInterface&&) = delete;
+ BulkLeakCheckServiceInterface& operator=(BulkLeakCheckServiceInterface&&) =
+ delete;
+
+ // Starts the checks or appends |credentials| to the existing queue.
+ virtual void CheckUsernamePasswordPairs(
+ std::vector<LeakCheckCredential> credentials) = 0;
+
+ // Stops all the current checks immediately.
+ virtual void Cancel() = 0;
+
+ // Returns number of pending passwords to be checked.
+ virtual size_t GetPendingChecksCount() const = 0;
+
+ // Returns the current state of the service.
+ virtual State GetState() const = 0;
+
+ virtual void AddObserver(Observer* obs) = 0;
+
+ virtual void RemoveObserver(Observer* obs) = 0;
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_BULK_LEAK_CHECK_SERVICE_INTERFACE_H_
diff --git a/chromium/components/password_manager/core/browser/bulk_leak_check_service_unittest.cc b/chromium/components/password_manager/core/browser/bulk_leak_check_service_unittest.cc
index 68518d78b58..aa406bb332b 100644
--- a/chromium/components/password_manager/core/browser/bulk_leak_check_service_unittest.cc
+++ b/chromium/components/password_manager/core/browser/bulk_leak_check_service_unittest.cc
@@ -124,12 +124,12 @@ void BulkLeakCheckServiceTest::ConductLeakCheck(
EXPECT_CALL(*weak_leak_check, GetPendingChecksCount)
.WillRepeatedly(Return(0));
delegate->OnFinishedCredential(TestCredential(), is_leaked);
- EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().GetState());
}
TEST_F(BulkLeakCheckServiceTest, OnCreation) {
EXPECT_EQ(0u, service().GetPendingChecksCount());
- EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().GetState());
EXPECT_THAT(
histogram_tester().GetTotalCountsForPrefix("PasswordManager.BulkCheck"),
@@ -141,7 +141,7 @@ TEST_F(BulkLeakCheckServiceTest, StartWithZeroPasswords) {
service().AddObserver(&observer);
service().CheckUsernamePasswordPairs({});
- EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().GetState());
EXPECT_EQ(0u, service().GetPendingChecksCount());
EXPECT_THAT(
histogram_tester().GetTotalCountsForPrefix("PasswordManager.BulkCheck"),
@@ -162,7 +162,7 @@ TEST_F(BulkLeakCheckServiceTest, Running) {
EXPECT_CALL(observer, OnStateChanged(BulkLeakCheckService::State::kRunning));
service().CheckUsernamePasswordPairs(TestCredentials());
- EXPECT_EQ(BulkLeakCheckService::State::kRunning, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kRunning, service().GetState());
EXPECT_CALL(*weak_leak_check, GetPendingChecksCount)
.WillRepeatedly(Return(10));
EXPECT_EQ(10u, service().GetPendingChecksCount());
@@ -189,7 +189,7 @@ TEST_F(BulkLeakCheckServiceTest, AppendRunning) {
EXPECT_CALL(observer, OnStateChanged(BulkLeakCheckService::State::kRunning));
service().CheckUsernamePasswordPairs(TestCredentials());
- EXPECT_EQ(BulkLeakCheckService::State::kRunning, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kRunning, service().GetState());
EXPECT_CALL(*weak_leak_check, GetPendingChecksCount)
.WillRepeatedly(Return(20));
EXPECT_EQ(20u, service().GetPendingChecksCount());
@@ -203,7 +203,7 @@ TEST_F(BulkLeakCheckServiceTest, FailedToCreateCheck) {
.WillOnce(Return(ByMove(nullptr)));
service().CheckUsernamePasswordPairs(TestCredentials());
- EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().GetState());
EXPECT_EQ(0u, service().GetPendingChecksCount());
EXPECT_THAT(
histogram_tester().GetTotalCountsForPrefix("PasswordManager.BulkCheck"),
@@ -223,7 +223,7 @@ TEST_F(BulkLeakCheckServiceTest, FailedToCreateCheckWithError) {
OnStateChanged(BulkLeakCheckService::State::kSignedOut));
service().CheckUsernamePasswordPairs(TestCredentials());
- EXPECT_EQ(BulkLeakCheckService::State::kSignedOut, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kSignedOut, service().GetState());
EXPECT_EQ(0u, service().GetPendingChecksCount());
base::HistogramTester::CountsMap expected_counts;
expected_counts["PasswordManager.BulkCheck.Error"] = 1;
@@ -240,7 +240,7 @@ TEST_F(BulkLeakCheckServiceTest, CancelNothing) {
service().Cancel();
- EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().GetState());
EXPECT_EQ(0u, service().GetPendingChecksCount());
EXPECT_THAT(
histogram_tester().GetTotalCountsForPrefix("PasswordManager.BulkCheck"),
@@ -259,7 +259,7 @@ TEST_F(BulkLeakCheckServiceTest, CancelSomething) {
EXPECT_CALL(observer, OnStateChanged(BulkLeakCheckService::State::kCanceled));
service().Cancel();
- EXPECT_EQ(BulkLeakCheckService::State::kCanceled, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kCanceled, service().GetState());
EXPECT_EQ(0u, service().GetPendingChecksCount());
histogram_tester().ExpectUniqueSample(
"PasswordManager.BulkCheck.CanceledCredentials", 2, 1);
@@ -315,7 +315,7 @@ TEST_F(BulkLeakCheckServiceTest, CheckFinished) {
IsLeaked(false)));
delegate->OnFinishedCredential(TestCredential(), IsLeaked(false));
- EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().GetState());
EXPECT_EQ(0u, service().GetPendingChecksCount());
histogram_tester().ExpectUniqueSample(
"PasswordManager.BulkCheck.CheckedCredentials", 2, 1);
@@ -351,7 +351,7 @@ TEST_F(BulkLeakCheckServiceTest, CheckFinishedWithLeakedCredential) {
}
delegate->OnFinishedCredential(TestCredential(), IsLeaked(true));
- EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kIdle, service().GetState());
EXPECT_EQ(0u, service().GetPendingChecksCount());
histogram_tester().ExpectUniqueSample(
"PasswordManager.BulkCheck.CheckedCredentials", 2, 1);
@@ -407,7 +407,7 @@ TEST_F(BulkLeakCheckServiceTest, CheckFinishedWithError) {
OnStateChanged(BulkLeakCheckService::State::kServiceError));
delegate->OnError(LeakDetectionError::kInvalidServerResponse);
- EXPECT_EQ(BulkLeakCheckService::State::kServiceError, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kServiceError, service().GetState());
EXPECT_EQ(0u, service().GetPendingChecksCount());
base::HistogramTester::CountsMap expected_counts;
expected_counts["PasswordManager.BulkCheck.Error"] = 1;
@@ -434,7 +434,7 @@ TEST_F(BulkLeakCheckServiceTest, CheckFinishedWithQuotaLimit) {
OnStateChanged(BulkLeakCheckService::State::kQuotaLimit));
delegate->OnError(LeakDetectionError::kQuotaLimit);
- EXPECT_EQ(BulkLeakCheckService::State::kQuotaLimit, service().state());
+ EXPECT_EQ(BulkLeakCheckService::State::kQuotaLimit, service().GetState());
EXPECT_EQ(0u, service().GetPendingChecksCount());
base::HistogramTester::CountsMap expected_counts;
expected_counts["PasswordManager.BulkCheck.Error"] = 1;
diff --git a/chromium/components/password_manager/core/browser/compromised_credentials_observer_unittest.cc b/chromium/components/password_manager/core/browser/compromised_credentials_observer_unittest.cc
index 16ea59a9a9d..aa8e02e6376 100644
--- a/chromium/components/password_manager/core/browser/compromised_credentials_observer_unittest.cc
+++ b/chromium/components/password_manager/core/browser/compromised_credentials_observer_unittest.cc
@@ -25,8 +25,8 @@ constexpr char kUsernameNew[] = "ana";
autofill::PasswordForm TestForm(base::StringPiece username) {
autofill::PasswordForm form;
- form.origin = GURL(kSite);
- form.signon_realm = form.origin.GetOrigin().spec();
+ form.url = GURL(kSite);
+ form.signon_realm = form.url.GetOrigin().spec();
form.username_value = base::ASCIIToUTF16(username);
form.password_value = base::ASCIIToUTF16("12345");
return form;
diff --git a/chromium/components/password_manager/core/browser/compromised_credentials_table_unittest.cc b/chromium/components/password_manager/core/browser/compromised_credentials_table_unittest.cc
index f87f65fd053..356c26bc91b 100644
--- a/chromium/components/password_manager/core/browser/compromised_credentials_table_unittest.cc
+++ b/chromium/components/password_manager/core/browser/compromised_credentials_table_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <memory>
+
#include "components/password_manager/core/browser/compromised_credentials_table.h"
#include "base/bind.h"
@@ -42,8 +44,8 @@ class CompromisedCredentialsTableTest : public testing::Test {
void ReloadDatabase() {
base::FilePath file = temp_dir_.GetPath().AppendASCII("TestDatabase");
- db_.reset(new CompromisedCredentialsTable);
- connection_.reset(new sql::Database);
+ db_ = std::make_unique<CompromisedCredentialsTable>();
+ connection_ = std::make_unique<sql::Database>();
connection_->set_exclusive_locking();
ASSERT_TRUE(connection_->Open(file));
db_->Init(connection_.get());
diff --git a/chromium/components/password_manager/core/browser/credential_manager_impl.cc b/chromium/components/password_manager/core/browser/credential_manager_impl.cc
index 97b8c2b0115..be90f0a8f0f 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_impl.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_impl.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "components/password_manager/core/browser/credential_manager_impl.h"
+#include <memory>
+
#include <string>
#include "base/bind.h"
@@ -29,22 +31,22 @@ CredentialManagerImpl::CredentialManagerImpl(PasswordManagerClient* client)
client_->GetPrefs());
}
-CredentialManagerImpl::~CredentialManagerImpl() {}
+CredentialManagerImpl::~CredentialManagerImpl() = default;
void CredentialManagerImpl::Store(const CredentialInfo& credential,
StoreCallback callback) {
DCHECK_NE(CredentialType::CREDENTIAL_TYPE_EMPTY, credential.type);
+ const url::Origin origin = GetOrigin();
if (password_manager_util::IsLoggingActive(client_)) {
CredentialManagerLogger(client_->GetLogManager())
- .LogStoreCredential(GetLastCommittedURL(), credential.type);
+ .LogStoreCredential(origin, credential.type);
}
// Send acknowledge response back.
std::move(callback).Run();
- const GURL origin = GetLastCommittedURL();
- if (!client_->IsSavingAndFillingEnabled(origin))
+ if (!client_->IsSavingAndFillingEnabled(origin.GetURL()))
return;
client_->NotifyStorePasswordCalled();
@@ -56,9 +58,9 @@ void CredentialManagerImpl::Store(const CredentialInfo& credential,
if (credential.type == CredentialType::CREDENTIAL_TYPE_PASSWORD)
leak_delegate_.StartLeakCheck(*form);
- std::string signon_realm = origin.GetOrigin().spec();
+ std::string signon_realm = origin.GetURL().spec();
PasswordStore::FormDigest observed_digest(
- autofill::PasswordForm::Scheme::kHtml, signon_realm, origin);
+ autofill::PasswordForm::Scheme::kHtml, signon_realm, origin.GetURL());
// Create a custom form fetcher without HTTP->HTTPS migration as the API is
// only available on HTTPS origins.
@@ -72,18 +74,18 @@ void CredentialManagerImpl::PreventSilentAccess(
PreventSilentAccessCallback callback) {
if (password_manager_util::IsLoggingActive(client_)) {
CredentialManagerLogger(client_->GetLogManager())
- .LogPreventSilentAccess(GetLastCommittedURL());
+ .LogPreventSilentAccess(GetOrigin());
}
// Send acknowledge response back.
std::move(callback).Run();
PasswordStore* store = GetPasswordStore();
- if (!store || !client_->IsSavingAndFillingEnabled(GetLastCommittedURL()))
+ if (!store || !client_->IsSavingAndFillingEnabled(GetOrigin().GetURL()))
return;
if (!pending_require_user_mediation_) {
- pending_require_user_mediation_.reset(
- new CredentialManagerPendingPreventSilentAccessTask(this));
+ pending_require_user_mediation_ =
+ std::make_unique<CredentialManagerPendingPreventSilentAccessTask>(this);
}
pending_require_user_mediation_->AddOrigin(GetSynthesizedFormForOrigin());
}
@@ -97,7 +99,7 @@ void CredentialManagerImpl::Get(CredentialMediationRequirement mediation,
PasswordStore* store = GetPasswordStore();
if (password_manager_util::IsLoggingActive(client_)) {
CredentialManagerLogger(client_->GetLogManager())
- .LogRequestCredential(GetLastCommittedURL(), mediation, federations);
+ .LogRequestCredential(GetOrigin(), mediation, federations);
}
if (pending_request_ || !store) {
// Callback error.
@@ -112,7 +114,7 @@ void CredentialManagerImpl::Get(CredentialMediationRequirement mediation,
// Return an empty credential if the current page has TLS errors, or if the
// page is being prerendered.
- if (!client_->IsFillingEnabled(GetLastCommittedURL())) {
+ if (!client_->IsFillingEnabled(GetOrigin().GetURL())) {
std::move(callback).Run(CredentialManagerError::SUCCESS, CredentialInfo());
LogCredentialManagerGetResult(
metrics_util::CredentialManagerGetResult::kNone, mediation);
@@ -126,6 +128,15 @@ void CredentialManagerImpl::Get(CredentialMediationRequirement mediation,
metrics_util::CredentialManagerGetResult::kNoneIncognito, mediation);
return;
}
+ // Return an empty credential while autofill-assistant is running.
+ if (client_->GetAutofillAssistantMode() == AutofillAssistantMode::kRunning) {
+ // Callback with empty credential info.
+ std::move(callback).Run(CredentialManagerError::SUCCESS, CredentialInfo());
+ LogCredentialManagerGetResult(
+ metrics_util::CredentialManagerGetResult::kNoneAutofillAssistant,
+ mediation);
+ return;
+ }
// Return an empty credential if zero-click is required but disabled.
if (mediation == CredentialMediationRequirement::kSilent &&
!IsZeroClickAllowed()) {
@@ -136,9 +147,9 @@ void CredentialManagerImpl::Get(CredentialMediationRequirement mediation,
return;
}
- pending_request_.reset(new CredentialManagerPendingRequestTask(
+ pending_request_ = std::make_unique<CredentialManagerPendingRequestTask>(
this, base::BindOnce(&RunGetCallback, std::move(callback)), mediation,
- include_passwords, federations));
+ include_passwords, federations);
// This will result in a callback to
// PendingRequestTask::OnGetPasswordStoreResults().
GetPasswordStore()->GetLogins(GetSynthesizedFormForOrigin(),
@@ -152,14 +163,13 @@ bool CredentialManagerImpl::IsZeroClickAllowed() const {
PasswordStore::FormDigest CredentialManagerImpl::GetSynthesizedFormForOrigin()
const {
PasswordStore::FormDigest digest = {autofill::PasswordForm::Scheme::kHtml,
- std::string(),
- GetLastCommittedURL().GetOrigin()};
- digest.signon_realm = digest.origin.spec();
+ std::string(), GetOrigin().GetURL()};
+ digest.signon_realm = digest.url.spec();
return digest;
}
-GURL CredentialManagerImpl::GetOrigin() const {
- return GetLastCommittedURL().GetOrigin();
+url::Origin CredentialManagerImpl::GetOrigin() const {
+ return client_->GetLastCommittedOrigin();
}
void CredentialManagerImpl::SendCredential(SendCredentialCallback send_callback,
@@ -168,7 +178,7 @@ void CredentialManagerImpl::SendCredential(SendCredentialCallback send_callback,
if (password_manager_util::IsLoggingActive(client_)) {
CredentialManagerLogger(client_->GetLogManager())
- .LogSendCredential(GetLastCommittedURL(), info.type);
+ .LogSendCredential(GetOrigin(), info.type);
}
std::move(send_callback).Run(info);
pending_request_.reset();
@@ -221,7 +231,7 @@ void CredentialManagerImpl::DoneRequiringUserMediation() {
void CredentialManagerImpl::OnProvisionalSaveComplete() {
DCHECK(form_manager_);
const autofill::PasswordForm& form = form_manager_->GetPendingCredentials();
- DCHECK(client_->IsSavingAndFillingEnabled(form.origin));
+ DCHECK(client_->IsSavingAndFillingEnabled(form.url));
if (form_manager_->IsPendingCredentialsPublicSuffixMatch()) {
// Having a credential with a PSL match implies there is no credential with
@@ -256,8 +266,4 @@ void CredentialManagerImpl::OnProvisionalSaveComplete() {
client_->PromptUserToSaveOrUpdatePassword(std::move(form_manager_), false);
}
-GURL CredentialManagerImpl::GetLastCommittedURL() const {
- return client_->GetLastCommittedEntryURL();
-}
-
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/credential_manager_impl.h b/chromium/components/password_manager/core/browser/credential_manager_impl.h
index 909e21b4236..cf3f0b45e51 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_impl.h
+++ b/chromium/components/password_manager/core/browser/credential_manager_impl.h
@@ -61,7 +61,7 @@ class CredentialManagerImpl
private:
// CredentialManagerPendingRequestTaskDelegate:
- GURL GetOrigin() const override;
+ url::Origin GetOrigin() const override;
void SendCredential(SendCredentialCallback send_callback,
const CredentialInfo& info) override;
void SendPasswordForm(SendCredentialCallback send_callback,
@@ -76,8 +76,6 @@ class CredentialManagerImpl
// CredentialManagerPasswordFormManagerDelegate:
void OnProvisionalSaveComplete() override;
- GURL GetLastCommittedURL() const;
-
PasswordManagerClient* client_;
// Set to false to disable automatic signing in.
diff --git a/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc b/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc
index 1984369ecd9..0d841083d93 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc
@@ -8,6 +8,8 @@
#include <algorithm>
#include <map>
+#include <memory>
+
#include <string>
#include <tuple>
@@ -26,6 +28,7 @@
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "components/password_manager/core/browser/test_password_store.h"
#include "components/password_manager/core/common/credential_manager_types.h"
+#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
@@ -67,15 +70,19 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
MOCK_METHOD1(PromptUserToSavePasswordPtr, void(PasswordFormManagerForUI*));
MOCK_METHOD3(PromptUserToChooseCredentialsPtr,
bool(const std::vector<autofill::PasswordForm*>& local_forms,
- const GURL& origin,
+ const url::Origin& origin,
const CredentialsCallback& callback));
MOCK_METHOD3(PasswordWasAutofilled,
void(const std::vector<const autofill::PasswordForm*>&,
- const GURL&,
+ const url::Origin&,
const std::vector<const autofill::PasswordForm*>*));
+ MOCK_CONST_METHOD0(GetAutofillAssistantMode, AutofillAssistantMode());
- explicit MockPasswordManagerClient(PasswordStore* store)
- : store_(store), password_manager_(this) {
+ explicit MockPasswordManagerClient(PasswordStore* profile_store,
+ PasswordStore* account_store)
+ : profile_store_(profile_store),
+ account_store_(account_store),
+ password_manager_(this) {
prefs_ = std::make_unique<TestingPrefServiceSimple>();
prefs_->registry()->RegisterBooleanPref(prefs::kCredentialsEnableAutosignin,
true);
@@ -103,7 +110,12 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
NotifyUserCouldBeAutoSignedInPtr(form.get());
}
- PasswordStore* GetProfilePasswordStore() const override { return store_; }
+ PasswordStore* GetProfilePasswordStore() const override {
+ return profile_store_;
+ }
+ PasswordStore* GetAccountPasswordStore() const override {
+ return account_store_;
+ }
PrefService* GetPrefs() const override { return prefs_.get(); }
@@ -111,13 +123,13 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
return &password_manager_;
}
- const GURL& GetLastCommittedEntryURL() const override {
- return last_committed_url_;
+ url::Origin GetLastCommittedOrigin() const override {
+ return url::Origin::Create(last_committed_url_);
}
bool PromptUserToChooseCredentials(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
- const GURL& origin,
+ const url::Origin& origin,
const CredentialsCallback& callback) override {
EXPECT_FALSE(local_forms.empty());
const autofill::PasswordForm* form = local_forms[0].get();
@@ -136,7 +148,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
void NotifyUserAutoSignin(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
- const GURL& origin) override {
+ const url::Origin& origin) override {
EXPECT_FALSE(local_forms.empty());
NotifyUserAutoSigninPtr();
}
@@ -158,7 +170,8 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
private:
std::unique_ptr<TestingPrefServiceSimple> prefs_;
- PasswordStore* store_;
+ PasswordStore* profile_store_;
+ PasswordStore* account_store_;
std::unique_ptr<PasswordFormManagerForUI> manager_;
PasswordManager password_manager_;
GURL last_committed_url_{kTestWebOrigin};
@@ -191,14 +204,19 @@ GURL HttpURLFromHttps(const GURL& https_url) {
class CredentialManagerImplTest : public testing::Test {
public:
- CredentialManagerImplTest() {}
+ CredentialManagerImplTest() = default;
void SetUp() override {
store_ = new TestPasswordStore;
- store_->Init(nullptr);
- client_.reset(
- new testing::NiceMock<MockPasswordManagerClient>(store_.get()));
- cm_service_impl_.reset(new CredentialManagerImpl(client_.get()));
+ store_->Init(/*prefs=*/nullptr);
+ if (base::FeatureList::IsEnabled(
+ features::kEnablePasswordsAccountStorage)) {
+ account_store_ = new TestPasswordStore;
+ ASSERT_TRUE(account_store_->Init(/*prefs=*/nullptr));
+ }
+ client_ = std::make_unique<testing::NiceMock<MockPasswordManagerClient>>(
+ store_.get(), account_store_.get());
+ cm_service_impl_ = std::make_unique<CredentialManagerImpl>(client_.get());
ON_CALL(*client_, IsSavingAndFillingEnabled(_))
.WillByDefault(testing::Return(true));
ON_CALL(*client_, IsFillingEnabled(_)).WillByDefault(testing::Return(true));
@@ -208,15 +226,15 @@ class CredentialManagerImplTest : public testing::Test {
form_.display_name = base::ASCIIToUTF16("Display Name");
form_.icon_url = GURL("https://example.com/icon.png");
form_.password_value = base::ASCIIToUTF16("Password");
- form_.origin = client_->GetLastCommittedEntryURL();
- form_.signon_realm = form_.origin.GetOrigin().spec();
+ form_.url = client_->GetLastCommittedOrigin().GetURL();
+ form_.signon_realm = form_.url.GetOrigin().spec();
form_.scheme = autofill::PasswordForm::Scheme::kHtml;
form_.skip_zero_click = false;
affiliated_form1_.username_value = base::ASCIIToUTF16("Affiliated 1");
affiliated_form1_.display_name = base::ASCIIToUTF16("Display Name");
affiliated_form1_.password_value = base::ASCIIToUTF16("Password");
- affiliated_form1_.origin = GURL();
+ affiliated_form1_.url = GURL();
affiliated_form1_.signon_realm = kTestAndroidRealm1;
affiliated_form1_.scheme = autofill::PasswordForm::Scheme::kHtml;
affiliated_form1_.skip_zero_click = false;
@@ -224,7 +242,7 @@ class CredentialManagerImplTest : public testing::Test {
affiliated_form2_.username_value = base::ASCIIToUTF16("Affiliated 2");
affiliated_form2_.display_name = base::ASCIIToUTF16("Display Name");
affiliated_form2_.password_value = base::ASCIIToUTF16("Password");
- affiliated_form2_.origin = GURL();
+ affiliated_form2_.url = GURL();
affiliated_form2_.signon_realm = kTestAndroidRealm2;
affiliated_form2_.scheme = autofill::PasswordForm::Scheme::kHtml;
affiliated_form2_.skip_zero_click = false;
@@ -232,26 +250,24 @@ class CredentialManagerImplTest : public testing::Test {
origin_path_form_.username_value = base::ASCIIToUTF16("Username 2");
origin_path_form_.display_name = base::ASCIIToUTF16("Display Name 2");
origin_path_form_.password_value = base::ASCIIToUTF16("Password 2");
- origin_path_form_.origin = GURL("https://example.com/path");
- origin_path_form_.signon_realm =
- origin_path_form_.origin.GetOrigin().spec();
+ origin_path_form_.url = GURL("https://example.com/path");
+ origin_path_form_.signon_realm = origin_path_form_.url.GetOrigin().spec();
origin_path_form_.scheme = autofill::PasswordForm::Scheme::kHtml;
origin_path_form_.skip_zero_click = false;
subdomain_form_.username_value = base::ASCIIToUTF16("Username 2");
subdomain_form_.display_name = base::ASCIIToUTF16("Display Name 2");
subdomain_form_.password_value = base::ASCIIToUTF16("Password 2");
- subdomain_form_.origin = GURL("https://subdomain.example.com/path");
- subdomain_form_.signon_realm = subdomain_form_.origin.GetOrigin().spec();
+ subdomain_form_.url = GURL("https://subdomain.example.com/path");
+ subdomain_form_.signon_realm = subdomain_form_.url.GetOrigin().spec();
subdomain_form_.scheme = autofill::PasswordForm::Scheme::kHtml;
subdomain_form_.skip_zero_click = false;
cross_origin_form_.username_value = base::ASCIIToUTF16("Username");
cross_origin_form_.display_name = base::ASCIIToUTF16("Display Name");
cross_origin_form_.password_value = base::ASCIIToUTF16("Password");
- cross_origin_form_.origin = GURL("https://example.net/");
- cross_origin_form_.signon_realm =
- cross_origin_form_.origin.GetOrigin().spec();
+ cross_origin_form_.url = GURL("https://example.net/");
+ cross_origin_form_.signon_realm = cross_origin_form_.url.GetOrigin().spec();
cross_origin_form_.scheme = autofill::PasswordForm::Scheme::kHtml;
cross_origin_form_.skip_zero_click = false;
@@ -262,6 +278,9 @@ class CredentialManagerImplTest : public testing::Test {
void TearDown() override {
cm_service_impl_.reset();
+ if (account_store_) {
+ account_store_->ShutdownOnUIThread();
+ }
store_->ShutdownOnUIThread();
// It's needed to cleanup the password store asynchronously.
@@ -357,6 +376,7 @@ class CredentialManagerImplTest : public testing::Test {
autofill::PasswordForm subdomain_form_;
autofill::PasswordForm cross_origin_form_;
scoped_refptr<TestPasswordStore> store_;
+ scoped_refptr<TestPasswordStore> account_store_;
std::unique_ptr<testing::NiceMock<MockPasswordManagerClient>> client_;
std::unique_ptr<CredentialManagerImpl> cm_service_impl_;
};
@@ -400,7 +420,7 @@ TEST_F(CredentialManagerImplTest, CredentialManagerOnStore) {
EXPECT_EQ(form_.username_value, new_form.username_value);
EXPECT_EQ(form_.display_name, new_form.display_name);
EXPECT_EQ(form_.password_value, new_form.password_value);
- EXPECT_EQ(form_.origin, new_form.origin);
+ EXPECT_EQ(form_.url, new_form.url);
EXPECT_EQ(form_.signon_realm, new_form.signon_realm);
EXPECT_TRUE(new_form.federation_origin.opaque());
EXPECT_EQ(form_.icon_url, new_form.icon_url);
@@ -431,7 +451,7 @@ TEST_F(CredentialManagerImplTest, CredentialManagerOnStoreFederated) {
EXPECT_EQ(form_.username_value, new_form.username_value);
EXPECT_EQ(form_.display_name, new_form.display_name);
EXPECT_EQ(form_.password_value, new_form.password_value);
- EXPECT_EQ(form_.origin, new_form.origin);
+ EXPECT_EQ(form_.url, new_form.url);
EXPECT_EQ(form_.signon_realm, new_form.signon_realm);
EXPECT_EQ(form_.federation_origin, new_form.federation_origin);
EXPECT_EQ(form_.icon_url, new_form.icon_url);
@@ -658,7 +678,7 @@ TEST_F(CredentialManagerImplTest, CredentialManagerGetOverwriteZeroClick) {
form_.skip_zero_click = true;
form_.username_element = base::ASCIIToUTF16("username-element");
form_.password_element = base::ASCIIToUTF16("password-element");
- form_.origin = GURL("https://example.com/old_form.html");
+ form_.url = GURL("https://example.com/old_form.html");
store_->AddLogin(form_);
RunAllPendingTasks();
@@ -686,7 +706,7 @@ TEST_F(CredentialManagerImplTest, CredentialManagerGetOverwriteZeroClick) {
TEST_F(CredentialManagerImplTest,
CredentialManagerSignInWithSavingDisabledForCurrentPage) {
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
- EXPECT_CALL(*client_, IsSavingAndFillingEnabled(form_.origin))
+ EXPECT_CALL(*client_, IsSavingAndFillingEnabled(form_.url))
.WillRepeatedly(testing::Return(false));
EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(0));
@@ -917,7 +937,7 @@ TEST_F(CredentialManagerImplTest,
federated.federation_origin =
url::Origin::Create(GURL("https://google.com/"));
federated.signon_realm =
- "federation://" + federated.origin.host() + "/google.com";
+ "federation://" + federated.url.host() + "/google.com";
store_->AddLogin(federated);
EXPECT_CALL(*client_,
@@ -932,7 +952,7 @@ TEST_F(CredentialManagerImplTest,
CredentialManagerError error;
base::Optional<CredentialInfo> credential;
std::vector<GURL> federations;
- federations.push_back(GURL("https://google.com/"));
+ federations.emplace_back("https://google.com/");
CallGet(CredentialMediationRequirement::kOptional, true, federations,
base::BindOnce(&GetCredentialCallback, &called, &error, &credential));
@@ -1022,7 +1042,7 @@ TEST_F(CredentialManagerImplTest,
client_->set_first_run_seen(true);
std::vector<GURL> federations;
- federations.push_back(GURL("https://example.com/"));
+ federations.emplace_back("https://example.com/");
EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(_)).Times(0);
@@ -1039,7 +1059,7 @@ TEST_F(CredentialManagerImplTest,
client_->set_first_run_seen(true);
std::vector<GURL> federations;
- federations.push_back(GURL("https://not-example.com/"));
+ federations.emplace_back("https://not-example.com/");
EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(_)).Times(0);
@@ -1099,7 +1119,7 @@ TEST_F(CredentialManagerImplTest,
std::make_unique<MockAffiliatedMatchHelper>());
std::vector<GURL> federations;
- federations.push_back(GURL("https://example.com/"));
+ federations.emplace_back("https://example.com/");
std::vector<std::string> affiliated_realms;
affiliated_realms.push_back(kTestAndroidRealm1);
@@ -1123,7 +1143,7 @@ TEST_F(CredentialManagerImplTest,
std::make_unique<MockAffiliatedMatchHelper>());
std::vector<GURL> federations;
- federations.push_back(GURL("https://not-example.com/"));
+ federations.emplace_back("https://not-example.com/");
std::vector<std::string> affiliated_realms;
affiliated_realms.push_back(kTestAndroidRealm1);
@@ -1332,6 +1352,21 @@ TEST_F(CredentialManagerImplTest, IncognitoZeroClickRequestCredential) {
federations, CredentialType::CREDENTIAL_TYPE_EMPTY);
}
+TEST_F(CredentialManagerImplTest, AutofillAssistantZeroClickRequestCredential) {
+ store_->AddLogin(form_);
+
+ std::vector<GURL> federations;
+ EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr)
+ .Times(testing::Exactly(0));
+ EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+ EXPECT_CALL(*client_, IsIncognito()).WillRepeatedly(testing::Return(false));
+ EXPECT_CALL(*client_, GetAutofillAssistantMode())
+ .WillRepeatedly(testing::Return(AutofillAssistantMode::kRunning));
+
+ ExpectCredentialType(CredentialMediationRequirement::kOptional, true,
+ federations, CredentialType::CREDENTIAL_TYPE_EMPTY);
+}
+
TEST_F(CredentialManagerImplTest, ZeroClickWithAffiliatedFormInPasswordStore) {
// Insert the affiliated form into the store, and mock out the association
// with the current origin. As it's the only form matching the origin, it
@@ -1392,8 +1427,8 @@ TEST_F(CredentialManagerImplTest,
static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
->ExpectCallToGetAffiliatedAndroidRealms(digest, affiliated_realms);
- digest.origin = HttpURLFromHttps(digest.origin);
- digest.signon_realm = digest.origin.spec();
+ digest.url = HttpURLFromHttps(digest.url);
+ digest.signon_realm = digest.url.spec();
// The second call happens for HTTP as the migration is triggered.
static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
->ExpectCallToGetAffiliatedAndroidRealms(digest, affiliated_realms);
@@ -1436,7 +1471,7 @@ TEST_F(CredentialManagerImplTest, ZeroClickWithPSLCredential) {
TEST_F(CredentialManagerImplTest, ZeroClickWithPSLAndNormalCredentials) {
form_.password_value.clear();
form_.federation_origin = url::Origin::Create(GURL("https://google.com/"));
- form_.signon_realm = "federation://" + form_.origin.host() + "/google.com";
+ form_.signon_realm = "federation://" + form_.url.host() + "/google.com";
form_.skip_zero_click = false;
store_->AddLogin(form_);
store_->AddLogin(subdomain_form_);
@@ -1450,8 +1485,8 @@ TEST_F(CredentialManagerImplTest, ZeroClickWithPSLAndNormalCredentials) {
TEST_F(CredentialManagerImplTest, ZeroClickAfterMigratingHttpCredential) {
// There is an http credential saved. It should be migrated and used for auto
// sign-in.
- form_.origin = HttpURLFromHttps(form_.origin);
- form_.signon_realm = form_.origin.GetOrigin().spec();
+ form_.url = HttpURLFromHttps(form_.url);
+ form_.signon_realm = form_.url.GetOrigin().spec();
// That is the default value for old credentials.
form_.skip_zero_click = true;
store_->AddLogin(form_);
@@ -1496,7 +1531,7 @@ TEST_F(CredentialManagerImplTest, MediationRequiredPreventsAutoSignIn) {
TEST_F(CredentialManagerImplTest, GetSynthesizedFormForOrigin) {
PasswordStore::FormDigest synthesized =
cm_service_impl_->GetSynthesizedFormForOrigin();
- EXPECT_EQ(kTestWebOrigin, synthesized.origin.spec());
+ EXPECT_EQ(kTestWebOrigin, synthesized.url.spec());
EXPECT_EQ(kTestWebOrigin, synthesized.signon_realm);
EXPECT_EQ(autofill::PasswordForm::Scheme::kHtml, synthesized.scheme);
}
@@ -1504,8 +1539,8 @@ TEST_F(CredentialManagerImplTest, GetSynthesizedFormForOrigin) {
TEST_F(CredentialManagerImplTest, GetBlacklistedPasswordCredential) {
autofill::PasswordForm blacklisted;
blacklisted.blacklisted_by_user = true;
- blacklisted.origin = form_.origin;
- blacklisted.signon_realm = blacklisted.origin.spec();
+ blacklisted.url = form_.url;
+ blacklisted.signon_realm = blacklisted.url.spec();
// Deliberately use a wrong format with a non-empty username to simulate a
// leak. See https://crbug.com/817754.
blacklisted.username_value = base::ASCIIToUTF16("Username");
@@ -1537,7 +1572,7 @@ TEST_F(CredentialManagerImplTest, BlacklistPasswordCredential) {
autofill::PasswordForm blacklisted;
TestPasswordStore::PasswordMap passwords = store_->stored_passwords();
blacklisted.blacklisted_by_user = true;
- blacklisted.origin = form_.origin;
+ blacklisted.url = form_.url;
blacklisted.signon_realm = form_.signon_realm;
blacklisted.date_created = passwords[form_.signon_realm][0].date_created;
EXPECT_THAT(passwords[form_.signon_realm],
@@ -1563,11 +1598,11 @@ TEST_F(CredentialManagerImplTest, BlacklistFederatedCredential) {
// Verify that the site is blacklisted.
TestPasswordStore::PasswordMap passwords = store_->stored_passwords();
- ASSERT_TRUE(passwords.count(form_.origin.spec()));
+ ASSERT_TRUE(passwords.count(form_.url.spec()));
autofill::PasswordForm blacklisted;
blacklisted.blacklisted_by_user = true;
- blacklisted.origin = form_.origin;
- blacklisted.signon_realm = blacklisted.origin.spec();
+ blacklisted.url = form_.url;
+ blacklisted.signon_realm = blacklisted.url.spec();
blacklisted.date_created =
passwords[blacklisted.signon_realm][0].date_created;
EXPECT_THAT(passwords[blacklisted.signon_realm],
@@ -1577,8 +1612,8 @@ TEST_F(CredentialManagerImplTest, BlacklistFederatedCredential) {
TEST_F(CredentialManagerImplTest, RespectBlacklistingPasswordCredential) {
autofill::PasswordForm blacklisted;
blacklisted.blacklisted_by_user = true;
- blacklisted.origin = form_.origin;
- blacklisted.signon_realm = blacklisted.origin.spec();
+ blacklisted.url = form_.url;
+ blacklisted.signon_realm = blacklisted.url.spec();
store_->AddLogin(blacklisted);
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
@@ -1595,8 +1630,8 @@ TEST_F(CredentialManagerImplTest, RespectBlacklistingPasswordCredential) {
TEST_F(CredentialManagerImplTest, RespectBlacklistingFederatedCredential) {
autofill::PasswordForm blacklisted;
blacklisted.blacklisted_by_user = true;
- blacklisted.origin = form_.origin;
- blacklisted.signon_realm = blacklisted.origin.spec();
+ blacklisted.url = form_.url;
+ blacklisted.signon_realm = blacklisted.url.spec();
store_->AddLogin(blacklisted);
form_.federation_origin = url::Origin::Create(GURL("https://example.com/"));
@@ -1619,7 +1654,7 @@ TEST_F(CredentialManagerImplTest,
federated.federation_origin =
url::Origin::Create(GURL("https://google.com/"));
federated.signon_realm =
- "federation://" + federated.origin.host() + "/google.com";
+ "federation://" + federated.url.host() + "/google.com";
store_->AddLogin(federated);
form_.username_value = base::ASCIIToUTF16("username_value");
@@ -1635,7 +1670,7 @@ TEST_F(CredentialManagerImplTest,
CredentialManagerError error;
base::Optional<CredentialInfo> credential;
std::vector<GURL> federations;
- federations.push_back(GURL("https://google.com/"));
+ federations.emplace_back("https://google.com/");
CallGet(CredentialMediationRequirement::kSilent, true, federations,
base::BindOnce(&GetCredentialCallback, &called, &error, &credential));
@@ -1671,7 +1706,7 @@ TEST_F(CredentialManagerImplTest, StorePasswordCredentialStartsLeakDetection) {
auto check_instance = std::make_unique<MockLeakDetectionCheck>();
EXPECT_CALL(*check_instance,
- Start(form_.origin, form_.username_value, form_.password_value));
+ Start(form_.url, form_.username_value, form_.password_value));
EXPECT_CALL(*weak_factory, TryCreateLeakCheck)
.WillOnce(testing::Return(testing::ByMove(std::move(check_instance))));
CallStore({form_, CredentialType::CREDENTIAL_TYPE_PASSWORD},
diff --git a/chromium/components/password_manager/core/browser/credential_manager_logger.cc b/chromium/components/password_manager/core/browser/credential_manager_logger.cc
index cc7373ced5b..22c27ecfa76 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_logger.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_logger.cc
@@ -21,11 +21,10 @@ CredentialManagerLogger::CredentialManagerLogger(
CredentialManagerLogger::~CredentialManagerLogger() = default;
void CredentialManagerLogger::LogRequestCredential(
- const GURL& url,
+ const url::Origin& origin,
CredentialMediationRequirement mediation,
const std::vector<GURL>& federations) {
- std::string s("CM API get credentials: origin=" +
- SavePasswordProgressLogger::ScrubURL(url));
+ std::string s("CM API get credentials: origin=" + origin.Serialize());
s += ", mediation=";
switch (mediation) {
case CredentialMediationRequirement::kSilent:
@@ -45,25 +44,23 @@ void CredentialManagerLogger::LogRequestCredential(
log_manager_->LogTextMessage(s);
}
-void CredentialManagerLogger::LogSendCredential(const GURL& url,
+void CredentialManagerLogger::LogSendCredential(const url::Origin& origin,
CredentialType type) {
- std::string s("CM API send a credential: origin=" +
- SavePasswordProgressLogger::ScrubURL(url));
+ std::string s("CM API send a credential: origin=" + origin.Serialize());
s += ", CredentialType=" + CredentialTypeToString(type);
log_manager_->LogTextMessage(s);
}
-void CredentialManagerLogger::LogStoreCredential(const GURL& url,
+void CredentialManagerLogger::LogStoreCredential(const url::Origin& origin,
CredentialType type) {
- std::string s("CM API save a credential: origin=" +
- SavePasswordProgressLogger::ScrubURL(url));
+ std::string s("CM API save a credential: origin=" + origin.Serialize());
s += ", CredentialType=" + CredentialTypeToString(type);
log_manager_->LogTextMessage(s);
}
-void CredentialManagerLogger::LogPreventSilentAccess(const GURL& url) {
- std::string s("CM API sign out: origin=" +
- SavePasswordProgressLogger::ScrubURL(url));
+void CredentialManagerLogger::LogPreventSilentAccess(
+ const url::Origin& origin) {
+ std::string s("CM API sign out: origin=" + origin.Serialize());
log_manager_->LogTextMessage(s);
}
diff --git a/chromium/components/password_manager/core/browser/credential_manager_logger.h b/chromium/components/password_manager/core/browser/credential_manager_logger.h
index 7febf4d1b63..5674ba48b48 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_logger.h
+++ b/chromium/components/password_manager/core/browser/credential_manager_logger.h
@@ -24,12 +24,12 @@ class CredentialManagerLogger {
explicit CredentialManagerLogger(const autofill::LogManager*);
~CredentialManagerLogger();
- void LogRequestCredential(const GURL& url,
+ void LogRequestCredential(const url::Origin& url,
CredentialMediationRequirement mediation,
const std::vector<GURL>& federations);
- void LogSendCredential(const GURL& url, CredentialType type);
- void LogStoreCredential(const GURL& url, CredentialType type);
- void LogPreventSilentAccess(const GURL& url);
+ void LogSendCredential(const url::Origin& origin, CredentialType type);
+ void LogStoreCredential(const url::Origin& origin, CredentialType type);
+ void LogPreventSilentAccess(const url::Origin& origin);
private:
// The LogManager to which logs can be sent for display.
diff --git a/chromium/components/password_manager/core/browser/credential_manager_logger_unittest.cc b/chromium/components/password_manager/core/browser/credential_manager_logger_unittest.cc
index 1a3f07a13ac..1aac5762195 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_logger_unittest.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_logger_unittest.cc
@@ -15,8 +15,8 @@ using ::testing::AllOf;
using ::testing::HasSubstr;
using ::testing::Return;
-const char kSiteOrigin[] = "https://example.com";
-const char kFederationOrigin[] = "https://google.com";
+constexpr char kSiteOrigin[] = "https://example.com";
+constexpr char kFederationOrigin[] = "https://google.com";
class MockLogManager : public autofill::StubLogManager {
public:
@@ -53,26 +53,26 @@ TEST_F(CredentialManagerLoggerTest, LogRequestCredential) {
EXPECT_CALL(log_manager(),
LogTextMessage(
AllOf(HasSubstr(kSiteOrigin), HasSubstr(kFederationOrigin))));
- logger().LogRequestCredential(GURL(kSiteOrigin),
+ logger().LogRequestCredential(url::Origin::Create(GURL(kSiteOrigin)),
CredentialMediationRequirement::kSilent,
{GURL(kFederationOrigin)});
}
TEST_F(CredentialManagerLoggerTest, LogSendCredential) {
EXPECT_CALL(log_manager(), LogTextMessage(HasSubstr(kSiteOrigin)));
- logger().LogSendCredential(GURL(kSiteOrigin),
+ logger().LogSendCredential(url::Origin::Create(GURL(kSiteOrigin)),
CredentialType::CREDENTIAL_TYPE_PASSWORD);
}
TEST_F(CredentialManagerLoggerTest, LogStoreCredential) {
EXPECT_CALL(log_manager(), LogTextMessage(HasSubstr(kSiteOrigin)));
- logger().LogStoreCredential(GURL(kSiteOrigin),
+ logger().LogStoreCredential(url::Origin::Create(GURL(kSiteOrigin)),
CredentialType::CREDENTIAL_TYPE_PASSWORD);
}
TEST_F(CredentialManagerLoggerTest, LogPreventSilentAccess) {
EXPECT_CALL(log_manager(), LogTextMessage(HasSubstr(kSiteOrigin)));
- logger().LogPreventSilentAccess(GURL(kSiteOrigin));
+ logger().LogPreventSilentAccess(url::Origin::Create(GURL(kSiteOrigin)));
}
} // namespace
diff --git a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc
index fb2c2003cfb..4bac5880558 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc
@@ -56,7 +56,7 @@ class MockFormSaver : public StubFormSaver {
};
MATCHER_P(FormMatches, form, "") {
- return form.signon_realm == arg.signon_realm && form.origin == arg.origin &&
+ return form.signon_realm == arg.signon_realm && form.url == arg.url &&
form.username_value == arg.username_value &&
form.password_value == arg.password_value &&
form.scheme == arg.scheme && form.type == arg.type;
@@ -67,7 +67,7 @@ MATCHER_P(FormMatches, form, "") {
class CredentialManagerPasswordFormManagerTest : public testing::Test {
public:
CredentialManagerPasswordFormManagerTest() {
- form_to_save_.origin = GURL("https://example.com/path");
+ form_to_save_.url = GURL("https://example.com/path");
form_to_save_.signon_realm = "https://example.com/";
form_to_save_.username_value = ASCIIToUTF16("user1");
form_to_save_.password_value = ASCIIToUTF16("pass1");
@@ -147,7 +147,7 @@ TEST_F(CredentialManagerPasswordFormManagerTest,
{&saved_match});
EXPECT_TRUE(form_manager->IsNewLogin());
EXPECT_TRUE(form_manager->is_submitted());
- EXPECT_EQ(form_to_save_.origin, form_manager->GetOrigin());
+ EXPECT_EQ(form_to_save_.url, form_manager->GetURL());
EXPECT_CALL(form_saver, Save(FormMatches(form_to_save_), _, _));
form_manager->Save();
diff --git a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index 7cf4bb3f5c9..e6e91ca69e8 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -105,7 +105,7 @@ CredentialManagerPendingRequestTask::~CredentialManagerPendingRequestTask() =
void CredentialManagerPendingRequestTask::OnGetPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
// localhost is a secure origin but not https.
- if (results.empty() && origin_.SchemeIs(url::kHttpsScheme)) {
+ if (results.empty() && origin_.scheme() == url::kHttpsScheme) {
// Try to migrate the HTTP passwords and process them later.
http_migrator_ = std::make_unique<HttpPasswordStoreMigrator>(
origin_, delegate_->client(), this);
@@ -150,7 +150,7 @@ void CredentialManagerPendingRequestTask::ProcessForms(
// GURL definition: scheme, host, and port.
// So we can't compare them directly.
if (form->is_affiliation_based_match ||
- form->origin.GetOrigin() == origin_.GetOrigin()) {
+ url::Origin::Create(form->url) == origin_) {
local_results.push_back(std::move(form));
} else if (form->is_public_suffix_match) {
psl_results.push_back(std::move(form));
diff --git a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h
index 787cadcd7c8..bb1d05c4c88 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h
+++ b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h
@@ -17,6 +17,7 @@
#include "components/password_manager/core/browser/password_store_consumer.h"
#include "components/password_manager/core/common/credential_manager_types.h"
#include "url/gurl.h"
+#include "url/origin.h"
namespace autofill {
struct PasswordForm;
@@ -38,7 +39,7 @@ class CredentialManagerPendingRequestTaskDelegate {
virtual bool IsZeroClickAllowed() const = 0;
// Retrieves the current page origin.
- virtual GURL GetOrigin() const = 0;
+ virtual url::Origin GetOrigin() const = 0;
// Returns the PasswordManagerClient.
virtual PasswordManagerClient* client() const = 0;
@@ -67,7 +68,7 @@ class CredentialManagerPendingRequestTask
const std::vector<GURL>& request_federations);
~CredentialManagerPendingRequestTask() override;
- const GURL& origin() const { return origin_; }
+ const url::Origin& origin() const { return origin_; }
// PasswordStoreConsumer:
void OnGetPasswordStoreResults(
@@ -84,7 +85,7 @@ class CredentialManagerPendingRequestTask
CredentialManagerPendingRequestTaskDelegate* delegate_; // Weak;
SendCredentialCallback send_callback_;
const CredentialMediationRequirement mediation_;
- const GURL origin_;
+ const url::Origin origin_;
const bool include_passwords_;
std::set<std::string> federations_;
diff --git a/chromium/components/password_manager/core/browser/export/OWNERS b/chromium/components/password_manager/core/browser/export/OWNERS
new file mode 100644
index 00000000000..1d447d61f5c
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/export/OWNERS
@@ -0,0 +1,4 @@
+cfroussios@chromium.org
+
+# COMPONENT: UI>Browser>Passwords
+# TEAM: chromium-dev@chromium.org
diff --git a/chromium/components/password_manager/core/browser/export/csv_writer_unittest.cc b/chromium/components/password_manager/core/browser/export/csv_writer_unittest.cc
index eb89d5a3c6d..c53ba9d6f06 100644
--- a/chromium/components/password_manager/core/browser/export/csv_writer_unittest.cc
+++ b/chromium/components/password_manager/core/browser/export/csv_writer_unittest.cc
@@ -18,7 +18,7 @@ namespace password_manager {
class CSVWriterTest : public testing::Test {
public:
- CSVWriterTest() {}
+ CSVWriterTest() = default;
void SetUp() override {
column_names_.push_back("foo");
diff --git a/chromium/components/password_manager/core/browser/export/password_csv_writer.cc b/chromium/components/password_manager/core/browser/export/password_csv_writer.cc
index 7d05e3e735c..5d893456bab 100644
--- a/chromium/components/password_manager/core/browser/export/password_csv_writer.cc
+++ b/chromium/components/password_manager/core/browser/export/password_csv_writer.cc
@@ -44,10 +44,10 @@ std::string PasswordCSVWriter::SerializePasswords(
std::map<std::string, std::string> PasswordCSVWriter::PasswordFormToRecord(
const PasswordForm& form) {
std::map<std::string, std::string> record;
- record[kUrlColumnName] = form.origin.spec();
+ record[kUrlColumnName] = form.url.spec();
record[kUsernameColumnName] = base::UTF16ToUTF8(form.username_value);
record[kPasswordColumnName] = base::UTF16ToUTF8(form.password_value);
- record[kTitleColumnName] = form.origin.host();
+ record[kTitleColumnName] = form.url.host();
return record;
}
diff --git a/chromium/components/password_manager/core/browser/export/password_csv_writer_unittest.cc b/chromium/components/password_manager/core/browser/export/password_csv_writer_unittest.cc
index e431f68f5e0..2b8d665b1a7 100644
--- a/chromium/components/password_manager/core/browser/export/password_csv_writer_unittest.cc
+++ b/chromium/components/password_manager/core/browser/export/password_csv_writer_unittest.cc
@@ -23,7 +23,7 @@ namespace password_manager {
namespace {
MATCHER_P3(FormHasOriginUsernamePassword, origin, username, password, "") {
- return arg.signon_realm == origin && arg.origin == GURL(origin) &&
+ return arg.signon_realm == origin && arg.url == GURL(origin) &&
arg.username_value == base::UTF8ToUTF16(username) &&
arg.password_value == base::UTF8ToUTF16(password);
}
@@ -42,7 +42,7 @@ TEST(PasswordCSVWriterTest, SerializePasswords_ZeroPasswords) {
TEST(PasswordCSVWriterTest, SerializePasswords_SinglePassword) {
std::vector<std::unique_ptr<PasswordForm>> passwords;
PasswordForm form;
- form.origin = GURL("http://example.com");
+ form.url = GURL("http://example.com");
form.username_value = base::UTF8ToUTF16("Someone");
form.password_value = base::UTF8ToUTF16("Secret");
passwords.push_back(std::make_unique<PasswordForm>(form));
@@ -61,11 +61,11 @@ TEST(PasswordCSVWriterTest, SerializePasswords_SinglePassword) {
TEST(PasswordCSVWriterTest, SerializePasswords_TwoPasswords) {
std::vector<std::unique_ptr<PasswordForm>> passwords;
PasswordForm form;
- form.origin = GURL("http://example.com");
+ form.url = GURL("http://example.com");
form.username_value = base::UTF8ToUTF16("Someone");
form.password_value = base::UTF8ToUTF16("Secret");
passwords.push_back(std::make_unique<PasswordForm>(form));
- form.origin = GURL("http://other.org");
+ form.url = GURL("http://other.org");
form.username_value = base::UTF8ToUTF16("Anyone");
form.password_value = base::UTF8ToUTF16("None");
passwords.push_back(std::make_unique<PasswordForm>(form));
diff --git a/chromium/components/password_manager/core/browser/export/password_manager_exporter.cc b/chromium/components/password_manager/core/browser/export/password_manager_exporter.cc
index 1505306fefa..9ef9a0a42d7 100644
--- a/chromium/components/password_manager/core/browser/export/password_manager_exporter.cc
+++ b/chromium/components/password_manager/core/browser/export/password_manager_exporter.cc
@@ -51,6 +51,10 @@ bool DefaultWriteFunction(const base::FilePath& file, base::StringPiece data) {
return base::WriteFile(file, data);
}
+bool DefaultDeleteFunction(const base::FilePath& file) {
+ return base::DeleteFile(file, /*recursive=*/false);
+}
+
} // namespace
namespace password_manager {
@@ -63,7 +67,7 @@ PasswordManagerExporter::PasswordManagerExporter(
on_progress_(std::move(on_progress)),
last_progress_status_(ExportProgressStatus::NOT_STARTED),
write_function_(base::BindRepeating(&DefaultWriteFunction)),
- delete_function_(base::BindRepeating(&base::DeleteFile)),
+ delete_function_(base::BindRepeating(&DefaultDeleteFunction)),
#if defined(OS_POSIX)
set_permissions_function_(
base::BindRepeating(base::SetPosixFilePermissions)),
@@ -74,7 +78,7 @@ PasswordManagerExporter::PasswordManagerExporter(
task_runner_(g_task_runner.Get()) {
}
-PasswordManagerExporter::~PasswordManagerExporter() {}
+PasswordManagerExporter::~PasswordManagerExporter() = default;
void PasswordManagerExporter::PreparePasswordsForExport() {
DCHECK_EQ(GetProgressStatus(), ExportProgressStatus::NOT_STARTED);
@@ -191,9 +195,9 @@ void PasswordManagerExporter::Cleanup() {
// TODO(crbug.com/811779) When Chrome is overwriting an existing file, cancel
// should restore the file rather than delete it.
if (!destination_.empty()) {
- task_runner_->PostTask(FROM_HERE,
- base::BindOnce(base::IgnoreResult(delete_function_),
- destination_, false));
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(base::IgnoreResult(delete_function_), destination_));
}
}
diff --git a/chromium/components/password_manager/core/browser/export/password_manager_exporter.h b/chromium/components/password_manager/core/browser/export/password_manager_exporter.h
index fe6c4d5c0a3..1c353b6a5dc 100644
--- a/chromium/components/password_manager/core/browser/export/password_manager_exporter.h
+++ b/chromium/components/password_manager/core/browser/export/password_manager_exporter.h
@@ -32,8 +32,7 @@ class PasswordManagerExporter {
const std::string&)>;
using WriteCallback =
base::RepeatingCallback<bool(const base::FilePath&, base::StringPiece)>;
- using DeleteCallback =
- base::RepeatingCallback<bool(const base::FilePath&, bool)>;
+ using DeleteCallback = base::RepeatingCallback<bool(const base::FilePath&)>;
using SetPosixFilePermissionsCallback =
base::RepeatingCallback<bool(const base::FilePath&, int)>;
diff --git a/chromium/components/password_manager/core/browser/export/password_manager_exporter_unittest.cc b/chromium/components/password_manager/core/browser/export/password_manager_exporter_unittest.cc
index d72097d3c2b..2772efc471a 100644
--- a/chromium/components/password_manager/core/browser/export/password_manager_exporter_unittest.cc
+++ b/chromium/components/password_manager/core/browser/export/password_manager_exporter_unittest.cc
@@ -53,7 +53,7 @@ const base::FilePath::CharType kNullFileName[] = FILE_PATH_LITERAL("/dev/null");
class FakeCredentialProvider
: public password_manager::CredentialProviderInterface {
public:
- FakeCredentialProvider() {}
+ FakeCredentialProvider() = default;
void SetPasswordList(
const std::vector<std::unique_ptr<autofill::PasswordForm>>&
@@ -83,7 +83,7 @@ class FakeCredentialProvider
// Creates a hardcoded set of credentials for tests.
std::vector<std::unique_ptr<autofill::PasswordForm>> CreatePasswordList() {
auto password_form = std::make_unique<autofill::PasswordForm>();
- password_form->origin = GURL("http://accounts.google.com/a/LoginAuth");
+ password_form->url = GURL("http://accounts.google.com/a/LoginAuth");
password_form->username_value = base::ASCIIToUTF16("test@gmail.com");
password_form->password_value = base::ASCIIToUTF16("test1");
@@ -153,7 +153,7 @@ TEST_F(PasswordManagerExporterTest, WriteFileFailed) {
destination_path_.DirName().BaseName().AsUTF8Unsafe());
EXPECT_CALL(mock_write_file_, Run(_, _)).WillOnce(Return(false));
- EXPECT_CALL(mock_delete_file_, Run(destination_path_, false));
+ EXPECT_CALL(mock_delete_file_, Run(destination_path_));
EXPECT_CALL(
mock_on_progress_,
Run(password_manager::ExportProgressStatus::IN_PROGRESS, IsEmpty()));
@@ -216,7 +216,7 @@ TEST_F(PasswordManagerExporterTest, CancelAfterPasswords) {
TEST_F(PasswordManagerExporterTest, CancelWhileExporting) {
EXPECT_CALL(mock_write_file_, Run(_, _)).Times(0);
- EXPECT_CALL(mock_delete_file_, Run(destination_path_, false));
+ EXPECT_CALL(mock_delete_file_, Run(destination_path_));
EXPECT_CALL(
mock_on_progress_,
Run(password_manager::ExportProgressStatus::IN_PROGRESS, IsEmpty()));
@@ -235,7 +235,7 @@ TEST_F(PasswordManagerExporterTest, CancelWhileExporting) {
// exporting. If they choose to cancel, we should clear the file.
TEST_F(PasswordManagerExporterTest, CancelAfterExporting) {
EXPECT_CALL(mock_write_file_, Run(_, _)).WillOnce(Return(true));
- EXPECT_CALL(mock_delete_file_, Run(destination_path_, false));
+ EXPECT_CALL(mock_delete_file_, Run(destination_path_));
EXPECT_CALL(
mock_on_progress_,
Run(password_manager::ExportProgressStatus::IN_PROGRESS, IsEmpty()));
diff --git a/chromium/components/password_manager/core/browser/form_fetcher_impl.cc b/chromium/components/password_manager/core/browser/form_fetcher_impl.cc
index 6fd1ff1aeb8..bffda9be769 100644
--- a/chromium/components/password_manager/core/browser/form_fetcher_impl.cc
+++ b/chromium/components/password_manager/core/browser/form_fetcher_impl.cc
@@ -92,8 +92,8 @@ void FormFetcherImpl::RemoveConsumer(FormFetcher::Consumer* consumer) {
void FormFetcherImpl::Fetch() {
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+ logger = std::make_unique<BrowserSavePasswordProgressLogger>(
+ client_->GetLogManager());
logger->LogMessage(Logger::STRING_FETCH_METHOD);
logger->LogNumber(Logger::STRING_FORM_FETCHER_STATE,
static_cast<int>(state_));
@@ -120,7 +120,7 @@ void FormFetcherImpl::Fetch() {
// processor cycles.
#if !defined(OS_IOS) && !defined(OS_ANDROID)
// The statistics is needed for the "Save password?" bubble.
- password_store->GetSiteStats(form_digest_.origin.GetOrigin(), this);
+ password_store->GetSiteStats(form_digest_.url.GetOrigin(), this);
// The desktop bubble needs this information.
password_store->GetMatchingCompromisedCredentials(form_digest_.signon_realm,
@@ -249,16 +249,16 @@ void FormFetcherImpl::OnGetPasswordStoreResults(
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+ logger = std::make_unique<BrowserSavePasswordProgressLogger>(
+ client_->GetLogManager());
logger->LogMessage(Logger::STRING_ON_GET_STORE_RESULTS_METHOD);
logger->LogNumber(Logger::STRING_NUMBER_RESULTS, results.size());
}
if (should_migrate_http_passwords_ && results.empty() &&
- form_digest_.origin.SchemeIs(url::kHttpsScheme)) {
+ form_digest_.url.SchemeIs(url::kHttpsScheme)) {
http_migrator_ = std::make_unique<HttpPasswordStoreMigrator>(
- form_digest_.origin, client_, this);
+ url::Origin::Create(form_digest_.url), client_, this);
return;
}
diff --git a/chromium/components/password_manager/core/browser/form_fetcher_impl.h b/chromium/components/password_manager/core/browser/form_fetcher_impl.h
index 9ff24e7423a..dd98d6d08ae 100644
--- a/chromium/components/password_manager/core/browser/form_fetcher_impl.h
+++ b/chromium/components/password_manager/core/browser/form_fetcher_impl.h
@@ -98,6 +98,12 @@ class FormFetcherImpl : public FormFetcher,
// non-federated matches.
std::vector<std::unique_ptr<autofill::PasswordForm>> federated_;
+ // Indicates whether HTTP passwords should be migrated to HTTPS.
+ const bool should_migrate_http_passwords_;
+
+ // Does the actual migration.
+ std::unique_ptr<HttpPasswordStoreMigrator> http_migrator_;
+
private:
// PasswordStoreConsumer:
void OnGetPasswordStoreResults(
@@ -139,12 +145,6 @@ class FormFetcherImpl : public FormFetcher,
// remove themselves from the list during their destruction.
base::ObserverList<FormFetcher::Consumer> consumers_;
- // Indicates whether HTTP passwords should be migrated to HTTPS.
- const bool should_migrate_http_passwords_;
-
- // Does the actual migration.
- std::unique_ptr<HttpPasswordStoreMigrator> http_migrator_;
-
DISALLOW_COPY_AND_ASSIGN(FormFetcherImpl);
};
diff --git a/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc b/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
index 9834cea409d..eab4a914be8 100644
--- a/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
@@ -123,7 +123,7 @@ PasswordForm CreateHTMLForm(const char* origin_url,
const char* password_value) {
PasswordForm form;
form.scheme = PasswordForm::Scheme::kHtml;
- form.origin = GURL(origin_url);
+ form.url = GURL(origin_url);
form.signon_realm = origin_url;
form.username_value = ASCIIToUTF16(username_value);
form.password_value = ASCIIToUTF16(password_value);
@@ -257,8 +257,8 @@ TEST_P(FormFetcherImplTest, Empty) {
Fetch();
form_fetcher_->AddConsumer(&consumer_);
EXPECT_CALL(consumer_, OnFetchCompleted);
- store_consumer()->OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<PasswordForm>>());
+ store_consumer()->OnGetPasswordStoreResultsFrom(
+ mock_store_, std::vector<std::unique_ptr<PasswordForm>>());
EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(), IsEmpty());
EXPECT_THAT(form_fetcher_->GetFederatedMatches(), IsEmpty());
@@ -273,7 +273,8 @@ TEST_P(FormFetcherImplTest, NonFederated) {
std::vector<std::unique_ptr<PasswordForm>> results;
results.push_back(std::make_unique<PasswordForm>(non_federated));
EXPECT_CALL(consumer_, OnFetchCompleted);
- store_consumer()->OnGetPasswordStoreResults(std::move(results));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ std::move(results));
EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(),
UnorderedElementsAre(Pointee(non_federated)));
@@ -291,7 +292,8 @@ TEST_P(FormFetcherImplTest, Federated) {
results.push_back(std::make_unique<PasswordForm>(federated));
results.push_back(std::make_unique<PasswordForm>(android_federated));
EXPECT_CALL(consumer_, OnFetchCompleted);
- store_consumer()->OnGetPasswordStoreResults(std::move(results));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ std::move(results));
EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(), IsEmpty());
EXPECT_THAT(
@@ -312,7 +314,8 @@ TEST_P(FormFetcherImplTest, Blacklited) {
results.push_back(std::make_unique<PasswordForm>(blacklisted));
results.push_back(std::make_unique<PasswordForm>(blacklisted_psl));
EXPECT_CALL(consumer_, OnFetchCompleted);
- store_consumer()->OnGetPasswordStoreResults(std::move(results));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ std::move(results));
EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(), IsEmpty());
EXPECT_THAT(form_fetcher_->GetFederatedMatches(), IsEmpty());
@@ -346,7 +349,8 @@ TEST_P(FormFetcherImplTest, Mixed) {
results.push_back(std::make_unique<PasswordForm>(non_federated3));
results.push_back(std::make_unique<PasswordForm>(blacklisted));
EXPECT_CALL(consumer_, OnFetchCompleted);
- store_consumer()->OnGetPasswordStoreResults(std::move(results));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ std::move(results));
EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
EXPECT_THAT(
form_fetcher_->GetNonFederatedMatches(),
@@ -377,7 +381,8 @@ TEST_P(FormFetcherImplTest, Filtered) {
results.push_back(std::make_unique<PasswordForm>(non_federated1));
results.push_back(std::make_unique<PasswordForm>(non_federated2));
EXPECT_CALL(consumer_, OnFetchCompleted);
- store_consumer()->OnGetPasswordStoreResults(std::move(results));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ std::move(results));
EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
// Expect that nothing got filtered out, since CredentialsFilter no longer
// filters things out:
@@ -432,7 +437,8 @@ TEST_P(FormFetcherImplTest, Update_Reentrance) {
// Delivering the first results will trigger the new GetLogins call, because
// of the Fetch() above.
EXPECT_CALL(*mock_store_, GetLogins(form_digest_, form_fetcher_.get()));
- store_consumer()->OnGetPasswordStoreResults(std::move(old_results));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ std::move(old_results));
// Second response from the store should not be ignored.
PasswordForm form_b = CreateNonFederated();
@@ -445,7 +451,8 @@ TEST_P(FormFetcherImplTest, Update_Reentrance) {
std::vector<std::unique_ptr<PasswordForm>> results;
results.push_back(std::make_unique<PasswordForm>(form_b));
results.push_back(std::make_unique<PasswordForm>(form_c));
- store_consumer()->OnGetPasswordStoreResults(std::move(results));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ std::move(results));
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(),
UnorderedElementsAre(Pointee(form_b), Pointee(form_c)));
}
@@ -453,7 +460,7 @@ TEST_P(FormFetcherImplTest, Update_Reentrance) {
#if !defined(OS_IOS) && !defined(OS_ANDROID)
TEST_P(FormFetcherImplTest, FetchStatistics) {
InteractionsStats stats;
- stats.origin_domain = form_digest_.origin.GetOrigin();
+ stats.origin_domain = form_digest_.url.GetOrigin();
stats.username_value = ASCIIToUTF16("some username");
stats.dismissal_count = 5;
std::vector<InteractionsStats> db_stats = {stats};
@@ -500,9 +507,9 @@ TEST_P(FormFetcherImplTest, DontFetchCompromised) {
TEST_P(FormFetcherImplTest, DoNotTryToMigrateHTTPPasswordsOnHTTPSites) {
GURL::Replacements http_rep;
http_rep.SetSchemeStr(url::kHttpScheme);
- const GURL http_origin = form_digest_.origin.ReplaceComponents(http_rep);
+ const GURL http_url = form_digest_.url.ReplaceComponents(http_rep);
form_digest_ = PasswordStore::FormDigest(
- PasswordForm::Scheme::kHtml, http_origin.GetOrigin().spec(), http_origin);
+ PasswordForm::Scheme::kHtml, http_url.GetOrigin().spec(), http_url);
// A new form fetcher is created to be able to set the form digest and
// migration flag.
@@ -519,14 +526,16 @@ TEST_P(FormFetcherImplTest, DoNotTryToMigrateHTTPPasswordsOnHTTPSites) {
EXPECT_CALL(*mock_store_, GetLogins(_, _)).Times(0);
EXPECT_CALL(*mock_store_, AddLogin(_)).Times(0);
EXPECT_CALL(consumer_, OnFetchCompleted);
- store_consumer()->OnGetPasswordStoreResults(MakeResults(empty_forms));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ MakeResults(empty_forms));
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(), IsEmpty());
EXPECT_THAT(form_fetcher_->GetFederatedMatches(), IsEmpty());
EXPECT_FALSE(form_fetcher_->IsBlacklisted());
Fetch();
EXPECT_CALL(consumer_, OnFetchCompleted);
- store_consumer()->OnGetPasswordStoreResults(MakeResults({http_form}));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ MakeResults({http_form}));
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(),
UnorderedElementsAre(Pointee(http_form)));
EXPECT_THAT(form_fetcher_->GetFederatedMatches(), IsEmpty());
@@ -534,8 +543,8 @@ TEST_P(FormFetcherImplTest, DoNotTryToMigrateHTTPPasswordsOnHTTPSites) {
Fetch();
EXPECT_CALL(consumer_, OnFetchCompleted);
- store_consumer()->OnGetPasswordStoreResults(
- MakeResults({http_form, federated_form}));
+ store_consumer()->OnGetPasswordStoreResultsFrom(
+ mock_store_, MakeResults({http_form, federated_form}));
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(),
UnorderedElementsAre(Pointee(http_form)));
EXPECT_THAT(form_fetcher_->GetFederatedMatches(),
@@ -548,10 +557,9 @@ TEST_P(FormFetcherImplTest, DoNotTryToMigrateHTTPPasswordsOnHTTPSites) {
TEST_P(FormFetcherImplTest, TryToMigrateHTTPPasswordsOnHTTPSSites) {
GURL::Replacements https_rep;
https_rep.SetSchemeStr(url::kHttpsScheme);
- const GURL https_origin = form_digest_.origin.ReplaceComponents(https_rep);
- form_digest_ =
- PasswordStore::FormDigest(PasswordForm::Scheme::kHtml,
- https_origin.GetOrigin().spec(), https_origin);
+ const GURL https_url = form_digest_.url.ReplaceComponents(https_rep);
+ form_digest_ = PasswordStore::FormDigest(
+ PasswordForm::Scheme::kHtml, https_url.GetOrigin().spec(), https_url);
// A new form fetcher is created to be able to set the form digest and
// migration flag.
@@ -567,30 +575,31 @@ TEST_P(FormFetcherImplTest, TryToMigrateHTTPPasswordsOnHTTPSSites) {
GURL::Replacements http_rep;
http_rep.SetSchemeStr(url::kHttpScheme);
PasswordForm http_form = https_form;
- http_form.origin = https_form.origin.ReplaceComponents(http_rep);
- http_form.signon_realm = http_form.origin.GetOrigin().spec();
+ http_form.url = https_form.url.ReplaceComponents(http_rep);
+ http_form.signon_realm = http_form.url.GetOrigin().spec();
std::vector<PasswordForm> empty_forms;
// Tests that there is only an attempt to migrate credentials on HTTPS origins
// when no other credentials are available.
- const GURL form_digest_http_origin =
- form_digest_.origin.ReplaceComponents(http_rep);
+ const GURL form_digest_http_url =
+ form_digest_.url.ReplaceComponents(http_rep);
PasswordStore::FormDigest http_form_digest(
- PasswordForm::Scheme::kHtml, form_digest_http_origin.GetOrigin().spec(),
- form_digest_http_origin);
+ PasswordForm::Scheme::kHtml, form_digest_http_url.GetOrigin().spec(),
+ form_digest_http_url);
Fetch();
base::WeakPtr<PasswordStoreConsumer> migrator_ptr;
EXPECT_CALL(*mock_store_, GetLogins(http_form_digest, _))
.WillOnce(WithArg<1>(GetAndAssignWeakPtr(&migrator_ptr)));
- store_consumer()->OnGetPasswordStoreResults(MakeResults(empty_forms));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ MakeResults(empty_forms));
ASSERT_TRUE(migrator_ptr);
// Now perform the actual migration.
EXPECT_CALL(*mock_store_, AddLogin(https_form));
EXPECT_CALL(consumer_, OnFetchCompleted);
static_cast<HttpPasswordStoreMigrator*>(migrator_ptr.get())
- ->OnGetPasswordStoreResults(MakeResults({http_form}));
+ ->OnGetPasswordStoreResultsFrom(mock_store_, MakeResults({http_form}));
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(),
UnorderedElementsAre(Pointee(https_form)));
EXPECT_THAT(form_fetcher_->GetFederatedMatches(), IsEmpty());
@@ -601,7 +610,8 @@ TEST_P(FormFetcherImplTest, TryToMigrateHTTPPasswordsOnHTTPSSites) {
EXPECT_CALL(*mock_store_, GetLogins(_, _)).Times(0);
EXPECT_CALL(*mock_store_, AddLogin(_)).Times(0);
EXPECT_CALL(consumer_, OnFetchCompleted);
- store_consumer()->OnGetPasswordStoreResults(MakeResults({https_form}));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ MakeResults({https_form}));
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(),
UnorderedElementsAre(Pointee(https_form)));
EXPECT_THAT(form_fetcher_->GetFederatedMatches(), IsEmpty());
@@ -610,8 +620,8 @@ TEST_P(FormFetcherImplTest, TryToMigrateHTTPPasswordsOnHTTPSSites) {
const PasswordForm federated_form = CreateFederated();
Fetch();
EXPECT_CALL(consumer_, OnFetchCompleted);
- store_consumer()->OnGetPasswordStoreResults(
- MakeResults({https_form, federated_form}));
+ store_consumer()->OnGetPasswordStoreResultsFrom(
+ mock_store_, MakeResults({https_form, federated_form}));
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(),
UnorderedElementsAre(Pointee(https_form)));
EXPECT_THAT(form_fetcher_->GetFederatedMatches(),
@@ -624,10 +634,9 @@ TEST_P(FormFetcherImplTest, TryToMigrateHTTPPasswordsOnHTTPSSites) {
TEST_P(FormFetcherImplTest, StateIsWaitingDuringMigration) {
GURL::Replacements https_rep;
https_rep.SetSchemeStr(url::kHttpsScheme);
- const GURL https_origin = form_digest_.origin.ReplaceComponents(https_rep);
- form_digest_ =
- PasswordStore::FormDigest(PasswordForm::Scheme::kHtml,
- https_origin.GetOrigin().spec(), https_origin);
+ const GURL https_url = form_digest_.url.ReplaceComponents(https_rep);
+ form_digest_ = PasswordStore::FormDigest(
+ PasswordForm::Scheme::kHtml, https_url.GetOrigin().spec(), https_url);
// A new form fetcher is created to be able to set the form digest and
// migration flag.
@@ -641,18 +650,18 @@ TEST_P(FormFetcherImplTest, StateIsWaitingDuringMigration) {
GURL::Replacements http_rep;
http_rep.SetSchemeStr(url::kHttpScheme);
PasswordForm http_form = https_form;
- http_form.origin = https_form.origin.ReplaceComponents(http_rep);
- http_form.signon_realm = http_form.origin.GetOrigin().spec();
+ http_form.url = https_form.url.ReplaceComponents(http_rep);
+ http_form.signon_realm = http_form.url.GetOrigin().spec();
std::vector<PasswordForm> empty_forms;
// Ensure there is an attempt to migrate credentials on HTTPS origins and
// extract the migrator.
- const GURL form_digest_http_origin =
- form_digest_.origin.ReplaceComponents(http_rep);
+ const GURL form_digest_http_url =
+ form_digest_.url.ReplaceComponents(http_rep);
PasswordStore::FormDigest http_form_digest(
- PasswordForm::Scheme::kHtml, form_digest_http_origin.GetOrigin().spec(),
- form_digest_http_origin);
+ PasswordForm::Scheme::kHtml, form_digest_http_url.GetOrigin().spec(),
+ form_digest_http_url);
Fetch();
// First the FormFetcher is waiting for the initial response from
// PasswordStore.
@@ -660,7 +669,8 @@ TEST_P(FormFetcherImplTest, StateIsWaitingDuringMigration) {
base::WeakPtr<PasswordStoreConsumer> migrator_ptr;
EXPECT_CALL(*mock_store_, GetLogins(http_form_digest, _))
.WillOnce(WithArg<1>(GetAndAssignWeakPtr(&migrator_ptr)));
- store_consumer()->OnGetPasswordStoreResults(MakeResults(empty_forms));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ MakeResults(empty_forms));
ASSERT_TRUE(migrator_ptr);
// While the initial results from PasswordStore arrived to the FormFetcher, it
// should be still waiting for the migrator.
@@ -669,7 +679,7 @@ TEST_P(FormFetcherImplTest, StateIsWaitingDuringMigration) {
// Now perform the actual migration.
EXPECT_CALL(*mock_store_, AddLogin(https_form));
static_cast<HttpPasswordStoreMigrator*>(migrator_ptr.get())
- ->OnGetPasswordStoreResults(MakeResults({http_form}));
+ ->OnGetPasswordStoreResultsFrom(mock_store_, MakeResults({http_form}));
EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
}
@@ -677,8 +687,8 @@ TEST_P(FormFetcherImplTest, StateIsWaitingDuringMigration) {
// instance with empty results.
TEST_P(FormFetcherImplTest, Clone_EmptyResults) {
Fetch();
- store_consumer()->OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<PasswordForm>>());
+ store_consumer()->OnGetPasswordStoreResultsFrom(
+ mock_store_, std::vector<std::unique_ptr<PasswordForm>>());
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(mock_store_.get()));
// Clone() should not cause re-fetching from PasswordStore.
@@ -705,7 +715,8 @@ TEST_P(FormFetcherImplTest, Clone_NonEmptyResults) {
results.push_back(std::make_unique<PasswordForm>(federated));
results.push_back(std::make_unique<PasswordForm>(android_federated));
- store_consumer()->OnGetPasswordStoreResults(std::move(results));
+ store_consumer()->OnGetPasswordStoreResultsFrom(mock_store_,
+ std::move(results));
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(),
UnorderedElementsAre(Pointee(non_federated)));
EXPECT_THAT(
@@ -740,8 +751,8 @@ TEST_P(FormFetcherImplTest, Clone_NonEmptyResults) {
TEST_P(FormFetcherImplTest, Clone_Stats) {
Fetch();
// Pass empty results to make the state NOT_WAITING.
- store_consumer()->OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<PasswordForm>>());
+ store_consumer()->OnGetPasswordStoreResultsFrom(
+ mock_store_, std::vector<std::unique_ptr<PasswordForm>>());
std::vector<InteractionsStats> stats(1);
store_consumer()->OnGetSiteStatistics(std::move(stats));
@@ -752,8 +763,8 @@ TEST_P(FormFetcherImplTest, Clone_Stats) {
TEST_P(FormFetcherImplTest, Clone_Compromised) {
Fetch();
// Pass empty results to make the state NOT_WAITING.
- store_consumer()->OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<PasswordForm>>());
+ store_consumer()->OnGetPasswordStoreResultsFrom(
+ mock_store_, std::vector<std::unique_ptr<PasswordForm>>());
const std::vector<CompromisedCredentials> credentials = {
{form_digest_.signon_realm, base::ASCIIToUTF16("username_value"),
base::Time::FromTimeT(1), CompromiseType::kLeaked}};
@@ -771,8 +782,8 @@ TEST_P(FormFetcherImplTest, RemoveConsumer) {
form_fetcher_->AddConsumer(&consumer_);
form_fetcher_->RemoveConsumer(&consumer_);
EXPECT_CALL(consumer_, OnFetchCompleted).Times(0);
- store_consumer()->OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<PasswordForm>>());
+ store_consumer()->OnGetPasswordStoreResultsFrom(
+ mock_store_, std::vector<std::unique_ptr<PasswordForm>>());
}
// Check that destroying the fetcher while notifying its consumers is handled
@@ -795,7 +806,8 @@ TEST_P(FormFetcherImplTest, DestroyFetcherFromConsumer) {
EXPECT_CALL(consumer_, OnFetchCompleted).Times(0);
static_cast<PasswordStoreConsumer*>(form_fetcher)
- ->OnGetPasswordStoreResults(std::vector<std::unique_ptr<PasswordForm>>());
+ ->OnGetPasswordStoreResultsFrom(
+ mock_store_, std::vector<std::unique_ptr<PasswordForm>>());
}
INSTANTIATE_TEST_SUITE_P(All,
diff --git a/chromium/components/password_manager/core/browser/form_parsing/form_parser.cc b/chromium/components/password_manager/core/browser/form_parsing/form_parser.cc
index 04b67f3d888..5e27c849a28 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/form_parser.cc
+++ b/chromium/components/password_manager/core/browser/form_parsing/form_parser.cc
@@ -13,7 +13,7 @@
#include <utility>
#include <vector>
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
@@ -976,7 +976,7 @@ std::unique_ptr<PasswordForm> AssemblePasswordForm(
// Create the PasswordForm and set data not related to specific fields.
auto result = std::make_unique<PasswordForm>();
- result->origin = form_data.url;
+ result->url = form_data.url;
result->signon_realm = GetSignonRealm(form_data.url);
result->action = form_data.action;
result->form_data = form_data;
@@ -1027,27 +1027,23 @@ std::unique_ptr<PasswordForm> FormDataParser::Parse(const FormData& form_data,
return nullptr;
SignificantFields significant_fields;
- UsernameDetectionMethod username_detection_method =
- UsernameDetectionMethod::kNoUsernameDetected;
+ UsernameDetectionMethod method = UsernameDetectionMethod::kNoUsernameDetected;
// (1) First, try to parse with server predictions.
if (predictions_) {
ParseUsingPredictions(&processed_fields, *predictions_, mode,
&significant_fields);
if (significant_fields.username) {
- username_detection_method =
- UsernameDetectionMethod::kServerSidePrediction;
+ method = UsernameDetectionMethod::kServerSidePrediction;
}
}
// (2) If that failed, try to parse with autocomplete attributes.
if (!significant_fields.is_single_username) {
ParseUsingAutocomplete(processed_fields, &significant_fields);
- if (username_detection_method ==
- UsernameDetectionMethod::kNoUsernameDetected &&
+ if (method == UsernameDetectionMethod::kNoUsernameDetected &&
significant_fields.username) {
- username_detection_method =
- UsernameDetectionMethod::kAutocompleteAttribute;
+ method = UsernameDetectionMethod::kAutocompleteAttribute;
}
}
@@ -1067,10 +1063,9 @@ std::unique_ptr<PasswordForm> FormDataParser::Parse(const FormData& form_data,
Interactability username_max = Interactability::kUnlikely;
ParseUsingBaseHeuristics(processed_fields, mode, &significant_fields,
&username_max, &readonly_status_);
- if (username_detection_method ==
- UsernameDetectionMethod::kNoUsernameDetected &&
+ if (method == UsernameDetectionMethod::kNoUsernameDetected &&
significant_fields.username) {
- username_detection_method = UsernameDetectionMethod::kBaseHeuristic;
+ method = UsernameDetectionMethod::kBaseHeuristic;
}
// Additionally, and based on the best interactability computed by base
@@ -1085,20 +1080,16 @@ std::unique_ptr<PasswordForm> FormDataParser::Parse(const FormData& form_data,
!(mode == FormDataParser::Mode::kSaving &&
username_field_by_context->value.empty())) {
significant_fields.username = username_field_by_context;
- if (username_detection_method ==
- UsernameDetectionMethod::kNoUsernameDetected ||
- username_detection_method ==
- UsernameDetectionMethod::kBaseHeuristic) {
- username_detection_method =
- UsernameDetectionMethod::kHtmlBasedClassifier;
+ if (method == UsernameDetectionMethod::kNoUsernameDetected ||
+ method == UsernameDetectionMethod::kBaseHeuristic) {
+ method = UsernameDetectionMethod::kHtmlBasedClassifier;
}
}
}
}
- UMA_HISTOGRAM_ENUMERATION("PasswordManager.UsernameDetectionMethod",
- username_detection_method,
- UsernameDetectionMethod::kCount);
+ base::UmaHistogramEnumeration("PasswordManager.UsernameDetectionMethod",
+ method);
return AssemblePasswordForm(form_data, significant_fields,
std::move(all_possible_passwords),
diff --git a/chromium/components/password_manager/core/browser/form_parsing/form_parser.h b/chromium/components/password_manager/core/browser/form_parsing/form_parser.h
index 7adcace01ab..a69e1448029 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/form_parser.h
+++ b/chromium/components/password_manager/core/browser/form_parsing/form_parser.h
@@ -39,7 +39,7 @@ class FormDataParser {
kHtmlBasedClassifier = 2,
kAutocompleteAttribute = 3,
kServerSidePrediction = 4,
- kCount
+ kMaxValue = kServerSidePrediction,
};
// Records whether password fields with a "readonly" attribute were ignored
diff --git a/chromium/components/password_manager/core/browser/form_saver.h b/chromium/components/password_manager/core/browser/form_saver.h
index b730e06d932..494abaf845c 100644
--- a/chromium/components/password_manager/core/browser/form_saver.h
+++ b/chromium/components/password_manager/core/browser/form_saver.h
@@ -53,10 +53,10 @@ class FormSaver {
const std::vector<const autofill::PasswordForm*>& matches,
const base::string16& old_password) = 0;
- // If any of the primary key fields (signon_realm, origin, username_element,
+ // If any of the unique key fields (signon_realm, origin, username_element,
// username_value, password_element) are updated, then the this version of
- // the Update method must be used, which takes |old_primary_key|, i.e., the
- // old values for the primary key fields (the rest of the fields are ignored).
+ // the Update method must be used, which takes |old_unique_key|, i.e., the
+ // old values for the unique key fields (the rest of the fields are ignored).
// The algorithm for handling |matches| and |old_password| is the same as
// above.
virtual void UpdateReplace(
diff --git a/chromium/components/password_manager/core/browser/form_saver_impl_unittest.cc b/chromium/components/password_manager/core/browser/form_saver_impl_unittest.cc
index d684f2d74ec..a8550278cbf 100644
--- a/chromium/components/password_manager/core/browser/form_saver_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/form_saver_impl_unittest.cc
@@ -37,8 +37,8 @@ namespace {
// Creates a dummy observed form with some basic arbitrary values.
PasswordForm CreateObserved() {
PasswordForm form;
- form.origin = GURL("https://example.in");
- form.signon_realm = form.origin.spec();
+ form.url = GURL("https://example.in");
+ form.signon_realm = form.url.spec();
form.action = GURL("https://login.example.org");
return form;
}
@@ -218,7 +218,7 @@ TEST_P(FormSaverImplSaveTest, Write_AndUpdatePasswordValuesOnExactMatch) {
constexpr char kNewPassword[] = "new_password";
PasswordForm duplicate = CreatePending("nameofuser", kOldPassword);
- duplicate.origin = GURL("https://example.in/somePath");
+ duplicate.url = GURL("https://example.in/somePath");
PasswordForm expected_update = duplicate;
expected_update.password_value = ASCIIToUTF16(kNewPassword);
@@ -234,8 +234,8 @@ TEST_P(FormSaverImplSaveTest, Write_AndUpdatePasswordValuesOnPSLMatch) {
constexpr char kNewPassword[] = "new_password";
PasswordForm duplicate = CreatePending("nameofuser", kOldPassword);
- duplicate.origin = GURL("https://www.example.in");
- duplicate.signon_realm = duplicate.origin.spec();
+ duplicate.url = GURL("https://www.example.in");
+ duplicate.signon_realm = duplicate.url.spec();
duplicate.is_public_suffix_match = true;
PasswordForm expected_update = duplicate;
@@ -328,7 +328,7 @@ TEST_F(FormSaverImplTest, PermanentlyBlacklist) {
observed.password_element = ASCIIToUTF16("password");
observed.all_possible_usernames = {
{ASCIIToUTF16("user2"), ASCIIToUTF16("field")}};
- observed.origin = GURL("https://www.example.com/foobar");
+ observed.url = GURL("https://www.example.com/foobar");
PasswordForm blacklisted =
password_manager_util::MakeNormalizedBlacklistedForm(
diff --git a/chromium/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc b/chromium/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
index bccf860fa92..bf18dee292d 100644
--- a/chromium/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
+++ b/chromium/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
@@ -65,7 +65,7 @@ std::string GetHashPrefix(const GURL& origin, size_t prefix_length) {
base::MD5Digest digest;
base::MD5Sum(domain_and_registry.data(), domain_and_registry.size(), &digest);
- for (size_t i = 0; i < base::size(digest.a); ++i) {
+ for (auto& byte : digest.a) {
if (prefix_length >= 8) {
prefix_length -= 8;
continue;
@@ -73,7 +73,7 @@ std::string GetHashPrefix(const GURL& origin, size_t prefix_length) {
// Determine the |prefix_length| most significant bits by calculating
// the 8 - |prefix_length| least significant bits and inverting the
// result.
- digest.a[i] &= ~((1 << (8 - prefix_length)) - 1);
+ byte &= ~((1 << (8 - prefix_length)) - 1);
prefix_length = 0;
}
}
@@ -137,15 +137,14 @@ void PasswordRequirementsSpecFetcherImpl::Fetch(GURL origin,
// If a lookup is happening already, just register another callback.
auto iter = lookups_in_flight_.find(hash_prefix);
if (iter != lookups_in_flight_.end()) {
- iter->second->callbacks.push_back(
- std::make_pair(origin, std::move(callback)));
+ iter->second->callbacks.emplace_back(origin, std::move(callback));
VLOG(1) << "Lookup already in flight";
return;
}
// Start another lookup otherwise.
auto lookup = std::make_unique<LookupInFlight>();
- lookup->callbacks.push_back(std::make_pair(origin, std::move(callback)));
+ lookup->callbacks.emplace_back(origin, std::move(callback));
lookup->start_of_request = base::TimeTicks::Now();
net::NetworkTrafficAnnotationTag traffic_annotation =
diff --git a/chromium/components/password_manager/core/browser/hsts_query.cc b/chromium/components/password_manager/core/browser/hsts_query.cc
index dfdf900b962..213ccd1f923 100644
--- a/chromium/components/password_manager/core/browser/hsts_query.cc
+++ b/chromium/components/password_manager/core/browser/hsts_query.cc
@@ -18,7 +18,7 @@ namespace {
// Helper since a once-callback may need to be called from two paths.
class HSTSCallbackHelper : public base::RefCounted<HSTSCallbackHelper> {
public:
- HSTSCallbackHelper(HSTSCallback user_callback)
+ explicit HSTSCallbackHelper(HSTSCallback user_callback)
: user_callback_(std::move(user_callback)) {}
void ReportResult(bool result) {
@@ -39,10 +39,10 @@ class HSTSCallbackHelper : public base::RefCounted<HSTSCallbackHelper> {
} // namespace
void PostHSTSQueryForHostAndNetworkContext(
- const GURL& origin,
+ const url::Origin& origin,
network::mojom::NetworkContext* network_context,
HSTSCallback callback) {
- if (!origin.is_valid()) {
+ if (origin.opaque()) {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), HSTSResult::kNo));
return;
diff --git a/chromium/components/password_manager/core/browser/hsts_query.h b/chromium/components/password_manager/core/browser/hsts_query.h
index 6bf21cce34d..d92ef83990e 100644
--- a/chromium/components/password_manager/core/browser/hsts_query.h
+++ b/chromium/components/password_manager/core/browser/hsts_query.h
@@ -7,14 +7,16 @@
#include "base/callback_forward.h"
-class GURL;
-
namespace network {
namespace mojom {
class NetworkContext;
}
} // namespace network
+namespace url {
+class Origin;
+}
+
namespace password_manager {
enum class HSTSResult { kNo, kYes, kError };
@@ -27,7 +29,7 @@ using HSTSCallback = base::OnceCallback<void(HSTSResult)>;
// thread the network context lives on (in things based on content/ the UI
// thread).
void PostHSTSQueryForHostAndNetworkContext(
- const GURL& origin,
+ const url::Origin& origin,
network::mojom::NetworkContext* network_context,
HSTSCallback callback);
diff --git a/chromium/components/password_manager/core/browser/hsts_query_unittest.cc b/chromium/components/password_manager/core/browser/hsts_query_unittest.cc
index 98a9b115708..b4707b61d18 100644
--- a/chromium/components/password_manager/core/browser/hsts_query_unittest.cc
+++ b/chromium/components/password_manager/core/browser/hsts_query_unittest.cc
@@ -81,7 +81,7 @@ class HSTSQueryTest : public testing::Test {
};
TEST_F(HSTSQueryTest, TestPostHSTSQueryForHostAndRequestContext) {
- const GURL origin("https://example.org");
+ const url::Origin origin = url::Origin::Create(GURL("https://example.org"));
for (bool is_hsts : {false, true}) {
SCOPED_TRACE(testing::Message()
<< std::boolalpha << "is_hsts: " << is_hsts);
@@ -107,7 +107,7 @@ TEST_F(HSTSQueryTest, TestPostHSTSQueryForHostAndRequestContext) {
}
TEST_F(HSTSQueryTest, NullNetworkContext) {
- const GURL origin("https://example.org");
+ const url::Origin origin = url::Origin::Create(GURL("https://example.org"));
bool callback_ran = false;
PostHSTSQueryForHostAndNetworkContext(
origin, nullptr,
diff --git a/chromium/components/password_manager/core/browser/http_auth_manager_impl.cc b/chromium/components/password_manager/core/browser/http_auth_manager_impl.cc
index f87ccd7390b..e4cdc054c0c 100644
--- a/chromium/components/password_manager/core/browser/http_auth_manager_impl.cc
+++ b/chromium/components/password_manager/core/browser/http_auth_manager_impl.cc
@@ -76,7 +76,7 @@ void HttpAuthManagerImpl::Autofill(
const PasswordFormManagerForUI* form_manager) const {
DCHECK_NE(PasswordForm::Scheme::kHtml, preferred_match.scheme);
if (observer_ && (form_manager_.get() == form_manager) &&
- client_->IsFillingEnabled(form_manager_->GetOrigin())) {
+ client_->IsFillingEnabled(form_manager_->GetURL())) {
observer_->OnAutofillDataAvailable(preferred_match.username_value,
preferred_match.password_value);
}
@@ -84,7 +84,7 @@ void HttpAuthManagerImpl::Autofill(
void HttpAuthManagerImpl::OnPasswordFormSubmitted(
const PasswordForm& password_form) {
- if (client_->IsSavingAndFillingEnabled(password_form.origin))
+ if (client_->IsSavingAndFillingEnabled(password_form.url))
ProvisionallySaveForm(password_form);
}
@@ -119,7 +119,7 @@ void HttpAuthManagerImpl::OnDidFinishMainFrameNavigation() {
void HttpAuthManagerImpl::OnLoginSuccesfull() {
LogMessage(Logger::STRING_HTTPAUTH_ON_ASK_USER_OR_SAVE_PASSWORD);
if (!form_manager_ ||
- !client_->IsSavingAndFillingEnabled(form_manager_->GetOrigin())) {
+ !client_->IsSavingAndFillingEnabled(form_manager_->GetURL())) {
return;
}
diff --git a/chromium/components/password_manager/core/browser/http_auth_manager_unittest.cc b/chromium/components/password_manager/core/browser/http_auth_manager_unittest.cc
index 6874807e212..8d5817669c1 100644
--- a/chromium/components/password_manager/core/browser/http_auth_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/http_auth_manager_unittest.cc
@@ -27,6 +27,7 @@
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
+#include "components/password_manager/core/common/password_manager_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -49,14 +50,13 @@ namespace {
class MockPasswordManagerClient : public StubPasswordManagerClient {
public:
- MockPasswordManagerClient() {}
-
MOCK_CONST_METHOD1(IsSavingAndFillingEnabled, bool(const GURL&));
MOCK_CONST_METHOD1(IsFillingEnabled, bool(const GURL&));
MOCK_METHOD2(AutofillHttpAuth,
void(const autofill::PasswordForm&,
const PasswordFormManagerForUI*));
MOCK_CONST_METHOD0(GetProfilePasswordStore, PasswordStore*());
+ MOCK_CONST_METHOD0(GetAccountPasswordStore, PasswordStore*());
MOCK_METHOD0(PromptUserToSaveOrUpdatePasswordPtr, void());
// Workaround for std::unique_ptr<> lacking a copy constructor.
@@ -71,7 +71,6 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
class MockHttpAuthObserver : public HttpAuthObserver {
public:
MockHttpAuthObserver() = default;
- ~MockHttpAuthObserver() override = default;
MOCK_METHOD0(OnLoginModelDestroying, void());
MOCK_METHOD2(OnAutofillDataAvailable,
@@ -80,15 +79,9 @@ class MockHttpAuthObserver : public HttpAuthObserver {
DISALLOW_COPY_AND_ASSIGN(MockHttpAuthObserver);
};
-// Invokes the password store consumer with a single copy of |form|.
-ACTION_P(InvokeConsumer, form) {
- std::vector<std::unique_ptr<PasswordForm>> result;
- result.push_back(std::make_unique<PasswordForm>(form));
- arg0->OnGetPasswordStoreResults(std::move(result));
-}
-
-ACTION(InvokeEmptyConsumerWithForms) {
- arg0->OnGetPasswordStoreResults(std::vector<std::unique_ptr<PasswordForm>>());
+ACTION_P(InvokeEmptyConsumerWithForms, store) {
+ arg0->OnGetPasswordStoreResultsFrom(
+ store, std::vector<std::unique_ptr<PasswordForm>>());
}
} // namespace
@@ -100,13 +93,31 @@ class HttpAuthManagerTest : public testing::Test {
protected:
void SetUp() override {
store_ = new testing::StrictMock<MockPasswordStore>;
- ASSERT_TRUE(store_->Init(nullptr));
+ ASSERT_TRUE(store_->Init(/*prefs=*/nullptr));
+
+ if (base::FeatureList::IsEnabled(
+ features::kEnablePasswordsAccountStorage)) {
+ account_store_ = new testing::NiceMock<MockPasswordStore>;
+ ASSERT_TRUE(account_store_->Init(/*prefs=*/nullptr));
+
+ // Most tests don't really need the account store, but it'll still get
+ // queried by MultiStoreFormFetcher, so it needs to return something to
+ // its consumers. Let the account store return empty results by default,
+ // so that not every test has to set this up individually. Individual
+ // tests that do cover the account store can still override this.
+ ON_CALL(*account_store_, GetLogins(_, _))
+ .WillByDefault(
+ WithArg<1>(InvokeEmptyConsumerWithForms(account_store_.get())));
+ }
ON_CALL(client_, GetProfilePasswordStore())
.WillByDefault(Return(store_.get()));
+ ON_CALL(client_, GetAccountPasswordStore())
+ .WillByDefault(Return(account_store_.get()));
+
EXPECT_CALL(*store_, GetSiteStatsImpl(_)).Times(AnyNumber());
- httpauth_manager_.reset(new HttpAuthManagerImpl(&client_));
+ httpauth_manager_ = std::make_unique<HttpAuthManagerImpl>(&client_);
EXPECT_CALL(*store_, IsAbleToSavePasswords()).WillRepeatedly(Return(true));
@@ -116,6 +127,10 @@ class HttpAuthManagerTest : public testing::Test {
}
void TearDown() override {
+ if (account_store_) {
+ account_store_->ShutdownOnUIThread();
+ account_store_ = nullptr;
+ }
store_->ShutdownOnUIThread();
store_ = nullptr;
}
@@ -124,6 +139,7 @@ class HttpAuthManagerTest : public testing::Test {
base::test::TaskEnvironment task_environment_;
scoped_refptr<MockPasswordStore> store_;
+ scoped_refptr<MockPasswordStore> account_store_;
testing::NiceMock<MockPasswordManagerClient> client_;
std::unique_ptr<HttpAuthManagerImpl> httpauth_manager_;
};
@@ -136,7 +152,7 @@ TEST_F(HttpAuthManagerTest, HttpAuthFilling) {
PasswordForm observed_form;
observed_form.scheme = PasswordForm::Scheme::kBasic;
- observed_form.origin = GURL("http://proxy.com/");
+ observed_form.url = GURL("http://proxy.com/");
observed_form.signon_realm = "proxy.com/realm";
PasswordForm stored_form = observed_form;
@@ -155,7 +171,7 @@ TEST_F(HttpAuthManagerTest, HttpAuthFilling) {
ASSERT_TRUE(consumer);
std::vector<std::unique_ptr<PasswordForm>> result;
result.push_back(std::make_unique<PasswordForm>(stored_form));
- consumer->OnGetPasswordStoreResults(std::move(result));
+ consumer->OnGetPasswordStoreResultsFrom(store_, std::move(result));
testing::Mock::VerifyAndClearExpectations(&store_);
httpauth_manager()->DetachObserver(&observer);
}
@@ -170,12 +186,12 @@ TEST_F(HttpAuthManagerTest, HttpAuthSaving) {
.WillRepeatedly(Return(filling_and_saving_enabled));
PasswordForm observed_form;
observed_form.scheme = PasswordForm::Scheme::kBasic;
- observed_form.origin = GURL("http://proxy.com/");
+ observed_form.url = GURL("http://proxy.com/");
observed_form.signon_realm = "proxy.com/realm";
MockHttpAuthObserver observer;
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
// Initiate creating a form manager.
httpauth_manager()->SetObserverAndDeliverCredentials(&observer,
@@ -202,12 +218,12 @@ TEST_F(HttpAuthManagerTest, NavigationWithoutSubmission) {
.WillRepeatedly(Return(true));
PasswordForm observed_form;
observed_form.scheme = PasswordForm::Scheme::kBasic;
- observed_form.origin = GURL("http://proxy.com/");
+ observed_form.url = GURL("http://proxy.com/");
observed_form.signon_realm = "proxy.com/realm";
MockHttpAuthObserver observer;
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
// Initiate creating a form manager.
httpauth_manager()->SetObserverAndDeliverCredentials(&observer,
@@ -223,7 +239,7 @@ TEST_F(HttpAuthManagerTest, NavigationWhenMatchingNotReady) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
PasswordForm observed_form;
observed_form.scheme = PasswordForm::Scheme::kBasic;
- observed_form.origin = GURL("http://proxy.com/");
+ observed_form.url = GURL("http://proxy.com/");
observed_form.signon_realm = "proxy.com/realm";
MockHttpAuthObserver observer;
diff --git a/chromium/components/password_manager/core/browser/http_credentials_cleaner.cc b/chromium/components/password_manager/core/browser/http_credentials_cleaner.cc
index 9146f096076..60e380f863e 100644
--- a/chromium/components/password_manager/core/browser/http_credentials_cleaner.cc
+++ b/chromium/components/password_manager/core/browser/http_credentials_cleaner.cc
@@ -47,8 +47,8 @@ void HttpCredentialCleaner::OnGetPasswordStoreResults(
{std::string(
password_manager_util::GetSignonRealmWithProtocolExcluded(*form)),
form->scheme, form->username_value});
- if (form->origin.SchemeIs(url::kHttpScheme)) {
- const GURL origin = form->origin;
+ if (form->url.SchemeIs(url::kHttpScheme)) {
+ auto origin = url::Origin::Create(form->url);
PostHSTSQueryForHostAndNetworkContext(
origin, network_context_getter_.Run(),
base::BindOnce(&HttpCredentialCleaner::OnHSTSQueryResult,
diff --git a/chromium/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc b/chromium/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
index a4024a60b67..9f1a1740eb9 100644
--- a/chromium/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
+++ b/chromium/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
@@ -152,7 +152,7 @@ TEST_P(HttpCredentialCleanerTest, ReportHttpMigrationMetrics) {
<< ", same_password=" << test.same_password);
autofill::PasswordForm http_form;
- http_form.origin = GURL("http://example.org/");
+ http_form.url = GURL("http://example.org/");
http_form.signon_realm = "http://example.org/";
http_form.scheme = test.http_form_scheme;
http_form.username_value = username[1];
@@ -160,7 +160,7 @@ TEST_P(HttpCredentialCleanerTest, ReportHttpMigrationMetrics) {
store_->AddLogin(http_form);
autofill::PasswordForm https_form;
- https_form.origin = GURL("https://example.org/");
+ https_form.url = GURL("https://example.org/");
https_form.signon_realm = signon_realm[test.same_signon_realm];
https_form.username_value = username[test.same_username];
https_form.password_value = password[test.same_password];
@@ -183,7 +183,7 @@ TEST_P(HttpCredentialCleanerTest, ReportHttpMigrationMetrics) {
if (test.is_hsts_enabled) {
base::RunLoop run_loop;
- network_context->AddHSTS(http_form.origin.host(), base::Time::Max(),
+ network_context->AddHSTS(http_form.url.host(), base::Time::Max(),
false /*include_subdomains*/,
run_loop.QuitClosure());
run_loop.Run();
diff --git a/chromium/components/password_manager/core/browser/http_password_store_migrator.cc b/chromium/components/password_manager/core/browser/http_password_store_migrator.cc
index 637bc8ce5af..5bc82989b88 100644
--- a/chromium/components/password_manager/core/browser/http_password_store_migrator.cc
+++ b/chromium/components/password_manager/core/browser/http_password_store_migrator.cc
@@ -37,20 +37,20 @@ void OnHSTSQueryResultHelper(
} // namespace
HttpPasswordStoreMigrator::HttpPasswordStoreMigrator(
- const GURL& https_origin,
+ const url::Origin& https_origin,
const PasswordManagerClient* client,
Consumer* consumer)
: client_(client), consumer_(consumer) {
DCHECK(client_);
- DCHECK(https_origin.is_valid());
- DCHECK(https_origin.SchemeIs(url::kHttpsScheme)) << https_origin;
+ DCHECK(!https_origin.opaque());
+ DCHECK_EQ(https_origin.scheme(), url::kHttpsScheme) << https_origin;
GURL::Replacements rep;
rep.SetSchemeStr(url::kHttpScheme);
- GURL http_origin = https_origin.ReplaceComponents(rep);
+ GURL http_origin = https_origin.GetURL().ReplaceComponents(rep);
PasswordStore::FormDigest form(autofill::PasswordForm::Scheme::kHtml,
http_origin.GetOrigin().spec(), http_origin);
- http_origin_domain_ = http_origin.GetOrigin();
+ http_origin_domain_ = url::Origin::Create(http_origin);
client_->GetProfilePasswordStore()->GetLogins(form, this);
client_->PostHSTSQueryForHost(
https_origin, base::BindOnce(&OnHSTSQueryResultHelper, GetWeakPtr()));
@@ -60,12 +60,12 @@ HttpPasswordStoreMigrator::~HttpPasswordStoreMigrator() = default;
autofill::PasswordForm HttpPasswordStoreMigrator::MigrateHttpFormToHttps(
const autofill::PasswordForm& http_form) {
- DCHECK(http_form.origin.SchemeIs(url::kHttpScheme));
+ DCHECK(http_form.url.SchemeIs(url::kHttpScheme));
autofill::PasswordForm https_form = http_form;
GURL::Replacements rep;
rep.SetSchemeStr(url::kHttpsScheme);
- https_form.origin = http_form.origin.ReplaceComponents(rep);
+ https_form.url = http_form.url.ReplaceComponents(rep);
// Only replace the scheme of the signon_realm in case it is HTTP. Do not
// change the signon_realm for federated credentials.
@@ -78,7 +78,7 @@ autofill::PasswordForm HttpPasswordStoreMigrator::MigrateHttpFormToHttps(
// If |action| is not HTTPS then it's most likely obsolete. Otherwise, it
// may still be valid.
if (!http_form.action.SchemeIs(url::kHttpsScheme))
- https_form.action = https_form.origin;
+ https_form.action = https_form.url;
https_form.form_data = autofill::FormData();
https_form.generation_upload_status =
autofill::PasswordForm::GenerationUploadStatus::kNoSignalSent;
@@ -103,7 +103,8 @@ void HttpPasswordStoreMigrator::OnHSTSQueryResult(HSTSResult is_hsts) {
got_hsts_query_result_ = true;
if (is_hsts == HSTSResult::kYes)
- client_->GetProfilePasswordStore()->RemoveSiteStats(http_origin_domain_);
+ client_->GetProfilePasswordStore()->RemoveSiteStats(
+ http_origin_domain_.GetURL());
if (got_password_store_results_)
ProcessPasswordStoreResults();
diff --git a/chromium/components/password_manager/core/browser/http_password_store_migrator.h b/chromium/components/password_manager/core/browser/http_password_store_migrator.h
index 6f2f8f00595..53cb8b975ca 100644
--- a/chromium/components/password_manager/core/browser/http_password_store_migrator.h
+++ b/chromium/components/password_manager/core/browser/http_password_store_migrator.h
@@ -12,7 +12,7 @@
#include "base/sequence_checker.h"
#include "components/password_manager/core/browser/hsts_query.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
-#include "url/gurl.h"
+#include "url/origin.h"
namespace autofill {
struct PasswordForm;
@@ -57,7 +57,7 @@ class HttpPasswordStoreMigrator : public PasswordStoreConsumer {
};
// |https_origin| should specify a valid HTTPS URL.
- HttpPasswordStoreMigrator(const GURL& https_origin,
+ HttpPasswordStoreMigrator(const url::Origin& https_origin,
const PasswordManagerClient* client,
Consumer* consumer);
~HttpPasswordStoreMigrator() override;
@@ -87,7 +87,7 @@ class HttpPasswordStoreMigrator : public PasswordStoreConsumer {
bool got_password_store_results_ = false;
HttpPasswordMigrationMode mode_ = HttpPasswordMigrationMode::kMove;
std::vector<std::unique_ptr<autofill::PasswordForm>> results_;
- GURL http_origin_domain_;
+ url::Origin http_origin_domain_;
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(HttpPasswordStoreMigrator);
diff --git a/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc b/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
index 689de82cc32..db696d6d2b3 100644
--- a/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
+++ b/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
@@ -31,8 +31,8 @@ constexpr char kTestSubdomainHttpURL[] = "http://login.example.org/path2";
// Creates a dummy http form with some basic arbitrary values.
PasswordForm CreateTestForm() {
PasswordForm form;
- form.origin = GURL(kTestHttpURL);
- form.signon_realm = form.origin.GetOrigin().spec();
+ form.url = GURL(kTestHttpURL);
+ form.signon_realm = form.url.GetOrigin().spec();
form.action = GURL("https://example.org/action.html");
form.username_value = base::ASCIIToUTF16("user");
form.password_value = base::ASCIIToUTF16("password");
@@ -42,8 +42,8 @@ PasswordForm CreateTestForm() {
// Creates a dummy http PSL-matching form with some basic arbitrary values.
PasswordForm CreateTestPSLForm() {
PasswordForm form;
- form.origin = GURL(kTestSubdomainHttpURL);
- form.signon_realm = form.origin.GetOrigin().spec();
+ form.url = GURL(kTestSubdomainHttpURL);
+ form.signon_realm = form.url.GetOrigin().spec();
form.action = GURL(kTestSubdomainHttpURL);
form.username_value = base::ASCIIToUTF16("user2");
form.password_value = base::ASCIIToUTF16("password2");
@@ -57,7 +57,7 @@ PasswordForm CreateAndroidCredential() {
form.username_value = base::ASCIIToUTF16("user3");
form.password_value = base::ASCIIToUTF16("password3");
form.signon_realm = "android://hash@com.example.android/";
- form.origin = GURL(form.signon_realm);
+ form.url = GURL(form.signon_realm);
form.action = GURL();
form.is_affiliation_based_match = true;
return form;
@@ -68,7 +68,7 @@ PasswordForm CreateLocalFederatedCredential() {
PasswordForm form;
form.username_value = base::ASCIIToUTF16("user4");
form.signon_realm = "federation://localhost/federation.example.com";
- form.origin = GURL("http://localhost/");
+ form.url = GURL("http://localhost/");
form.action = GURL("http://localhost/");
form.federation_origin =
url::Origin::Create(GURL("https://federation.example.com"));
@@ -97,20 +97,18 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
// PasswordManagerClient:
PasswordStore* GetProfilePasswordStore() const override { return store_; }
- void PostHSTSQueryForHost(const GURL& gurl,
+ void PostHSTSQueryForHost(const url::Origin& origin,
HSTSCallback callback) const override {
saved_callback_ = std::move(callback);
- PostHSTSQueryForHostHelper(gurl);
+ PostHSTSQueryForHostHelper(origin);
}
- MOCK_CONST_METHOD1(PostHSTSQueryForHostHelper, void(const GURL&));
+ MOCK_CONST_METHOD1(PostHSTSQueryForHostHelper, void(const url::Origin&));
HSTSCallback hsts_acquire_callback() { return std::move(saved_callback_); }
private:
PasswordStore* store_;
mutable HSTSCallback saved_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerClient);
};
} // namespace
@@ -148,12 +146,14 @@ class HttpPasswordStoreMigratorTest : public testing::Test {
};
void HttpPasswordStoreMigratorTest::TestEmptyStore(bool is_hsts) {
- PasswordStore::FormDigest form(CreateTestForm());
- EXPECT_CALL(store(), GetLogins(form, _));
- EXPECT_CALL(client(), PostHSTSQueryForHostHelper(GURL(kTestHttpsURL)))
+ PasswordStore::FormDigest form_digest(CreateTestForm());
+ form_digest.url = form_digest.url.GetOrigin();
+ EXPECT_CALL(store(), GetLogins(form_digest, _));
+ EXPECT_CALL(client(), PostHSTSQueryForHostHelper(
+ url::Origin::Create(GURL(kTestHttpsURL))))
.Times(1);
- HttpPasswordStoreMigrator migrator(GURL(kTestHttpsURL), &client(),
- &consumer());
+ HttpPasswordStoreMigrator migrator(url::Origin::Create(GURL(kTestHttpsURL)),
+ &client(), &consumer());
HSTSCallback callback = client().hsts_acquire_callback();
std::move(callback).Run(is_hsts ? HSTSResult::kYes : HSTSResult::kNo);
// We expect a potential call to |RemoveSiteStatsImpl| which is a async task
@@ -170,11 +170,13 @@ void HttpPasswordStoreMigratorTest::TestEmptyStore(bool is_hsts) {
void HttpPasswordStoreMigratorTest::TestFullStore(bool is_hsts) {
PasswordStore::FormDigest form_digest(CreateTestForm());
+ form_digest.url = form_digest.url.GetOrigin();
EXPECT_CALL(store(), GetLogins(form_digest, _));
- EXPECT_CALL(client(), PostHSTSQueryForHostHelper(GURL(kTestHttpsURL)))
+ EXPECT_CALL(client(), PostHSTSQueryForHostHelper(
+ url::Origin::Create(GURL(kTestHttpsURL))))
.Times(1);
- HttpPasswordStoreMigrator migrator(GURL(kTestHttpsURL), &client(),
- &consumer());
+ HttpPasswordStoreMigrator migrator(url::Origin::Create(GURL(kTestHttpsURL)),
+ &client(), &consumer());
HSTSCallback callback = client().hsts_acquire_callback();
std::move(callback).Run(is_hsts ? HSTSResult::kYes : HSTSResult::kNo);
// We expect a potential call to |RemoveSiteStatsImpl| which is a async task
@@ -189,11 +191,11 @@ void HttpPasswordStoreMigratorTest::TestFullStore(bool is_hsts) {
PasswordForm android_form = CreateAndroidCredential();
PasswordForm federated_form = CreateLocalFederatedCredential();
PasswordForm expected_form = form;
- expected_form.origin = GURL(kTestHttpsURL);
- expected_form.signon_realm = expected_form.origin.GetOrigin().spec();
+ expected_form.url = GURL(kTestHttpsURL);
+ expected_form.signon_realm = expected_form.url.GetOrigin().spec();
PasswordForm expected_federated_form = federated_form;
- expected_federated_form.origin = GURL("https://localhost");
+ expected_federated_form.url = GURL("https://localhost");
expected_federated_form.action = GURL("https://localhost");
EXPECT_CALL(store(), AddLogin(expected_form));
@@ -218,13 +220,14 @@ void HttpPasswordStoreMigratorTest::TestMigratorDeletionByConsumer(
bool is_hsts) {
// Setup expectations on store and client.
EXPECT_CALL(store(), GetLogins(_, _));
- EXPECT_CALL(client(), PostHSTSQueryForHostHelper(GURL(kTestHttpsURL)))
+ EXPECT_CALL(client(), PostHSTSQueryForHostHelper(
+ url::Origin::Create(GURL(kTestHttpsURL))))
.Times(1);
// Construct the migrator, call |OnGetPasswordStoreResults| explicitly and
// manually delete it.
auto migrator = std::make_unique<HttpPasswordStoreMigrator>(
- GURL(kTestHttpsURL), &client(), &consumer());
+ url::Origin::Create(GURL(kTestHttpsURL)), &client(), &consumer());
migrator->OnGetPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>>());
EXPECT_CALL(consumer(), ProcessForms(_)).WillOnce(Invoke([&migrator](Unused) {
@@ -271,17 +274,17 @@ TEST(HttpPasswordStoreMigrator, MigrateHttpFormToHttpsTestSignonRealm) {
for (bool origin_has_paths : {true, false}) {
PasswordForm http_html_form;
- http_html_form.origin = kOrigins[origin_has_paths];
+ http_html_form.url = kOrigins[origin_has_paths];
http_html_form.signon_realm = "http://example.org/";
http_html_form.scheme = PasswordForm::Scheme::kHtml;
PasswordForm non_html_empty_realm_form;
- non_html_empty_realm_form.origin = kOrigins[origin_has_paths];
+ non_html_empty_realm_form.url = kOrigins[origin_has_paths];
non_html_empty_realm_form.signon_realm = "http://example.org/";
non_html_empty_realm_form.scheme = PasswordForm::Scheme::kBasic;
PasswordForm non_html_form;
- non_html_form.origin = kOrigins[origin_has_paths];
+ non_html_form.url = kOrigins[origin_has_paths];
non_html_form.signon_realm = "http://example.org/realm";
non_html_form.scheme = PasswordForm::Scheme::kBasic;
diff --git a/chromium/components/password_manager/core/browser/import/csv_password.cc b/chromium/components/password_manager/core/browser/import/csv_password.cc
index 3628823f9cc..554eac73531 100644
--- a/chromium/components/password_manager/core/browser/import/csv_password.cc
+++ b/chromium/components/password_manager/core/browser/import/csv_password.cc
@@ -104,7 +104,7 @@ CSVPassword::Status CSVPassword::ParseImpl(PasswordForm* form) const {
form->signon_realm = IsValidAndroidFacetURI(origin.spec())
? origin.spec()
: origin.GetOrigin().spec();
- form->origin = std::move(origin);
+ form->url = std::move(origin);
form->username_value = Convert(username);
form->password_value = Convert(password);
form->date_created = base::Time::Now();
diff --git a/chromium/components/password_manager/core/browser/import/csv_password_sequence_unittest.cc b/chromium/components/password_manager/core/browser/import/csv_password_sequence_unittest.cc
index 115d58f286a..50c8d27df07 100644
--- a/chromium/components/password_manager/core/browser/import/csv_password_sequence_unittest.cc
+++ b/chromium/components/password_manager/core/browser/import/csv_password_sequence_unittest.cc
@@ -113,7 +113,7 @@ TEST(CSVPasswordSequenceTest, Iteration) {
ASSERT_LT(order, base::size(kExpectedCredentials));
PasswordForm parsed = pwd.ParseValid();
const auto& expected = kExpectedCredentials[order];
- EXPECT_EQ(GURL(expected.url), parsed.origin);
+ EXPECT_EQ(GURL(expected.url), parsed.url);
EXPECT_EQ(base::ASCIIToUTF16(expected.username), parsed.username_value);
EXPECT_EQ(base::ASCIIToUTF16(expected.password), parsed.password_value);
++order;
@@ -129,7 +129,7 @@ TEST(CSVPasswordSequenceTest, MissingEolAtEof) {
ASSERT_EQ(1, std::distance(seq.begin(), seq.end()));
PasswordForm parsed = seq.begin()->ParseValid();
- EXPECT_EQ(GURL("http://a.com"), parsed.origin);
+ EXPECT_EQ(GURL("http://a.com"), parsed.url);
EXPECT_EQ(base::ASCIIToUTF16("l"), parsed.username_value);
EXPECT_EQ(base::ASCIIToUTF16("p"), parsed.password_value);
}
diff --git a/chromium/components/password_manager/core/browser/import/csv_password_unittest.cc b/chromium/components/password_manager/core/browser/import/csv_password_unittest.cc
index 10d1f96d63b..8b38a94d416 100644
--- a/chromium/components/password_manager/core/browser/import/csv_password_unittest.cc
+++ b/chromium/components/password_manager/core/browser/import/csv_password_unittest.cc
@@ -32,7 +32,7 @@ TEST(CSVPasswordTest, Construction) {
const CSVPassword csv_pwd(kColMap, "http://example.com,user,password");
const PasswordForm result = csv_pwd.ParseValid();
const GURL expected_origin("http://example.com");
- EXPECT_EQ(expected_origin, result.origin);
+ EXPECT_EQ(expected_origin, result.url);
EXPECT_EQ(expected_origin.GetOrigin().spec(), result.signon_realm);
EXPECT_EQ(base::ASCIIToUTF16("user"), result.username_value);
EXPECT_EQ(base::ASCIIToUTF16("password"), result.password_value);
@@ -54,7 +54,9 @@ struct TestCase {
class TestCaseBuilder {
public:
- TestCaseBuilder(std::string name) { test_case_.name = std::move(name); }
+ explicit TestCaseBuilder(std::string name) {
+ test_case_.name = std::move(name);
+ }
~TestCaseBuilder() = default;
@@ -114,7 +116,7 @@ TEST_P(CSVPasswordTestSuccess, Parse) {
const PasswordForm result = csv_pwd.ParseValid();
const GURL expected_origin(test_case.origin);
- EXPECT_EQ(expected_origin, result.origin);
+ EXPECT_EQ(expected_origin, result.url);
EXPECT_EQ(expected_origin.GetOrigin().spec(), result.signon_realm);
EXPECT_EQ(base::UTF8ToUTF16(test_case.username), result.username_value);
diff --git a/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc b/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc
index 00bd344014a..3b530f5d1b5 100644
--- a/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc
+++ b/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc
@@ -26,10 +26,7 @@ const char kTestFileName[] = "test_only.csv";
class PasswordImporterTest : public testing::Test {
public:
- PasswordImporterTest()
- : callback_called_(false), result_(PasswordImporter::NUM_IMPORT_RESULTS) {
- CHECK(temp_directory_.CreateUniqueTempDir());
- }
+ PasswordImporterTest() { CHECK(temp_directory_.CreateUniqueTempDir()); }
protected:
void StartImportAndWaitForCompletion(const base::FilePath& input_file) {
@@ -65,8 +62,8 @@ class PasswordImporterTest : public testing::Test {
private:
base::test::TaskEnvironment task_environment_;
- bool callback_called_;
- PasswordImporter::Result result_;
+ bool callback_called_ = false;
+ PasswordImporter::Result result_ = PasswordImporter::NUM_IMPORT_RESULTS;
std::vector<autofill::PasswordForm> imported_passwords_;
DISALLOW_COPY_AND_ASSIGN(PasswordImporterTest);
@@ -85,7 +82,7 @@ TEST_F(PasswordImporterTest, CSVImport) {
EXPECT_EQ(PasswordImporter::SUCCESS, result());
ASSERT_EQ(1u, imported_passwords().size());
- EXPECT_EQ(GURL(kTestOriginURL), imported_passwords()[0].origin);
+ EXPECT_EQ(GURL(kTestOriginURL), imported_passwords()[0].url);
EXPECT_EQ(kTestSignonRealm, imported_passwords()[0].signon_realm);
EXPECT_EQ(base::ASCIIToUTF16(kTestUsername),
imported_passwords()[0].username_value);
diff --git a/chromium/components/password_manager/core/browser/leak_detection/leak_detection_check_factory_impl_unittest.cc b/chromium/components/password_manager/core/browser/leak_detection/leak_detection_check_factory_impl_unittest.cc
index b85fa926bf1..1aec99fe4c4 100644
--- a/chromium/components/password_manager/core/browser/leak_detection/leak_detection_check_factory_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection/leak_detection_check_factory_impl_unittest.cc
@@ -100,6 +100,9 @@ TEST_F(LeakDetectionCheckFactoryImplTest, BulkCheck_SignedInAndSyncing) {
}
TEST_F(LeakDetectionCheckFactoryImplTest, BulkCheck_FeatureOff) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(
+ password_manager::features::kPasswordCheck);
identity_env().SetPrimaryAccount(kTestAccount);
EXPECT_FALSE(request_factory().TryCreateBulkLeakCheck(
&bulk_delegate(), identity_env().identity_manager(),
diff --git a/chromium/components/password_manager/core/browser/leak_detection_delegate.cc b/chromium/components/password_manager/core/browser/leak_detection_delegate.cc
index ee6e9d1dfe9..ef1e159f295 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_delegate.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection_delegate.cc
@@ -4,6 +4,8 @@
#include "components/password_manager/core/browser/leak_detection_delegate.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "build/build_config.h"
#include "components/autofill/core/common/password_form.h"
@@ -61,7 +63,7 @@ void LeakDetectionDelegate::StartLeakCheck(const autofill::PasswordForm& form) {
helper_.reset();
if (leak_check_) {
is_leaked_timer_ = std::make_unique<base::ElapsedTimer>();
- leak_check_->Start(form.origin, form.username_value, form.password_value);
+ leak_check_->Start(form.url, form.username_value, form.password_value);
}
}
@@ -75,16 +77,20 @@ void LeakDetectionDelegate::OnLeakDetectionDone(bool is_leaked,
logger.LogBoolean(Logger::STRING_LEAK_DETECTION_FINISHED, is_leaked);
}
- if (is_leaked) {
- // Otherwise query the helper to asynchronously determine the
- // |CredentialLeakType|.
- helper_ = std::make_unique<LeakDetectionDelegateHelper>(
- client_->GetProfilePasswordStore(),
- base::BindOnce(
- &LeakDetectionDelegate::OnShowLeakDetectionNotification,
- base::Unretained(this)));
- helper_->ProcessLeakedPassword(std::move(url), std::move(username),
- std::move(password));
+ bool force_dialog_for_testing = base::GetFieldTrialParamByFeatureAsBool(
+ password_manager::features::kPasswordChange,
+ password_manager::features::
+ kPasswordChangeWithForcedDialogAfterEverySuccessfulSubmission,
+ false);
+ if (is_leaked || force_dialog_for_testing) {
+ // Otherwise query the helper to asynchronously determine the
+ // |CredentialLeakType|.
+ helper_ = std::make_unique<LeakDetectionDelegateHelper>(
+ client_->GetProfilePasswordStore(),
+ base::BindOnce(&LeakDetectionDelegate::OnShowLeakDetectionNotification,
+ base::Unretained(this)));
+ helper_->ProcessLeakedPassword(std::move(url), std::move(username),
+ std::move(password));
}
}
@@ -93,6 +99,22 @@ void LeakDetectionDelegate::OnShowLeakDetectionNotification(
IsReused is_reused,
GURL url,
base::string16 username) {
+ bool force_dialog_for_testing = base::GetFieldTrialParamByFeatureAsBool(
+ password_manager::features::kPasswordChange,
+ password_manager::features::
+ kPasswordChangeWithForcedDialogAfterEverySuccessfulSubmission,
+ false);
+ if (force_dialog_for_testing) {
+ helper_.reset();
+ // Correct leak_type to offer change password.
+ CredentialLeakType leak_type =
+ CreateLeakType(is_saved, IsReused(false),
+ IsSyncing(client_->GetPasswordSyncState() ==
+ SYNCING_NORMAL_ENCRYPTION));
+ client_->NotifyUserCredentialsWereLeaked(leak_type, url, username);
+ return;
+ }
+
DCHECK(is_leaked_timer_);
base::UmaHistogramTimes("PasswordManager.LeakDetection.NotifyIsLeakedTime",
std::exchange(is_leaked_timer_, nullptr)->Elapsed());
diff --git a/chromium/components/password_manager/core/browser/leak_detection_delegate_helper.cc b/chromium/components/password_manager/core/browser/leak_detection_delegate_helper.cc
index 17eae1007dc..e9e7dc1bff6 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_delegate_helper.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection_delegate_helper.cc
@@ -46,7 +46,7 @@ void LeakDetectionDelegateHelper::OnGetPasswordStoreResults(
IsSaved is_saved(
std::any_of(results.begin(), results.end(), [this](const auto& form) {
- return form->origin == url_ && form->username_value == username_;
+ return form->url == url_ && form->username_value == username_;
}));
IsReused is_reused(results.size() > (is_saved ? 1 : 0));
diff --git a/chromium/components/password_manager/core/browser/leak_detection_delegate_helper_unittest.cc b/chromium/components/password_manager/core/browser/leak_detection_delegate_helper_unittest.cc
index c58890c36ed..bdef2803db9 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_delegate_helper_unittest.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection_delegate_helper_unittest.cc
@@ -43,10 +43,10 @@ PasswordForm CreateForm(base::StringPiece origin,
base::StringPiece username,
base::StringPiece password = kLeakedPassword) {
PasswordForm form;
- form.origin = GURL(ASCIIToUTF16(origin));
+ form.url = GURL(ASCIIToUTF16(origin));
form.username_value = ASCIIToUTF16(username);
form.password_value = ASCIIToUTF16(password);
- form.signon_realm = form.origin.GetOrigin().spec();
+ form.signon_realm = form.url.GetOrigin().spec();
return form;
}
@@ -122,6 +122,8 @@ TEST_F(LeakDetectionDelegateHelperTest, SavedLeakedCredentials) {
SetGetLoginByPasswordConsumerInvocation(std::move(password_forms));
SetOnShowLeakDetectionNotificationExpectation(IsSaved(true), IsReused(false));
+ EXPECT_CALL(*store_, AddCompromisedCredentialsImpl)
+ .Times(base::FeatureList::IsEnabled(features::kPasswordCheck));
InitiateGetCredentialLeakType();
}
@@ -134,6 +136,8 @@ TEST_F(LeakDetectionDelegateHelperTest,
SetGetLoginByPasswordConsumerInvocation(std::move(password_forms));
SetOnShowLeakDetectionNotificationExpectation(IsSaved(true), IsReused(true));
+ EXPECT_CALL(*store_, AddCompromisedCredentialsImpl)
+ .Times(2 * base::FeatureList::IsEnabled(features::kPasswordCheck));
InitiateGetCredentialLeakType();
}
@@ -147,6 +151,8 @@ TEST_F(LeakDetectionDelegateHelperTest,
SetGetLoginByPasswordConsumerInvocation(std::move(password_forms));
SetOnShowLeakDetectionNotificationExpectation(IsSaved(true), IsReused(true));
+ EXPECT_CALL(*store_, AddCompromisedCredentialsImpl)
+ .Times(base::FeatureList::IsEnabled(features::kPasswordCheck));
InitiateGetCredentialLeakType();
}
@@ -167,6 +173,8 @@ TEST_F(LeakDetectionDelegateHelperTest, ReusedPasswordOnOtherOrigin) {
SetGetLoginByPasswordConsumerInvocation(std::move(password_forms));
SetOnShowLeakDetectionNotificationExpectation(IsSaved(false), IsReused(true));
+ EXPECT_CALL(*store_, AddCompromisedCredentialsImpl)
+ .Times(base::FeatureList::IsEnabled(features::kPasswordCheck));
InitiateGetCredentialLeakType();
}
diff --git a/chromium/components/password_manager/core/browser/leak_detection_delegate_unittest.cc b/chromium/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
index edea5aa94bc..40c50661b59 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
@@ -40,7 +40,7 @@ using testing::WithArg;
autofill::PasswordForm CreateTestForm() {
autofill::PasswordForm form;
- form.origin = GURL("http://www.example.com/a/LoginAuth");
+ form.url = GURL("http://www.example.com/a/LoginAuth");
form.username_value = ASCIIToUTF16("Adam");
form.password_value = ASCIIToUTF16("p4ssword");
form.signon_realm = "http://www.example.com/";
@@ -164,7 +164,7 @@ TEST_F(LeakDetectionDelegateTest, StartCheck) {
EXPECT_CALL(client(), IsIncognito).WillOnce(Return(false));
auto check_instance = std::make_unique<MockLeakDetectionCheck>();
EXPECT_CALL(*check_instance,
- Start(form.origin, form.username_value, form.password_value));
+ Start(form.url, form.username_value, form.password_value));
EXPECT_CALL(factory(), TryCreateLeakCheck(&delegate(), _, _))
.WillOnce(Return(ByMove(std::move(check_instance))));
delegate().StartLeakCheck(form);
@@ -190,7 +190,7 @@ TEST_F(LeakDetectionDelegateTest, StartCheckWithStandardProtection) {
EXPECT_CALL(client(), IsIncognito).WillOnce(Return(false));
auto check_instance = std::make_unique<MockLeakDetectionCheck>();
EXPECT_CALL(*check_instance,
- Start(form.origin, form.username_value, form.password_value));
+ Start(form.url, form.username_value, form.password_value));
EXPECT_CALL(factory(), TryCreateLeakCheck(&delegate(), _, _))
.WillOnce(Return(ByMove(std::move(check_instance))));
delegate().StartLeakCheck(form);
@@ -209,7 +209,7 @@ TEST_F(LeakDetectionDelegateTest, StartCheckWithEnhancedProtection) {
EXPECT_CALL(client(), IsIncognito).WillOnce(Return(false));
auto check_instance = std::make_unique<MockLeakDetectionCheck>();
EXPECT_CALL(*check_instance,
- Start(form.origin, form.username_value, form.password_value));
+ Start(form.url, form.username_value, form.password_value));
EXPECT_CALL(factory(), TryCreateLeakCheck(&delegate(), _, _))
.WillOnce(Return(ByMove(std::move(check_instance))));
delegate().StartLeakCheck(form);
@@ -256,12 +256,47 @@ TEST_F(LeakDetectionDelegateTest, LeakDetectionDoneWithFalseResult) {
EXPECT_CALL(client(), NotifyUserCredentialsWereLeaked).Times(0);
delegate_interface->OnLeakDetectionDone(
- /*is_leaked=*/false, form.origin, form.username_value,
- form.password_value);
+ /*is_leaked=*/false, form.url, form.username_value, form.password_value);
histogram_tester.ExpectTotalCount(
"PasswordManager.LeakDetection.NotifyIsLeakedTime", 0);
}
+TEST_F(LeakDetectionDelegateTest,
+ LeakDetectionWithForcedDialogAfterEverySuccessfulSubmission) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ features::kPasswordChange,
+ {{features::kPasswordChangeWithForcedDialogAfterEverySuccessfulSubmission,
+ "true"}});
+
+ EXPECT_TRUE(base::GetFieldTrialParamByFeatureAsBool(
+ password_manager::features::kPasswordChange,
+ password_manager::features::
+ kPasswordChangeWithForcedDialogAfterEverySuccessfulSubmission,
+ false));
+
+ LeakDetectionDelegateInterface* delegate_interface = &delegate();
+ const autofill::PasswordForm form = CreateTestForm();
+
+ EXPECT_CALL(client(), GetProfilePasswordStore())
+ .WillRepeatedly(testing::Return(store()));
+ EXPECT_CALL(*store(), FillMatchingLoginsByPassword);
+ EXPECT_CALL(factory(), TryCreateLeakCheck)
+ .WillOnce(
+ Return(ByMove(std::make_unique<NiceMock<MockLeakDetectionCheck>>())));
+ delegate().StartLeakCheck(form);
+
+ EXPECT_CALL(client(),
+ NotifyUserCredentialsWereLeaked(
+ password_manager::CreateLeakType(
+ IsSaved(false), IsReused(false), IsSyncing(false)),
+ form.url, form.username_value));
+
+ delegate_interface->OnLeakDetectionDone(
+ /*is_leaked=*/false, form.url, form.username_value, form.password_value);
+ WaitForPasswordStore();
+}
+
TEST_F(LeakDetectionDelegateTest, LeakDetectionDoneWithTrueResult) {
base::HistogramTester histogram_tester;
LeakDetectionDelegateInterface* delegate_interface = &delegate();
@@ -279,10 +314,9 @@ TEST_F(LeakDetectionDelegateTest, LeakDetectionDoneWithTrueResult) {
NotifyUserCredentialsWereLeaked(
password_manager::CreateLeakType(
IsSaved(false), IsReused(false), IsSyncing(false)),
- form.origin, form.username_value));
+ form.url, form.username_value));
delegate_interface->OnLeakDetectionDone(
- /*is_leaked=*/true, form.origin, form.username_value,
- form.password_value);
+ /*is_leaked=*/true, form.url, form.username_value, form.password_value);
WaitForPasswordStore();
histogram_tester.ExpectTotalCount(
"PasswordManager.LeakDetection.NotifyIsLeakedTime", 1);
@@ -305,14 +339,13 @@ TEST_F(LeakDetectionDelegateTest, LeakHistoryAddCredentials) {
Return(ByMove(std::make_unique<NiceMock<MockLeakDetectionCheck>>())));
delegate().StartLeakCheck(form);
- EXPECT_CALL(client(), NotifyUserCredentialsWereLeaked(_, form.origin,
+ EXPECT_CALL(client(), NotifyUserCredentialsWereLeaked(_, form.url,
form.username_value));
delegate_interface->OnLeakDetectionDone(
- /*is_leaked=*/true, form.origin, form.username_value,
- form.password_value);
+ /*is_leaked=*/true, form.url, form.username_value, form.password_value);
const CompromisedCredentials compromised_credentials = {
- GetSignonRealm(form.origin), form.username_value, base::Time::Now(),
+ GetSignonRealm(form.url), form.username_value, base::Time::Now(),
CompromiseType::kLeaked};
EXPECT_CALL(*store(), AddCompromisedCredentialsImpl(compromised_credentials));
WaitForPasswordStore();
@@ -334,8 +367,7 @@ TEST_F(LeakDetectionDelegateTest, CallStartTwice) {
// The delegate analyses the password store after this call.
LeakDetectionDelegateInterface* delegate_interface = &delegate();
delegate_interface->OnLeakDetectionDone(
- /*is_leaked=*/true, form.origin, form.username_value,
- form.password_value);
+ /*is_leaked=*/true, form.url, form.username_value, form.password_value);
// Start the check again on another form in the mean time.
check_instance = std::make_unique<NiceMock<MockLeakDetectionCheck>>();
@@ -352,8 +384,7 @@ TEST_F(LeakDetectionDelegateTest, CallStartTwice) {
// The second check is finishing and talking to the password store. It should
// not crash.
delegate_interface->OnLeakDetectionDone(
- /*is_leaked=*/true, form.origin, form.username_value,
- form.password_value);
+ /*is_leaked=*/true, form.url, form.username_value, form.password_value);
WaitForPasswordStore();
}
diff --git a/chromium/components/password_manager/core/browser/leak_detection_dialog_utils.cc b/chromium/components/password_manager/core/browser/leak_detection_dialog_utils.cc
index c0db868c259..f3b9ac7495b 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_dialog_utils.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection_dialog_utils.cc
@@ -4,6 +4,7 @@
#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
+#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
@@ -55,8 +56,17 @@ base::string16 GetFormattedUrl(const GURL& origin) {
}
base::string16 GetAcceptButtonLabel(CredentialLeakType leak_type) {
- return l10n_util::GetStringUTF16(
- ShouldCheckPasswords(leak_type) ? IDS_LEAK_CHECK_CREDENTIALS : IDS_OK);
+ // |ShouldShowChangePasswordButton()| and |ShouldCheckPasswords()| are not
+ // both true at the same time.
+ if (ShouldCheckPasswords(leak_type)) {
+ return l10n_util::GetStringUTF16(IDS_LEAK_CHECK_CREDENTIALS);
+ }
+
+ if (ShouldShowChangePasswordButton(leak_type)) {
+ return l10n_util::GetStringUTF16(IDS_PASSWORD_CHANGE);
+ }
+
+ return l10n_util::GetStringUTF16(IDS_OK);
}
base::string16 GetCancelButtonLabel() {
@@ -97,8 +107,27 @@ bool ShouldCheckPasswords(CredentialLeakType leak_type) {
password_manager::IsSyncingPasswordsNormally(leak_type);
}
+bool ShouldShowChangePasswordButton(CredentialLeakType leak_type) {
+ if (!base::FeatureList::IsEnabled(
+ password_manager::features::kPasswordChange)) {
+ return false;
+ }
+
+ // Password change should be offered if all following conditions are
+ // fulfilled:
+ // - password is saved (The password change flows will automatically save the
+ // password. This should only happen as an update of an existing entry.)
+ // - sync is on (because the password change flow relies on password
+ // generation which is only available to sync users).
+ // - password is not used on the other sites (TODO(crbug/1086114): to be
+ // removed when we have proper UI).
+ return IsPasswordSaved(leak_type) && !IsPasswordUsedOnOtherSites(leak_type) &&
+ IsSyncingPasswordsNormally(leak_type);
+}
+
bool ShouldShowCancelButton(CredentialLeakType leak_type) {
- return ShouldCheckPasswords(leak_type);
+ return ShouldCheckPasswords(leak_type) ||
+ ShouldShowChangePasswordButton(leak_type);
}
LeakDialogType GetLeakDialogType(CredentialLeakType leak_type) {
diff --git a/chromium/components/password_manager/core/browser/leak_detection_dialog_utils.h b/chromium/components/password_manager/core/browser/leak_detection_dialog_utils.h
index 2702e708955..bb907274f12 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_dialog_utils.h
+++ b/chromium/components/password_manager/core/browser/leak_detection_dialog_utils.h
@@ -74,6 +74,9 @@ base::string16 GetLeakDetectionTooltip();
// Checks whether the leak dialog should prompt user to password checkup.
bool ShouldCheckPasswords(password_manager::CredentialLeakType leak_type);
+// Checks whether the leak dialog should show change password button.
+bool ShouldShowChangePasswordButton(CredentialLeakType leak_type);
+
// Checks whether the leak dialog should show cancel button.
bool ShouldShowCancelButton(password_manager::CredentialLeakType leak_type);
diff --git a/chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc b/chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc
index 0aea00c147c..861ec2ae9d8 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc
@@ -6,6 +6,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/strings/grit/components_strings.h"
#include "components/url_formatter/elide_url.h"
@@ -198,4 +199,69 @@ INSTANTIATE_TEST_SUITE_P(InstantiationName,
BulkCheckCredentialLeakDialogUtilsTest,
testing::ValuesIn(kBulkCheckTestCases));
+#if defined(OS_ANDROID)
+struct PasswordChangeParams {
+ // Specifies the test case.
+ CredentialLeakType leak_type;
+ int accept_button_id;
+ bool should_show_cancel_button;
+ bool should_show_change_password_button;
+} kPasswordChangeTestCases[] = {
+ {CreateLeakType(IsSaved(false), IsReused(false), IsSyncing(false)), IDS_OK,
+ false, false},
+ {CreateLeakType(IsSaved(false), IsReused(false), IsSyncing(true)), IDS_OK,
+ false, false},
+ {CreateLeakType(IsSaved(false), IsReused(true), IsSyncing(false)), IDS_OK,
+ false, false},
+ {CreateLeakType(IsSaved(false), IsReused(true), IsSyncing(true)),
+ IDS_LEAK_CHECK_CREDENTIALS, true, false},
+ {CreateLeakType(IsSaved(true), IsReused(false), IsSyncing(false)), IDS_OK,
+ false, false},
+ {CreateLeakType(IsSaved(true), IsReused(false), IsSyncing(true)),
+ IDS_PASSWORD_CHANGE, true, true},
+ {CreateLeakType(IsSaved(true), IsReused(true), IsSyncing(false)), IDS_OK,
+ false, false},
+ {CreateLeakType(IsSaved(true), IsReused(true), IsSyncing(true)),
+ IDS_LEAK_CHECK_CREDENTIALS, true, false}};
+
+class PasswordChangeCredentialLeakDialogUtilsTest
+ : public testing::TestWithParam<PasswordChangeParams> {
+ public:
+ PasswordChangeCredentialLeakDialogUtilsTest() {
+ feature_list_.InitAndEnableFeature(features::kPasswordChange);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_P(PasswordChangeCredentialLeakDialogUtilsTest,
+ ShouldShowChangePasswordButton) {
+ SCOPED_TRACE(testing::Message() << GetParam().leak_type);
+
+ // ShouldCheckPasswords and ShouldShowChangePasswordButton
+ // should never be true both.
+ EXPECT_FALSE(ShouldCheckPasswords(GetParam().leak_type) &&
+ ShouldShowChangePasswordButton(GetParam().leak_type));
+
+ EXPECT_EQ(GetParam().should_show_change_password_button,
+ ShouldShowChangePasswordButton(GetParam().leak_type));
+}
+
+TEST_P(PasswordChangeCredentialLeakDialogUtilsTest, ShouldShowCancelButton) {
+ SCOPED_TRACE(testing::Message() << GetParam().leak_type);
+ EXPECT_EQ(GetParam().should_show_cancel_button,
+ ShouldShowCancelButton(GetParam().leak_type));
+}
+
+TEST_P(PasswordChangeCredentialLeakDialogUtilsTest, GetAcceptButtonLabel) {
+ SCOPED_TRACE(testing::Message() << GetParam().leak_type);
+ EXPECT_EQ(l10n_util::GetStringUTF16(GetParam().accept_button_id),
+ GetAcceptButtonLabel(GetParam().leak_type));
+}
+
+INSTANTIATE_TEST_SUITE_P(InstantiationName,
+ PasswordChangeCredentialLeakDialogUtilsTest,
+ testing::ValuesIn(kPasswordChangeTestCases));
+#endif
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/login_database.cc b/chromium/components/password_manager/core/browser/login_database.cc
index a4f62f50250..73c22b24e1d 100644
--- a/chromium/components/password_manager/core/browser/login_database.cc
+++ b/chromium/components/password_manager/core/browser/login_database.cc
@@ -66,9 +66,9 @@ const int kCompatibleVersionNumber = 19;
base::Pickle SerializeValueElementPairs(
const autofill::ValueElementVector& vec) {
base::Pickle p;
- for (size_t i = 0; i < vec.size(); ++i) {
- p.WriteString16(vec[i].first);
- p.WriteString16(vec[i].second);
+ for (const auto& pair : vec) {
+ p.WriteString16(pair.first);
+ p.WriteString16(pair.second);
}
return p;
}
@@ -199,7 +199,7 @@ struct SQLTableBuilders {
};
void BindAddStatement(const PasswordForm& form, sql::Statement* s) {
- s->BindString(COLUMN_ORIGIN_URL, form.origin.spec());
+ s->BindString(COLUMN_ORIGIN_URL, form.url.spec());
s->BindString(COLUMN_ACTION_URL, form.action.spec());
s->BindString16(COLUMN_USERNAME_ELEMENT, form.username_element);
s->BindString16(COLUMN_USERNAME_VALUE, form.username_value);
@@ -251,7 +251,7 @@ void AddCallback(int* output_err, int err, sql::Statement* /*stmt*/) {
}
bool DoesMatchConstraints(const PasswordForm& form) {
- if (!IsValidAndroidFacetURI(form.signon_realm) && form.origin.is_empty()) {
+ if (!IsValidAndroidFacetURI(form.signon_realm) && form.url.is_empty()) {
DLOG(ERROR) << "Constraint violation: form.origin is empty";
return false;
}
@@ -279,10 +279,13 @@ void LogTimesUsedStat(const std::string& name, int sample) {
base::UmaHistogramCustomCounts(name, sample, 0, 100, 10);
}
-void LogNumberOfAccountsForScheme(const std::string& scheme, int sample) {
+void LogNumberOfAccountsForScheme(base::StringPiece suffix_for_store,
+ const std::string& scheme,
+ int sample) {
base::UmaHistogramCustomCounts(
- "PasswordManager.TotalAccountsHiRes.WithScheme." + scheme, sample, 1,
- 1000, 100);
+ base::StrCat({kPasswordManager, suffix_for_store,
+ ".TotalAccountsHiRes.WithScheme.", scheme}),
+ sample, 1, 1000, 100);
}
bool ClearAllSyncMetadata(sql::Database* db) {
@@ -602,7 +605,7 @@ std::string GeneratePlaceholders(size_t count) {
// and returns it.
PasswordForm GetFormForRemoval(const sql::Statement& statement) {
PasswordForm form;
- form.origin = GURL(statement.ColumnString(COLUMN_ORIGIN_URL));
+ form.url = GURL(statement.ColumnString(COLUMN_ORIGIN_URL));
form.username_element = statement.ColumnString16(COLUMN_USERNAME_ELEMENT);
form.username_value = statement.ColumnString16(COLUMN_USERNAME_VALUE);
form.password_element = statement.ColumnString16(COLUMN_PASSWORD_ELEMENT);
@@ -612,6 +615,12 @@ PasswordForm GetFormForRemoval(const sql::Statement& statement) {
} // namespace
+struct LoginDatabase::PrimaryKeyAndPassword {
+ int primary_key;
+ std::string encrypted_password;
+ base::string16 decrypted_password;
+};
+
LoginDatabase::LoginDatabase(const base::FilePath& db_path,
IsAccountStore is_account_store)
: db_path_(db_path), is_account_store_(is_account_store) {}
@@ -866,7 +875,7 @@ void LoginDatabase::ReportNumberOfAccountsMetrics(
blacklisted_sites);
}
-void LoginDatabase::RecordTimesPasswordUsedMetrics(
+void LoginDatabase::ReportTimesPasswordUsedMetrics(
bool custom_passphrase_sync_enabled) {
sql::Statement usage_statement(db_.GetCachedStatement(
SQL_FROM_HERE, "SELECT password_type, times_used FROM logins"));
@@ -939,8 +948,10 @@ void LoginDatabase::ReportEmptyUsernamesMetrics() {
"WHERE blacklisted_by_user=0 AND username_value=''"));
if (empty_usernames_statement.Step()) {
int empty_forms = empty_usernames_statement.ColumnInt(0);
- UMA_HISTOGRAM_COUNTS_100("PasswordManager.EmptyUsernames.CountInDatabase",
- empty_forms);
+ base::UmaHistogramCounts100(
+ base::StrCat({kPasswordManager, GetMetricsSuffixForStore(),
+ ".EmptyUsernames.CountInDatabase"}),
+ empty_forms);
}
}
@@ -977,11 +988,13 @@ void LoginDatabase::ReportLoginsWithSchemesMetrics() {
}
}
- LogNumberOfAccountsForScheme("Android", android_logins);
- LogNumberOfAccountsForScheme("Ftp", ftp_logins);
- LogNumberOfAccountsForScheme("Http", http_logins);
- LogNumberOfAccountsForScheme("Https", https_logins);
- LogNumberOfAccountsForScheme("Other", other_logins);
+ base::StringPiece suffix_for_store = GetMetricsSuffixForStore();
+
+ LogNumberOfAccountsForScheme(suffix_for_store, "Android", android_logins);
+ LogNumberOfAccountsForScheme(suffix_for_store, "Ftp", ftp_logins);
+ LogNumberOfAccountsForScheme(suffix_for_store, "Http", http_logins);
+ LogNumberOfAccountsForScheme(suffix_for_store, "Https", https_logins);
+ LogNumberOfAccountsForScheme(suffix_for_store, "Other", other_logins);
}
void LoginDatabase::ReportBubbleSuppressionMetrics() {
@@ -1015,8 +1028,10 @@ void LoginDatabase::ReportInaccessiblePasswordsMetrics() {
++failed_encryption;
}
}
- UMA_HISTOGRAM_COUNTS_100("PasswordManager.InaccessiblePasswords",
- failed_encryption);
+ base::UmaHistogramCounts100(
+ base::StrCat({kPasswordManager, GetMetricsSuffixForStore(),
+ ".InaccessiblePasswords"}),
+ failed_encryption);
}
void LoginDatabase::ReportDuplicateCredentialsMetrics() {
@@ -1083,20 +1098,23 @@ void LoginDatabase::ReportMetrics(const std::string& sync_username,
TRACE_EVENT0("passwords", "LoginDatabase::ReportMetrics");
ReportNumberOfAccountsMetrics(custom_passphrase_sync_enabled);
- RecordTimesPasswordUsedMetrics(custom_passphrase_sync_enabled);
+ ReportLoginsWithSchemesMetrics();
+ ReportTimesPasswordUsedMetrics(custom_passphrase_sync_enabled);
+ ReportEmptyUsernamesMetrics();
+ ReportInaccessiblePasswordsMetrics();
- // TODO(crbug.com/1063852): For now, don't record the remaining metrics for
- // the account store, so as to not break the existing profile store metrics.
- // Ultimately, many of these metrics should be recorded for both stores, but
- // split into separate histograms.
+ // The remaining metrics are not recorded for the account store:
+ // - SyncingAccountState just doesn't make sense, since syncing users only use
+ // the profile store.
+ // - BubbleSuppression fields aren't used in the account store.
+ // - DuplicateCredentials *could* be recorded for the profile store, but are
+ // not very critical.
+ // - Compromised credentials are only stored in the profile store.
if (is_account_store_.value())
return;
ReportSyncingAccountStateMetrics(sync_username);
- ReportEmptyUsernamesMetrics();
- ReportLoginsWithSchemesMetrics();
ReportBubbleSuppressionMetrics();
- ReportInaccessiblePasswordsMetrics();
ReportDuplicateCredentialsMetrics();
compromised_credentials_table_.ReportMetrics(bulk_check_done);
@@ -1145,15 +1163,16 @@ PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form,
// Repeat the same statement but with REPLACE semantic.
sqlite_error_code = 0;
DCHECK(!add_replace_statement_.empty());
- const std::string encrpyted_old_password = GetEncryptedPassword(form);
- bool password_changed = !encrpyted_old_password.empty() &&
- encrpyted_old_password != encrypted_password;
- int old_primary_key = GetPrimaryKey(form);
+ PrimaryKeyAndPassword old_primary_key_password =
+ GetPrimaryKeyAndPassword(form);
+ bool password_changed =
+ form.password_value != old_primary_key_password.decrypted_password;
s.Assign(
db_.GetCachedStatement(SQL_FROM_HERE, add_replace_statement_.c_str()));
BindAddStatement(form_with_encrypted_password, &s);
if (s.Run()) {
- list.emplace_back(PasswordStoreChange::REMOVE, form, old_primary_key);
+ list.emplace_back(PasswordStoreChange::REMOVE, form,
+ old_primary_key_password.primary_key);
list.emplace_back(PasswordStoreChange::ADD,
std::move(form_with_encrypted_password),
db_.GetLastInsertRowId(), password_changed);
@@ -1183,12 +1202,12 @@ PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form,
return PasswordStoreChangeList();
}
- const std::string encrpyted_old_password = GetEncryptedPassword(form);
- bool password_changed = !encrpyted_old_password.empty() &&
- encrpyted_old_password != encrypted_password;
+ const PrimaryKeyAndPassword old_primary_key_password =
+ GetPrimaryKeyAndPassword(form);
#if defined(OS_IOS)
- DeleteEncryptedPassword(form);
+ DeleteEncryptedPasswordFromKeychain(
+ old_primary_key_password.encrypted_password);
#endif
DCHECK(!update_statement_.empty());
sql::Statement s(
@@ -1230,7 +1249,7 @@ PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form,
// If so, add new field below.
// WHERE starts here.
- s.BindString(next_param++, form.origin.spec());
+ s.BindString(next_param++, form.url.spec());
s.BindString16(next_param++, form.username_element);
s.BindString16(next_param++, form.username_value);
s.BindString16(next_param++, form.password_element);
@@ -1247,11 +1266,13 @@ PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form,
PasswordStoreChangeList list;
if (db_.GetLastChangeCount()) {
+ bool password_changed =
+ form.password_value != old_primary_key_password.decrypted_password;
PasswordForm form_with_encrypted_password = form;
form_with_encrypted_password.encrypted_password = encrypted_password;
list.emplace_back(PasswordStoreChange::UPDATE,
std::move(form_with_encrypted_password),
- GetPrimaryKey(form), password_changed);
+ old_primary_key_password.primary_key, password_changed);
} else if (error) {
*error = UpdateLoginError::kNoUpdatedRecords;
}
@@ -1265,15 +1286,17 @@ bool LoginDatabase::RemoveLogin(const PasswordForm& form,
if (changes) {
changes->clear();
}
+ const PrimaryKeyAndPassword old_primary_key_password =
+ GetPrimaryKeyAndPassword(form);
#if defined(OS_IOS)
- DeleteEncryptedPassword(form);
+ DeleteEncryptedPasswordFromKeychain(
+ old_primary_key_password.encrypted_password);
#endif
// Remove a login by UNIQUE-constrained fields.
DCHECK(!delete_statement_.empty());
- int primary_key = GetPrimaryKey(form);
sql::Statement s(
db_.GetCachedStatement(SQL_FROM_HERE, delete_statement_.c_str()));
- s.BindString(0, form.origin.spec());
+ s.BindString(0, form.url.spec());
s.BindString16(1, form.username_element);
s.BindString16(2, form.username_value);
s.BindString16(3, form.password_element);
@@ -1283,7 +1306,8 @@ bool LoginDatabase::RemoveLogin(const PasswordForm& form,
return false;
}
if (changes) {
- changes->emplace_back(PasswordStoreChange::REMOVE, form, primary_key,
+ changes->emplace_back(PasswordStoreChange::REMOVE, form,
+ old_primary_key_password.primary_key,
/*password_changed=*/true);
}
return true;
@@ -1341,7 +1365,7 @@ bool LoginDatabase::RemoveLoginsCreatedBetween(
#if defined(OS_IOS)
for (const auto& pair : key_to_form_map) {
- DeleteEncryptedPassword(*pair.second);
+ DeleteEncryptedPasswordById(pair.first);
}
#endif
@@ -1408,7 +1432,7 @@ LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
*primary_key = s.ColumnInt(COLUMN_ID);
std::string tmp = s.ColumnString(COLUMN_ORIGIN_URL);
- form->origin = GURL(tmp);
+ form->url = GURL(tmp);
tmp = s.ColumnString(COLUMN_ACTION_URL);
form->action = GURL(tmp);
form->username_element = s.ColumnString16(COLUMN_USERNAME_ELEMENT);
@@ -1537,7 +1561,7 @@ bool LoginDatabase::GetLogins(
}
} else if (should_federated_apply) {
std::string expression =
- base::StringPrintf("federation://%s/%%", form.origin.host().c_str());
+ base::StringPrintf("federation://%s/%%", form.url.host().c_str());
s.BindString(placeholder++, expression);
}
@@ -1720,26 +1744,6 @@ DatabaseCleanupResult LoginDatabase::DeleteUndecryptableLogins() {
return DatabaseCleanupResult::kSuccess;
}
-std::string LoginDatabase::GetEncryptedPassword(
- const PasswordForm& form) const {
- TRACE_EVENT0("passwords", "LoginDatabase::GetEncryptedPassword");
- DCHECK(!encrypted_statement_.empty());
- sql::Statement s(
- db_.GetCachedStatement(SQL_FROM_HERE, encrypted_statement_.c_str()));
-
- s.BindString(0, form.origin.spec());
- s.BindString16(1, form.username_element);
- s.BindString16(2, form.username_value);
- s.BindString16(3, form.password_element);
- s.BindString(4, form.signon_realm);
-
- std::string encrypted_password;
- if (s.Step()) {
- s.ColumnBlobAsString(0, &encrypted_password);
- }
- return encrypted_password;
-}
-
std::unique_ptr<syncer::MetadataBatch> LoginDatabase::GetAllSyncMetadata() {
TRACE_EVENT0("passwords", "LoginDatabase::GetAllSyncMetadata");
std::unique_ptr<syncer::MetadataBatch> metadata_batch =
@@ -1760,7 +1764,15 @@ std::unique_ptr<syncer::MetadataBatch> LoginDatabase::GetAllSyncMetadata() {
void LoginDatabase::DeleteAllSyncMetadata() {
TRACE_EVENT0("passwords", "LoginDatabase::DeleteAllSyncMetadata");
+ bool had_unsynced_deletions = HasUnsyncedDeletions();
ClearAllSyncMetadata(&db_);
+ if (had_unsynced_deletions && deletions_have_synced_callback_) {
+ // Note: At this point we can't be fully sure whether the deletions actually
+ // reached the server yet. We might have sent a commit, but haven't received
+ // the commit confirmation. Let's be conservative and assume they haven't
+ // been successfully deleted.
+ deletions_have_synced_callback_.Run(/*success=*/false);
+ }
}
bool LoginDatabase::UpdateSyncMetadata(
@@ -1792,7 +1804,13 @@ bool LoginDatabase::UpdateSyncMetadata(
s.BindInt(0, storage_key_int);
s.BindString(1, encrypted_metadata);
- return s.Run();
+ bool had_unsynced_deletions = HasUnsyncedDeletions();
+ bool result = s.Run();
+ if (result && had_unsynced_deletions && !HasUnsyncedDeletions() &&
+ deletions_have_synced_callback_) {
+ deletions_have_synced_callback_.Run(/*success=*/true);
+ }
+ return result;
}
bool LoginDatabase::ClearSyncMetadata(syncer::ModelType model_type,
@@ -1813,7 +1831,13 @@ bool LoginDatabase::ClearSyncMetadata(syncer::ModelType model_type,
"storage_key=?"));
s.BindInt(0, storage_key_int);
- return s.Run();
+ bool had_unsynced_deletions = HasUnsyncedDeletions();
+ bool result = s.Run();
+ if (result && had_unsynced_deletions && !HasUnsyncedDeletions() &&
+ deletions_have_synced_callback_) {
+ deletions_have_synced_callback_.Run(/*success=*/true);
+ }
+ return result;
}
bool LoginDatabase::UpdateModelTypeState(
@@ -1843,6 +1867,26 @@ bool LoginDatabase::ClearModelTypeState(syncer::ModelType model_type) {
return s.Run();
}
+void LoginDatabase::SetDeletionsHaveSyncedCallback(
+ base::RepeatingCallback<void(bool)> callback) {
+ deletions_have_synced_callback_ = std::move(callback);
+}
+
+bool LoginDatabase::HasUnsyncedDeletions() {
+ TRACE_EVENT0("passwords", "LoginDatabase::HasUnsyncedDeletions");
+
+ std::unique_ptr<syncer::MetadataBatch> batch = GetAllSyncEntityMetadata();
+ if (!batch)
+ return false;
+ for (const auto& metadata_entry : batch->GetAllMetadata()) {
+ // Note: No need for an explicit "is unsynced" check: Once the deletion is
+ // committed, the metadata entry is removed.
+ if (metadata_entry.second->is_deleted())
+ return true;
+ }
+ return false;
+}
+
bool LoginDatabase::BeginTransaction() {
TRACE_EVENT0("passwords", "LoginDatabase::BeginTransaction");
return db_.BeginTransaction();
@@ -1858,21 +1902,29 @@ bool LoginDatabase::CommitTransaction() {
return db_.CommitTransaction();
}
-int LoginDatabase::GetPrimaryKey(const PasswordForm& form) const {
- DCHECK(!id_statement_.empty());
- sql::Statement s(
- db_.GetCachedStatement(SQL_FROM_HERE, id_statement_.c_str()));
+LoginDatabase::PrimaryKeyAndPassword LoginDatabase::GetPrimaryKeyAndPassword(
+ const PasswordForm& form) const {
+ DCHECK(!id_and_password_statement_.empty());
+ sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
+ id_and_password_statement_.c_str()));
- s.BindString(0, form.origin.spec());
+ s.BindString(0, form.url.spec());
s.BindString16(1, form.username_element);
s.BindString16(2, form.username_value);
s.BindString16(3, form.password_element);
s.BindString(4, form.signon_realm);
if (s.Step()) {
- return s.ColumnInt(0);
+ PrimaryKeyAndPassword result = {s.ColumnInt(0)};
+ s.ColumnBlobAsString(1, &result.encrypted_password);
+ if (DecryptedString(result.encrypted_password,
+ &result.decrypted_password) !=
+ ENCRYPTION_RESULT_SUCCESS) {
+ result.decrypted_password.clear();
+ }
+ return result;
}
- return -1;
+ return {-1, std::string(), base::string16()};
}
std::unique_ptr<syncer::MetadataBatch>
@@ -1979,20 +2031,10 @@ FormRetrievalResult LoginDatabase::StatementToForms(
count_removed_logins++;
}
}
-
- if (count_removed_logins > 0) {
- UMA_HISTOGRAM_COUNTS_100("PasswordManager.RemovedCorruptedPasswords",
- count_removed_logins);
- }
-
- if (count_removed_logins != forms_to_be_deleted.size()) {
- metrics_util::LogDeleteCorruptedPasswordsResult(
- metrics_util::DeleteCorruptedPasswordsResult::kItemFailure);
- } else if (count_removed_logins > 0) {
+ if (count_removed_logins == forms_to_be_deleted.size() &&
+ count_removed_logins > 0) {
DCHECK(password_recovery_util_);
password_recovery_util_->RecordPasswordRecovery();
- metrics_util::LogDeleteCorruptedPasswordsResult(
- metrics_util::DeleteCorruptedPasswordsResult::kSuccessPasswordsDeleted);
}
#endif
@@ -2059,14 +2101,12 @@ void LoginDatabase::InitializeStatementStrings(const SQLTableBuilder& builder) {
blacklisted_statement_ =
"SELECT " + all_column_names +
" FROM logins WHERE blacklisted_by_user == ? ORDER BY origin_url";
- DCHECK(encrypted_statement_.empty());
- encrypted_statement_ =
- "SELECT password_value FROM logins WHERE " + all_unique_key_column_names;
DCHECK(encrypted_password_statement_by_id_.empty());
encrypted_password_statement_by_id_ =
"SELECT password_value FROM logins WHERE id=?";
- DCHECK(id_statement_.empty());
- id_statement_ = "SELECT id FROM logins WHERE " + all_unique_key_column_names;
+ DCHECK(id_and_password_statement_.empty());
+ id_and_password_statement_ = "SELECT id, password_value FROM logins WHERE " +
+ all_unique_key_column_names;
}
bool LoginDatabase::IsUsingCleanupMechanism() const {
diff --git a/chromium/components/password_manager/core/browser/login_database.h b/chromium/components/password_manager/core/browser/login_database.h
index f6f510bbe3d..88fa8f9460f 100644
--- a/chromium/components/password_manager/core/browser/login_database.h
+++ b/chromium/components/password_manager/core/browser/login_database.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/macros.h"
@@ -175,10 +176,6 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
// removed from the database, returns ITEM_FAILURE.
DatabaseCleanupResult DeleteUndecryptableLogins();
- // Returns the encrypted password value for the specified |form|. Returns an
- // empty string if the row for this |form| is not found.
- std::string GetEncryptedPassword(const autofill::PasswordForm& form) const;
-
// PasswordStoreSync::MetadataStore implementation.
std::unique_ptr<syncer::MetadataBatch> GetAllSyncMetadata() override;
void DeleteAllSyncMetadata() override;
@@ -191,6 +188,9 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
syncer::ModelType model_type,
const sync_pb::ModelTypeState& model_type_state) override;
bool ClearModelTypeState(syncer::ModelType model_type) override;
+ void SetDeletionsHaveSyncedCallback(
+ base::RepeatingCallback<void(bool)> callback) override;
+ bool HasUnsyncedDeletions() override;
// Callers that requires transaction support should call these methods to
// begin, rollback and commit transactions. They delegate to the transaction
@@ -214,16 +214,18 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
#endif // defined(OS_POSIX) && !defined(OS_MACOSX)
private:
+ struct PrimaryKeyAndPassword;
#if defined(OS_IOS)
friend class LoginDatabaseIOSTest;
FRIEND_TEST_ALL_PREFIXES(LoginDatabaseIOSTest, KeychainStorage);
- // On iOS, removes the keychain item that is used to store the
- // encrypted password for the supplied |form|.
- void DeleteEncryptedPassword(const autofill::PasswordForm& form);
+ // Removes the keychain item corresponding to the look-up key |cipher_text|.
+ // It's stored as the encrypted password value.
+ static void DeleteEncryptedPasswordFromKeychain(
+ const std::string& cipher_text);
- // Similar to DeleteEncryptedPassword() but uses |id| to look for the
- // password.
+ // On iOS, removes the keychain item that is used to store the encrypted
+ // password for the supplied primary key |id|.
void DeleteEncryptedPasswordById(int id);
// Returns the encrypted password value for the specified |id|. Returns an
@@ -236,7 +238,7 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
base::StringPiece GetMetricsSuffixForStore() const;
void ReportNumberOfAccountsMetrics(bool custom_passphrase_sync_enabled);
- void RecordTimesPasswordUsedMetrics(bool custom_passphrase_sync_enabled);
+ void ReportTimesPasswordUsedMetrics(bool custom_passphrase_sync_enabled);
void ReportSyncingAccountStateMetrics(const std::string& sync_username);
void ReportEmptyUsernamesMetrics();
void ReportLoginsWithSchemesMetrics();
@@ -295,9 +297,10 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
bool blacklisted,
std::vector<std::unique_ptr<autofill::PasswordForm>>* forms);
- // Returns the DB primary key for the specified |form|. Returns -1 if the row
- // for this |form| is not found.
- int GetPrimaryKey(const autofill::PasswordForm& form) const;
+ // Returns the DB primary key for the specified |form| and decrypted/encrypted
+ // password. Returns {-1, "", ""} if the row for this |form| is not found.
+ PrimaryKeyAndPassword GetPrimaryKeyAndPassword(
+ const autofill::PasswordForm& form) const;
// Reads all the stored sync entities metadata in a MetadataBatch. Returns
// nullptr in case of failure.
@@ -349,9 +352,8 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
std::string get_statement_psl_federated_;
std::string created_statement_;
std::string blacklisted_statement_;
- std::string encrypted_statement_;
std::string encrypted_password_statement_by_id_;
- std::string id_statement_;
+ std::string id_and_password_statement_;
#if defined(OS_MACOSX) && !defined(OS_IOS)
std::unique_ptr<PasswordRecoveryUtilMac> password_recovery_util_;
@@ -364,6 +366,12 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
bool use_encryption_ = true;
#endif // defined(OS_POSIX)
+ // A callback to be invoked whenever all pending deletions have been processed
+ // by Sync - see
+ // PasswordStoreSync::MetadataStore::SetDeletionsHaveSyncedCallback for more
+ // details.
+ base::RepeatingCallback<void(bool)> deletions_have_synced_callback_;
+
DISALLOW_COPY_AND_ASSIGN(LoginDatabase);
};
diff --git a/chromium/components/password_manager/core/browser/login_database_ios.cc b/chromium/components/password_manager/core/browser/login_database_ios.cc
index 9fae41caa85..a9d09bb7ae8 100644
--- a/chromium/components/password_manager/core/browser/login_database_ios.cc
+++ b/chromium/components/password_manager/core/browser/login_database_ios.cc
@@ -23,38 +23,6 @@ using autofill::PasswordForm;
namespace password_manager {
-namespace {
-
-void DeleteEncryptedPasswordFromKeychain(const std::string& cipher_text) {
- if (cipher_text.empty())
- return;
-
- ScopedCFTypeRef<CFMutableDictionaryRef> query(
- CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks));
- CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
-
- ScopedCFTypeRef<CFStringRef> item_ref(
- base::SysUTF8ToCFStringRef(cipher_text));
- // We are using the account attribute to store item references.
- CFDictionarySetValue(query, kSecAttrAccount, item_ref);
-
- OSStatus status = SecItemDelete(query);
- if (status != errSecSuccess && status != errSecItemNotFound) {
- NOTREACHED() << "Unable to remove password from keychain: " << status;
- }
-
- // Delete the temporary passwords directory, since there might be leftover
- // temporary files used for password export that contain the password being
- // deleted. It can be called for a removal triggered by sync, which might
- // happen at the same time as an export operation. In the unlikely event
- // that the file is still needed by the consumer app, the export operation
- // will fail.
- password_manager::DeletePasswordsDirectory();
-}
-
-} // namespace
-
// On iOS, the LoginDatabase uses Keychain API to store passwords. The
// "encrypted" version of the password is a unique ID (UUID) that is
// stored as an attribute along with the password in the keychain.
@@ -145,9 +113,34 @@ LoginDatabase::EncryptionResult LoginDatabase::DecryptedString(
return ENCRYPTION_RESULT_SUCCESS;
}
-void LoginDatabase::DeleteEncryptedPassword(const PasswordForm& form) {
- std::string cipher_text = GetEncryptedPassword(form);
- DeleteEncryptedPasswordFromKeychain(cipher_text);
+// static
+void LoginDatabase::DeleteEncryptedPasswordFromKeychain(
+ const std::string& cipher_text) {
+ if (cipher_text.empty())
+ return;
+
+ ScopedCFTypeRef<CFMutableDictionaryRef> query(
+ CFDictionaryCreateMutable(nullptr, 0, &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+ CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
+
+ ScopedCFTypeRef<CFStringRef> item_ref(
+ base::SysUTF8ToCFStringRef(cipher_text));
+ // We are using the account attribute to store item references.
+ CFDictionarySetValue(query, kSecAttrAccount, item_ref);
+
+ OSStatus status = SecItemDelete(query);
+ if (status != errSecSuccess && status != errSecItemNotFound) {
+ NOTREACHED() << "Unable to remove password from keychain: " << status;
+ }
+
+ // Delete the temporary passwords directory, since there might be leftover
+ // temporary files used for password export that contain the password being
+ // deleted. It can be called for a removal triggered by sync, which might
+ // happen at the same time as an export operation. In the unlikely event
+ // that the file is still needed by the consumer app, the export operation
+ // will fail.
+ password_manager::DeletePasswordsDirectory();
}
void LoginDatabase::DeleteEncryptedPasswordById(int id) {
diff --git a/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc b/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
index e79dfc28337..72300f2dc95 100644
--- a/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
+++ b/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
@@ -107,7 +107,7 @@ TEST_F(LoginDatabaseIOSTest, AddLogin) {
ASSERT_EQ(0U, GetKeychainSize());
PasswordForm form;
- form.origin = GURL("http://0.com");
+ form.url = GURL("http://0.com");
form.signon_realm = "http://www.example.com/";
form.action = GURL("http://www.example.com/action");
form.password_element = base::ASCIIToUTF16("pwd");
@@ -136,7 +136,7 @@ TEST_F(LoginDatabaseIOSTest, AddLogin) {
TEST_F(LoginDatabaseIOSTest, UpdateLogin) {
PasswordForm form;
- form.origin = GURL("http://0.com");
+ form.url = GURL("http://0.com");
form.signon_realm = "http://www.example.com";
form.action = GURL("http://www.example.com/action");
form.password_element = base::ASCIIToUTF16("pwd");
@@ -178,19 +178,19 @@ TEST_F(LoginDatabaseIOSTest, RemoveLogin) {
TEST_F(LoginDatabaseIOSTest, RemoveLoginsCreatedBetween) {
PasswordForm forms[3];
- forms[0].origin = GURL("http://0.com");
+ forms[0].url = GURL("http://0.com");
forms[0].signon_realm = "http://www.example.com";
forms[0].username_element = base::ASCIIToUTF16("login0");
forms[0].date_created = base::Time::FromDoubleT(100);
forms[0].password_value = base::ASCIIToUTF16("pass0");
- forms[1].origin = GURL("http://1.com");
+ forms[1].url = GURL("http://1.com");
forms[1].signon_realm = "http://www.example.com";
forms[1].username_element = base::ASCIIToUTF16("login1");
forms[1].date_created = base::Time::FromDoubleT(200);
forms[1].password_value = base::ASCIIToUTF16("pass1");
- forms[2].origin = GURL("http://2.com");
+ forms[2].url = GURL("http://2.com");
forms[2].signon_realm = "http://www.example.com";
forms[2].username_element = base::ASCIIToUTF16("login2");
forms[2].date_created = base::Time::FromDoubleT(300);
diff --git a/chromium/components/password_manager/core/browser/login_database_unittest.cc b/chromium/components/password_manager/core/browser/login_database_unittest.cc
index 5af4423fbe0..d2c03d25779 100644
--- a/chromium/components/password_manager/core/browser/login_database_unittest.cc
+++ b/chromium/components/password_manager/core/browser/login_database_unittest.cc
@@ -71,7 +71,7 @@ PasswordStoreChangeList RemoveChangeForForm(const PasswordForm& form) {
}
void GenerateExamplePasswordForm(PasswordForm* form) {
- form->origin = GURL("http://accounts.google.com/LoginAuth");
+ form->url = GURL("http://accounts.google.com/LoginAuth");
form->action = GURL("http://accounts.google.com/Login");
form->username_element = ASCIIToUTF16("Email");
form->username_value = ASCIIToUTF16("test@gmail.com");
@@ -145,12 +145,12 @@ bool AddZeroClickableLogin(LoginDatabase* db,
const GURL& origin) {
// Example password form.
PasswordForm form;
- form.origin = origin;
+ form.url = origin;
form.username_element = ASCIIToUTF16(unique_string);
form.username_value = ASCIIToUTF16(unique_string);
form.password_element = ASCIIToUTF16(unique_string);
form.submit_element = ASCIIToUTF16("signIn");
- form.signon_realm = form.origin.spec();
+ form.signon_realm = form.url.spec();
form.display_name = ASCIIToUTF16(unique_string);
form.icon_url = origin;
form.federation_origin = url::Origin::Create(origin);
@@ -162,14 +162,14 @@ bool AddZeroClickableLogin(LoginDatabase* db,
}
MATCHER(IsGoogle1Account, "") {
- return arg.origin.spec() == "https://accounts.google.com/ServiceLogin" &&
+ return arg.url.spec() == "https://accounts.google.com/ServiceLogin" &&
arg.action.spec() == "https://accounts.google.com/ServiceLoginAuth" &&
arg.username_value == ASCIIToUTF16("theerikchen") &&
arg.scheme == PasswordForm::Scheme::kHtml;
}
MATCHER(IsGoogle2Account, "") {
- return arg.origin.spec() == "https://accounts.google.com/ServiceLogin" &&
+ return arg.url.spec() == "https://accounts.google.com/ServiceLogin" &&
arg.action.spec() == "https://accounts.google.com/ServiceLoginAuth" &&
arg.username_value == ASCIIToUTF16("theerikchen2") &&
arg.scheme == PasswordForm::Scheme::kHtml;
@@ -209,7 +209,7 @@ class LoginDatabaseTest : public testing::Test {
// Simple non-html auth form.
PasswordForm non_html_auth;
- non_html_auth.origin = GURL("http://example.com");
+ non_html_auth.url = GURL("http://example.com");
non_html_auth.username_value = ASCIIToUTF16("test@gmail.com");
non_html_auth.password_value = ASCIIToUTF16("test");
non_html_auth.signon_realm = "http://example.com/Realm";
@@ -262,7 +262,7 @@ class LoginDatabaseTest : public testing::Test {
std::string origin("http://56.7.8.90");
PasswordForm ip_form;
- ip_form.origin = GURL(origin);
+ ip_form.url = GURL(origin);
ip_form.username_value = ASCIIToUTF16("test@gmail.com");
ip_form.password_value = ASCIIToUTF16("test");
ip_form.signon_realm = origin;
@@ -324,7 +324,7 @@ TEST_F(LoginDatabaseTest, Logins) {
// The example site changes...
PasswordForm form2(form);
- form2.origin = GURL("http://www.google.com/new/accounts/LoginAuth");
+ form2.url = GURL("http://www.google.com/new/accounts/LoginAuth");
form2.submit_element = ASCIIToUTF16("reallySignIn");
// Match against an inexact copy
@@ -486,7 +486,7 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) {
// Example password form.
PasswordForm form;
- form.origin = GURL("https://foo.com/");
+ form.url = GURL("https://foo.com/");
form.action = GURL("https://foo.com/login");
form.username_element = ASCIIToUTF16("username");
form.username_value = ASCIIToUTF16("test@gmail.com");
@@ -509,7 +509,7 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) {
// We go to the mobile site.
PasswordForm form2(form);
- form2.origin = GURL("https://mobile.foo.com/");
+ form2.url = GURL("https://mobile.foo.com/");
form2.action = GURL("https://mobile.foo.com/login");
form2.signon_realm = "https://mobile.foo.com/";
@@ -525,7 +525,7 @@ TEST_F(LoginDatabaseTest, TestFederatedMatching) {
// Example password form.
PasswordForm form;
- form.origin = GURL("https://foo.com/");
+ form.url = GURL("https://foo.com/");
form.action = GURL("https://foo.com/login");
form.username_value = ASCIIToUTF16("test@gmail.com");
form.password_value = ASCIIToUTF16("test");
@@ -534,7 +534,7 @@ TEST_F(LoginDatabaseTest, TestFederatedMatching) {
// We go to the mobile site.
PasswordForm form2(form);
- form2.origin = GURL("https://mobile.foo.com/");
+ form2.url = GURL("https://mobile.foo.com/");
form2.action = GURL("https://mobile.foo.com/login");
form2.signon_realm = "federation://mobile.foo.com/accounts.google.com";
form2.username_value = ASCIIToUTF16("test1@gmail.com");
@@ -563,7 +563,7 @@ TEST_F(LoginDatabaseTest, TestFederatedMatching) {
EXPECT_THAT(result, UnorderedElementsAre(Pointee(form), Pointee(form2)));
// Match against the mobile site.
- form_request.origin = GURL("https://mobile.foo.com/");
+ form_request.url = GURL("https://mobile.foo.com/");
form_request.signon_realm = "https://mobile.foo.com/";
EXPECT_TRUE(db().GetLogins(form_request, &result));
// Both forms are matched, only form is a PSL match.
@@ -574,7 +574,7 @@ TEST_F(LoginDatabaseTest, TestFederatedMatching) {
TEST_F(LoginDatabaseTest, TestFederatedMatchingLocalhost) {
PasswordForm form;
- form.origin = GURL("http://localhost/");
+ form.url = GURL("http://localhost/");
form.signon_realm = "federation://localhost/accounts.google.com";
form.federation_origin =
url::Origin::Create(GURL("https://accounts.google.com/"));
@@ -583,7 +583,7 @@ TEST_F(LoginDatabaseTest, TestFederatedMatchingLocalhost) {
form.scheme = PasswordForm::Scheme::kHtml;
PasswordForm form_with_port(form);
- form_with_port.origin = GURL("http://localhost:8080/");
+ form_with_port.url = GURL("http://localhost:8080/");
form_with_port.signon_realm = "federation://localhost/accounts.google.com";
EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
@@ -601,7 +601,7 @@ TEST_F(LoginDatabaseTest, TestFederatedMatchingLocalhost) {
EXPECT_TRUE(db().GetLogins(form_request, &result));
EXPECT_THAT(result, UnorderedElementsAre(Pointee(form)));
- form_request.origin = GURL("http://localhost:8080/");
+ form_request.url = GURL("http://localhost:8080/");
form_request.signon_realm = "http://localhost:8080/";
EXPECT_TRUE(db().GetLogins(form_request, &result));
EXPECT_THAT(result, UnorderedElementsAre(Pointee(form_with_port)));
@@ -638,7 +638,7 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingShouldMatchingApply) {
// Saved password form on Google sign-in page.
PasswordForm form;
- form.origin = GURL("https://accounts.google.com/");
+ form.url = GURL("https://accounts.google.com/");
form.username_value = ASCIIToUTF16("test@gmail.com");
form.password_value = ASCIIToUTF16("test");
form.signon_realm = "https://accounts.google.com/";
@@ -680,7 +680,7 @@ TEST_F(LoginDatabaseTest, TestFederatedMatchingWithoutPSLMatching) {
// Example password form.
PasswordForm form;
- form.origin = GURL("https://accounts.google.com/");
+ form.url = GURL("https://accounts.google.com/");
form.action = GURL("https://accounts.google.com/login");
form.username_value = ASCIIToUTF16("test@gmail.com");
form.password_value = ASCIIToUTF16("test");
@@ -689,7 +689,7 @@ TEST_F(LoginDatabaseTest, TestFederatedMatchingWithoutPSLMatching) {
// We go to a different site on the same domain where PSL is disabled.
PasswordForm form2(form);
- form2.origin = GURL("https://some.other.google.com/");
+ form2.url = GURL("https://some.other.google.com/");
form2.action = GURL("https://some.other.google.com/login");
form2.signon_realm = "federation://some.other.google.com/accounts.google.com";
form2.username_value = ASCIIToUTF16("test1@gmail.com");
@@ -709,12 +709,12 @@ TEST_F(LoginDatabaseTest, TestFederatedMatchingWithoutPSLMatching) {
// Match against the first one.
PasswordStore::FormDigest form_request = {PasswordForm::Scheme::kHtml,
- form.signon_realm, form.origin};
+ form.signon_realm, form.url};
EXPECT_TRUE(db().GetLogins(form_request, &result));
EXPECT_THAT(result, testing::ElementsAre(Pointee(form)));
// Match against the second one.
- form_request.origin = form2.origin;
+ form_request.url = form2.url;
form_request.signon_realm = form2.signon_realm;
EXPECT_TRUE(db().GetLogins(form_request, &result));
form.is_public_suffix_match = true;
@@ -724,7 +724,7 @@ TEST_F(LoginDatabaseTest, TestFederatedMatchingWithoutPSLMatching) {
TEST_F(LoginDatabaseTest, TestFederatedPSLMatching) {
// Save a federated credential for the PSL matched site.
PasswordForm form;
- form.origin = GURL("https://psl.example.com/");
+ form.url = GURL("https://psl.example.com/");
form.action = GURL("https://psl.example.com/login");
form.signon_realm = "federation://psl.example.com/accounts.google.com";
form.username_value = ASCIIToUTF16("test1@gmail.com");
@@ -759,7 +759,7 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
// Example password form.
PasswordForm form;
- form.origin = GURL("https://foo.com/");
+ form.url = GURL("https://foo.com/");
form.action = GURL("https://foo.com/login");
form.username_element = ASCIIToUTF16("username");
form.username_value = ASCIIToUTF16("test@gmail.com");
@@ -782,7 +782,7 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
// We go to the mobile site.
PasswordStore::FormDigest form2(form);
- form2.origin = GURL("https://mobile.foo.com/");
+ form2.url = GURL("https://mobile.foo.com/");
form2.signon_realm = "https://mobile.foo.com/";
// Match against the mobile site.
@@ -793,7 +793,7 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
result.clear();
// Add baz.com desktop site.
- form.origin = GURL("https://baz.com/login/");
+ form.url = GURL("https://baz.com/login/");
form.action = GURL("https://baz.com/login/");
form.username_element = ASCIIToUTF16("email");
form.username_value = ASCIIToUTF16("test@gmail.com");
@@ -811,7 +811,7 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
// We go to the mobile site of baz.com.
PasswordStore::FormDigest form3(form);
- form3.origin = GURL("https://m.baz.com/login/");
+ form3.url = GURL("https://m.baz.com/login/");
form3.signon_realm = "https://m.baz.com/";
// Match against the mobile site of baz.com.
@@ -825,7 +825,7 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
PasswordForm GetFormWithNewSignonRealm(PasswordForm form,
std::string signon_realm) {
PasswordForm form2(form);
- form2.origin = GURL(signon_realm);
+ form2.url = GURL(signon_realm);
form2.action = GURL(signon_realm);
form2.signon_realm = signon_realm;
return form2;
@@ -840,7 +840,7 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingRegexp) {
// Example password form.
PasswordForm form;
- form.origin = GURL("http://foo.com/");
+ form.url = GURL("http://foo.com/");
form.action = GURL("http://foo.com/login");
form.username_element = ASCIIToUTF16("username");
form.username_value = ASCIIToUTF16("test@gmail.com");
@@ -946,7 +946,7 @@ static bool AddTimestampedLogin(LoginDatabase* db,
bool date_is_creation) {
// Example password form.
PasswordForm form;
- form.origin = GURL(url + std::string("/LoginAuth"));
+ form.url = GURL(url + std::string("/LoginAuth"));
form.username_element = ASCIIToUTF16(unique_string);
form.username_value = ASCIIToUTF16(unique_string);
form.password_element = ASCIIToUTF16(unique_string);
@@ -1083,7 +1083,7 @@ TEST_F(LoginDatabaseTest, DisableAutoSignInForOrigin) {
EXPECT_TRUE(db().DisableAutoSignInForOrigin(origin3));
EXPECT_TRUE(db().GetAutofillableLogins(&result));
for (const auto& form : result) {
- if (form->origin == origin1 || form->origin == origin3)
+ if (form->url == origin1 || form->url == origin3)
EXPECT_TRUE(form->skip_zero_click);
else
EXPECT_FALSE(form->skip_zero_click);
@@ -1099,7 +1099,7 @@ TEST_F(LoginDatabaseTest, BlacklistedLogins) {
// Save a form as blacklisted.
PasswordForm form;
- form.origin = GURL("http://accounts.google.com/LoginAuth");
+ form.url = GURL("http://accounts.google.com/LoginAuth");
form.action = GURL("http://accounts.google.com/Login");
form.username_element = ASCIIToUTF16("Email");
form.password_element = ASCIIToUTF16("Passwd");
@@ -1181,7 +1181,7 @@ TEST_F(LoginDatabaseTest, UpdateIncompleteCredentials) {
// are sometimes inserted during import from other browsers (which may not
// store this info).
PasswordForm incomplete_form;
- incomplete_form.origin = GURL("http://accounts.google.com/LoginAuth");
+ incomplete_form.url = GURL("http://accounts.google.com/LoginAuth");
incomplete_form.signon_realm = "http://accounts.google.com/";
incomplete_form.username_value = ASCIIToUTF16("my_username");
incomplete_form.password_value = ASCIIToUTF16("my_password");
@@ -1192,7 +1192,7 @@ TEST_F(LoginDatabaseTest, UpdateIncompleteCredentials) {
// A form on some website. It should trigger a match with the stored one.
PasswordForm encountered_form;
- encountered_form.origin = GURL("http://accounts.google.com/LoginAuth");
+ encountered_form.url = GURL("http://accounts.google.com/LoginAuth");
encountered_form.signon_realm = "http://accounts.google.com/";
encountered_form.action = GURL("http://accounts.google.com/Login");
encountered_form.username_element = ASCIIToUTF16("Email");
@@ -1203,7 +1203,7 @@ TEST_F(LoginDatabaseTest, UpdateIncompleteCredentials) {
EXPECT_TRUE(
db().GetLogins(PasswordStore::FormDigest(encountered_form), &result));
ASSERT_EQ(1U, result.size());
- EXPECT_EQ(incomplete_form.origin, result[0]->origin);
+ EXPECT_EQ(incomplete_form.url, result[0]->url);
EXPECT_EQ(incomplete_form.signon_realm, result[0]->signon_realm);
EXPECT_EQ(incomplete_form.username_value, result[0]->username_value);
EXPECT_EQ(incomplete_form.password_value, result[0]->password_value);
@@ -1248,7 +1248,7 @@ TEST_F(LoginDatabaseTest, UpdateOverlappingCredentials) {
// are sometimes inserted during import from other browsers (which may not
// store this info).
PasswordForm incomplete_form;
- incomplete_form.origin = GURL("http://accounts.google.com/LoginAuth");
+ incomplete_form.url = GURL("http://accounts.google.com/LoginAuth");
incomplete_form.signon_realm = "http://accounts.google.com/";
incomplete_form.username_value = ASCIIToUTF16("my_username");
incomplete_form.password_value = ASCIIToUTF16("my_password");
@@ -1298,7 +1298,7 @@ TEST_F(LoginDatabaseTest, UpdateOverlappingCredentials) {
TEST_F(LoginDatabaseTest, DoubleAdd) {
PasswordForm form;
- form.origin = GURL("http://accounts.google.com/LoginAuth");
+ form.url = GURL("http://accounts.google.com/LoginAuth");
form.signon_realm = "http://accounts.google.com/";
form.username_value = ASCIIToUTF16("my_username");
form.password_value = ASCIIToUTF16("my_password");
@@ -1317,7 +1317,7 @@ TEST_F(LoginDatabaseTest, DoubleAdd) {
TEST_F(LoginDatabaseTest, AddWrongForm) {
PasswordForm form;
// |origin| shouldn't be empty.
- form.origin = GURL();
+ form.url = GURL();
form.signon_realm = "http://accounts.google.com/";
form.username_value = ASCIIToUTF16("my_username");
form.password_value = ASCIIToUTF16("my_password");
@@ -1326,14 +1326,14 @@ TEST_F(LoginDatabaseTest, AddWrongForm) {
EXPECT_EQ(PasswordStoreChangeList(), db().AddLogin(form));
// |signon_realm| shouldn't be empty.
- form.origin = GURL("http://accounts.google.com/LoginAuth");
+ form.url = GURL("http://accounts.google.com/LoginAuth");
form.signon_realm.clear();
EXPECT_EQ(PasswordStoreChangeList(), db().AddLogin(form));
}
TEST_F(LoginDatabaseTest, UpdateLogin) {
PasswordForm form;
- form.origin = GURL("http://accounts.google.com/LoginAuth");
+ form.url = GURL("http://accounts.google.com/LoginAuth");
form.signon_realm = "http://accounts.google.com/";
form.username_value = ASCIIToUTF16("my_username");
form.password_value = ASCIIToUTF16("my_password");
@@ -1375,10 +1375,48 @@ TEST_F(LoginDatabaseTest, UpdateLogin) {
EXPECT_EQ(form, *result[0]);
}
+TEST_F(LoginDatabaseTest, UpdateLoginWithoutPassword) {
+ PasswordForm form;
+ form.url = GURL("http://accounts.google.com/LoginAuth");
+ form.signon_realm = "http://accounts.google.com/";
+ form.username_value = ASCIIToUTF16("my_username");
+ form.password_value = ASCIIToUTF16("my_password");
+ form.blacklisted_by_user = false;
+ form.scheme = PasswordForm::Scheme::kHtml;
+ form.date_last_used = base::Time::Now();
+ EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
+
+ form.action = GURL("http://accounts.google.com/login");
+ form.all_possible_usernames.push_back(autofill::ValueElementPair(
+ ASCIIToUTF16("my_new_username"), ASCIIToUTF16("new_username_id")));
+ form.times_used = 20;
+ form.submit_element = ASCIIToUTF16("submit_element");
+ form.date_synced = base::Time::Now();
+ form.date_created = base::Time::Now() - base::TimeDelta::FromDays(1);
+ form.date_last_used = base::Time::Now() + base::TimeDelta::FromDays(1);
+ form.display_name = ASCIIToUTF16("Mr. Smith");
+ form.icon_url = GURL("https://accounts.google.com/Icon");
+ form.skip_zero_click = true;
+ form.moving_blocked_for_list.push_back(GaiaIdHash::FromGaiaId("gaia_id"));
+
+ PasswordStoreChangeList changes = db().UpdateLogin(form);
+ EXPECT_EQ(UpdateChangeForForm(form, /*passwordchanged=*/false), changes);
+ ASSERT_EQ(1U, changes.size());
+ EXPECT_EQ(1, changes[0].primary_key());
+
+ // When we retrieve the form from the store, it should have |in_store| set.
+ form.in_store = PasswordForm::Store::kProfileStore;
+
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ ASSERT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
+ ASSERT_EQ(1U, result.size());
+ EXPECT_EQ(form, *result[0]);
+}
+
TEST_F(LoginDatabaseTest, RemoveWrongForm) {
PasswordForm form;
// |origin| shouldn't be empty.
- form.origin = GURL("http://accounts.google.com/LoginAuth");
+ form.url = GURL("http://accounts.google.com/LoginAuth");
form.signon_realm = "http://accounts.google.com/";
form.username_value = ASCIIToUTF16("my_username");
form.password_value = ASCIIToUTF16("my_password");
@@ -1396,7 +1434,7 @@ namespace {
void AddMetricsTestData(LoginDatabase* db) {
PasswordForm password_form;
- password_form.origin = GURL("http://example.com");
+ password_form.url = GURL("http://example.com");
password_form.username_value = ASCIIToUTF16("test1@gmail.com");
password_form.password_value = ASCIIToUTF16("test");
password_form.signon_realm = "http://example.com/";
@@ -1407,7 +1445,7 @@ void AddMetricsTestData(LoginDatabase* db) {
password_form.times_used = 1;
EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
- password_form.origin = GURL("http://second.example.com");
+ password_form.url = GURL("http://second.example.com");
password_form.signon_realm = "http://second.example.com";
password_form.times_used = 3;
EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
@@ -1417,13 +1455,13 @@ void AddMetricsTestData(LoginDatabase* db) {
password_form.times_used = 2;
EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
- password_form.origin = GURL("ftp://third.example.com/");
+ password_form.url = GURL("ftp://third.example.com/");
password_form.signon_realm = "ftp://third.example.com/";
password_form.times_used = 4;
password_form.scheme = PasswordForm::Scheme::kOther;
EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
- password_form.origin = GURL("http://fourth.example.com/");
+ password_form.url = GURL("http://fourth.example.com/");
password_form.signon_realm = "http://fourth.example.com/";
password_form.type = PasswordForm::Type::kManual;
password_form.username_value = ASCIIToUTF16("");
@@ -1431,20 +1469,20 @@ void AddMetricsTestData(LoginDatabase* db) {
password_form.scheme = PasswordForm::Scheme::kHtml;
EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
- password_form.origin = GURL("https://fifth.example.com/");
+ password_form.url = GURL("https://fifth.example.com/");
password_form.signon_realm = "https://fifth.example.com/";
password_form.password_value = ASCIIToUTF16("");
password_form.blacklisted_by_user = true;
EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
- password_form.origin = GURL("https://sixth.example.com/");
+ password_form.url = GURL("https://sixth.example.com/");
password_form.signon_realm = "https://sixth.example.com/";
password_form.username_value = ASCIIToUTF16("my_username");
password_form.password_value = ASCIIToUTF16("my_password");
password_form.blacklisted_by_user = false;
EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
- password_form.origin = GURL();
+ password_form.url = GURL();
password_form.signon_realm = "android://hash@com.example.android/";
password_form.username_value = ASCIIToUTF16("JohnDoe");
password_form.password_value = ASCIIToUTF16("my_password");
@@ -1454,22 +1492,22 @@ void AddMetricsTestData(LoginDatabase* db) {
password_form.username_value = ASCIIToUTF16("JaneDoe");
EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
- password_form.origin = GURL("http://rsolomakhin.github.io/autofill/");
+ password_form.url = GURL("http://rsolomakhin.github.io/autofill/");
password_form.signon_realm = "http://rsolomakhin.github.io/";
password_form.blacklisted_by_user = true;
EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
- password_form.origin = GURL("https://rsolomakhin.github.io/autofill/");
+ password_form.url = GURL("https://rsolomakhin.github.io/autofill/");
password_form.signon_realm = "https://rsolomakhin.github.io/";
password_form.blacklisted_by_user = true;
EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
- password_form.origin = GURL("http://rsolomakhin.github.io/autofill/123");
+ password_form.url = GURL("http://rsolomakhin.github.io/autofill/123");
password_form.signon_realm = "http://rsolomakhin.github.io/";
password_form.blacklisted_by_user = true;
EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
- password_form.origin = GURL("https://rsolomakhin.github.io/autofill/1234");
+ password_form.url = GURL("https://rsolomakhin.github.io/autofill/1234");
password_form.signon_realm = "https://rsolomakhin.github.io/";
password_form.blacklisted_by_user = true;
EXPECT_EQ(AddChangeForForm(password_form), db->AddLogin(password_form));
@@ -1662,8 +1700,6 @@ TEST_F(LoginDatabaseTest, ReportAccountStoreMetricsTest) {
"WithoutCustomPassphrase",
9, 1);
-#if 0
- // TODO(crbug.com/1063852): Add recording code for the scheme-based metrics.
histogram_tester.ExpectUniqueSample(
"PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Android", 2,
1);
@@ -1675,7 +1711,6 @@ TEST_F(LoginDatabaseTest, ReportAccountStoreMetricsTest) {
"PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Https", 1, 1);
histogram_tester.ExpectUniqueSample(
"PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Other", 0, 1);
-#endif
histogram_tester.ExpectBucketCount(
"PasswordManager.AccountStore.TimesPasswordUsed.AutoGenerated."
@@ -1716,13 +1751,18 @@ TEST_F(LoginDatabaseTest, ReportAccountStoreMetricsTest) {
"PasswordManager.AccountStore.TimesPasswordUsed.Overall."
"WithoutCustomPassphrase",
3, 2);
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStore.EmptyUsernames.CountInDatabase", 1, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStore.InaccessiblePasswords", 0, 1);
}
TEST_F(LoginDatabaseTest, DuplicatesMetrics_NoDuplicates) {
// No duplicate.
PasswordForm password_form;
password_form.signon_realm = "http://example1.com/";
- password_form.origin = GURL("http://example1.com/");
+ password_form.url = GURL("http://example1.com/");
password_form.username_element = ASCIIToUTF16("userelem_1");
password_form.username_value = ASCIIToUTF16("username_1");
password_form.password_value = ASCIIToUTF16("password_1");
@@ -1730,7 +1770,7 @@ TEST_F(LoginDatabaseTest, DuplicatesMetrics_NoDuplicates) {
// Different username -> no duplicate.
password_form.signon_realm = "http://example2.com/";
- password_form.origin = GURL("http://example2.com/");
+ password_form.url = GURL("http://example2.com/");
password_form.username_value = ASCIIToUTF16("username_1");
ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
password_form.username_value = ASCIIToUTF16("username_2");
@@ -1739,7 +1779,7 @@ TEST_F(LoginDatabaseTest, DuplicatesMetrics_NoDuplicates) {
// Blacklisted forms don't count as duplicates (neither against other
// blacklisted forms nor against actual saved credentials).
password_form.signon_realm = "http://example3.com/";
- password_form.origin = GURL("http://example3.com/");
+ password_form.url = GURL("http://example3.com/");
password_form.username_value = ASCIIToUTF16("username_1");
ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
password_form.blacklisted_by_user = true;
@@ -1764,7 +1804,7 @@ TEST_F(LoginDatabaseTest, DuplicatesMetrics_ExactDuplicates) {
// username_element is different, which doesn't matter).
PasswordForm password_form;
password_form.signon_realm = "http://example1.com/";
- password_form.origin = GURL("http://example1.com/");
+ password_form.url = GURL("http://example1.com/");
password_form.username_element = ASCIIToUTF16("userelem_1");
password_form.username_value = ASCIIToUTF16("username_1");
ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
@@ -1777,9 +1817,9 @@ TEST_F(LoginDatabaseTest, DuplicatesMetrics_ExactDuplicates) {
// Similarly, origin doesn't make forms "different" either.
password_form.signon_realm = "http://example2.com/";
- password_form.origin = GURL("http://example2.com/path1");
+ password_form.url = GURL("http://example2.com/path1");
ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
- password_form.origin = GURL("http://example2.com/path2");
+ password_form.url = GURL("http://example2.com/path2");
ASSERT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
base::HistogramTester histogram_tester;
@@ -1798,7 +1838,7 @@ TEST_F(LoginDatabaseTest, DuplicatesMetrics_MismatchedDuplicates) {
// Mismatched duplicates: Identical except for the password.
PasswordForm password_form;
password_form.signon_realm = "http://example1.com/";
- password_form.origin = GURL("http://example1.com/");
+ password_form.url = GURL("http://example1.com/");
password_form.username_element = ASCIIToUTF16("userelem_1");
password_form.username_value = ASCIIToUTF16("username_1");
password_form.password_element = ASCIIToUTF16("passelem_1");
@@ -2280,7 +2320,7 @@ INSTANTIATE_TEST_SUITE_P(MigrationToVCurrent,
class LoginDatabaseUndecryptableLoginsTest : public testing::Test {
protected:
- LoginDatabaseUndecryptableLoginsTest() {}
+ LoginDatabaseUndecryptableLoginsTest() = default;
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -2321,7 +2361,7 @@ PasswordForm LoginDatabaseUndecryptableLoginsTest::AddDummyLogin(
// Create a dummy password form.
const base::string16 unique_string16 = ASCIIToUTF16(unique_string);
PasswordForm form;
- form.origin = origin;
+ form.url = origin;
form.username_element = unique_string16;
form.username_value = unique_string16;
form.password_element = unique_string16;
@@ -2414,7 +2454,6 @@ TEST_F(LoginDatabaseUndecryptableLoginsTest, DeleteUndecryptableLoginsTest) {
#if defined(OS_MACOSX) && !defined(OS_IOS)
TEST_F(LoginDatabaseUndecryptableLoginsTest, PasswordRecoveryEnabledGetLogins) {
- base::HistogramTester histogram_tester;
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kDeleteCorruptedPasswords);
@@ -2436,18 +2475,10 @@ TEST_F(LoginDatabaseUndecryptableLoginsTest, PasswordRecoveryEnabledGetLogins) {
RunUntilIdle();
EXPECT_TRUE(testing_local_state().HasPrefPath(prefs::kPasswordRecovery));
-
- histogram_tester.ExpectUniqueSample(
- "PasswordManager.RemovedCorruptedPasswords", 1, 1);
- histogram_tester.ExpectUniqueSample(
- "PasswordManager.DeleteCorruptedPasswordsResult",
- metrics_util::DeleteCorruptedPasswordsResult::kSuccessPasswordsDeleted,
- 1);
}
TEST_F(LoginDatabaseUndecryptableLoginsTest,
PasswordRecoveryDisabledGetLogins) {
- base::HistogramTester histogram_tester;
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(
features::kDeleteCorruptedPasswords);
@@ -2469,19 +2500,10 @@ TEST_F(LoginDatabaseUndecryptableLoginsTest,
RunUntilIdle();
EXPECT_FALSE(testing_local_state().HasPrefPath(prefs::kPasswordRecovery));
-
- EXPECT_TRUE(histogram_tester
- .GetAllSamples("PasswordManager.RemovedCorruptedPasswords")
- .empty());
- EXPECT_TRUE(
- histogram_tester
- .GetAllSamples("PasswordManager.DeleteCorruptedPasswordsResult")
- .empty());
}
TEST_F(LoginDatabaseUndecryptableLoginsTest,
PasswordRecoveryEnabledKeychainLocked) {
- base::HistogramTester histogram_tester;
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kDeleteCorruptedPasswords);
@@ -2505,14 +2527,6 @@ TEST_F(LoginDatabaseUndecryptableLoginsTest,
RunUntilIdle();
EXPECT_FALSE(testing_local_state().HasPrefPath(prefs::kPasswordRecovery));
- EXPECT_TRUE(histogram_tester
- .GetAllSamples("PasswordManager.RemovedCorruptedPasswords")
- .empty());
- EXPECT_TRUE(
- histogram_tester
- .GetAllSamples("PasswordManager.DeleteCorruptedPasswordsResult")
- .empty());
-
// Note: it's not possible that encryption suddenly becomes available. This is
// only used to check that the form is not removed from the database.
OSCryptMocker::SetBackendLocked(false);
@@ -2564,8 +2578,8 @@ TEST_F(LoginDatabaseTest, GetLoginsByPassword) {
// Insert another form with a different password for a different origin.
PasswordForm form2;
GenerateExamplePasswordForm(&form2);
- form2.origin = GURL("https://myrandomsite.com/login.php");
- form2.signon_realm = form2.origin.GetOrigin().spec();
+ form2.url = GURL("https://myrandomsite.com/login.php");
+ form2.signon_realm = form2.url.GetOrigin().spec();
form2.password_value = base::ASCIIToUTF16("my-unique-random-password");
changes = db().AddLogin(form2);
ASSERT_EQ(AddChangeForForm(form2), changes);
@@ -2577,8 +2591,8 @@ TEST_F(LoginDatabaseTest, GetLoginsByPassword) {
// Insert another form with the target password for a different origin.
PasswordForm form3;
GenerateExamplePasswordForm(&form3);
- form3.origin = GURL("https://myrandomsite1.com/login.php");
- form3.signon_realm = form3.origin.GetOrigin().spec();
+ form3.url = GURL("https://myrandomsite1.com/login.php");
+ form3.signon_realm = form3.url.GetOrigin().spec();
form3.password_value = duplicated_password;
changes = db().AddLogin(form3);
ASSERT_EQ(AddChangeForForm(form3), changes);
@@ -2591,7 +2605,7 @@ TEST_F(LoginDatabaseTest, GetLoginsByPassword) {
// Test encrypted passwords are present in add change lists.
TEST_F(LoginDatabaseTest, EncryptedPasswordAdd) {
PasswordForm form;
- form.origin = GURL("http://0.com");
+ form.url = GURL("http://0.com");
form.signon_realm = "http://www.example.com/";
form.action = GURL("http://www.example.com/action");
form.password_element = base::ASCIIToUTF16("pwd");
@@ -2605,7 +2619,7 @@ TEST_F(LoginDatabaseTest, EncryptedPasswordAdd) {
// is already in the DB.
TEST_F(LoginDatabaseTest, EncryptedPasswordAddWithReplaceSemantics) {
PasswordForm form;
- form.origin = GURL("http://0.com");
+ form.url = GURL("http://0.com");
form.signon_realm = "http://www.example.com/";
form.action = GURL("http://www.example.com/action");
form.password_element = base::ASCIIToUTF16("pwd");
@@ -2625,7 +2639,7 @@ TEST_F(LoginDatabaseTest, EncryptedPasswordAddWithReplaceSemantics) {
// Test encrypted passwords are present in update change lists.
TEST_F(LoginDatabaseTest, EncryptedPasswordUpdate) {
PasswordForm form;
- form.origin = GURL("http://0.com");
+ form.url = GURL("http://0.com");
form.signon_realm = "http://www.example.com/";
form.action = GURL("http://www.example.com/action");
form.password_element = base::ASCIIToUTF16("pwd");
@@ -2643,7 +2657,7 @@ TEST_F(LoginDatabaseTest, EncryptedPasswordUpdate) {
// Test encrypted passwords are present when retrieving from DB.
TEST_F(LoginDatabaseTest, GetLoginsEncryptedPassword) {
PasswordForm form;
- form.origin = GURL("http://0.com");
+ form.url = GURL("http://0.com");
form.signon_realm = "http://www.example.com/";
form.action = GURL("http://www.example.com/action");
form.password_element = base::ASCIIToUTF16("pwd");
diff --git a/chromium/components/password_manager/core/browser/mock_bulk_leak_check_service.cc b/chromium/components/password_manager/core/browser/mock_bulk_leak_check_service.cc
new file mode 100644
index 00000000000..b569ac3eb62
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/mock_bulk_leak_check_service.cc
@@ -0,0 +1,14 @@
+// Copyright 2020 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/password_manager/core/browser/mock_bulk_leak_check_service.h"
+
+#include "base/timer/elapsed_timer.h"
+
+namespace password_manager {
+
+MockBulkLeakCheckService::MockBulkLeakCheckService() = default;
+MockBulkLeakCheckService::~MockBulkLeakCheckService() = default;
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/mock_bulk_leak_check_service.h b/chromium/components/password_manager/core/browser/mock_bulk_leak_check_service.h
new file mode 100644
index 00000000000..5e3a702aa33
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/mock_bulk_leak_check_service.h
@@ -0,0 +1,38 @@
+// Copyright 2020 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_PASSWORD_MANAGER_CORE_BROWSER_MOCK_BULK_LEAK_CHECK_SERVICE_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_MOCK_BULK_LEAK_CHECK_SERVICE_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/observer_list.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/password_manager/core/browser/bulk_leak_check_service_interface.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace password_manager {
+
+// Mocked BulkLeakCheckService used by unit tests.
+class MockBulkLeakCheckService : public BulkLeakCheckServiceInterface {
+ public:
+ MockBulkLeakCheckService();
+ ~MockBulkLeakCheckService() override;
+ MOCK_METHOD(void,
+ CheckUsernamePasswordPairs,
+ (std::vector<LeakCheckCredential>),
+ (override));
+ MOCK_METHOD(void, Cancel, (), (override));
+ MOCK_METHOD(size_t, GetPendingChecksCount, (), (const, override));
+ MOCK_METHOD(State, GetState, (), (const, override));
+ MOCK_METHOD(void, AddObserver, (Observer*), (override));
+ MOCK_METHOD(void, RemoveObserver, (Observer*), (override));
+ MOCK_METHOD(void, Shutdown, (), (override));
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_MOCK_BULK_LEAK_CHECK_SERVICE_H_
diff --git a/chromium/components/password_manager/core/browser/mock_password_feature_manager.cc b/chromium/components/password_manager/core/browser/mock_password_feature_manager.cc
index 1cc00d6b00f..51710b47a83 100644
--- a/chromium/components/password_manager/core/browser/mock_password_feature_manager.cc
+++ b/chromium/components/password_manager/core/browser/mock_password_feature_manager.cc
@@ -6,7 +6,7 @@
namespace password_manager {
-MockPasswordFeatureManager::MockPasswordFeatureManager() {}
+MockPasswordFeatureManager::MockPasswordFeatureManager() = default;
MockPasswordFeatureManager::~MockPasswordFeatureManager() = default;
diff --git a/chromium/components/password_manager/core/browser/mock_password_feature_manager.h b/chromium/components/password_manager/core/browser/mock_password_feature_manager.h
index b11fd285557..4ec7a46ee02 100644
--- a/chromium/components/password_manager/core/browser/mock_password_feature_manager.h
+++ b/chromium/components/password_manager/core/browser/mock_password_feature_manager.h
@@ -23,7 +23,7 @@ class MockPasswordFeatureManager : public PasswordFeatureManager {
MOCK_METHOD0(OptInToAccountStorage, void());
MOCK_METHOD0(OptOutOfAccountStorageAndClearSettings, void());
- MOCK_CONST_METHOD0(ShouldShowPasswordStorePicker, bool());
+ MOCK_CONST_METHOD0(ShouldShowAccountStorageBubbleUi, bool());
MOCK_METHOD1(SetDefaultPasswordStore,
void(const autofill::PasswordForm::Store& store));
diff --git a/chromium/components/password_manager/core/browser/mock_password_form_manager_for_ui.h b/chromium/components/password_manager/core/browser/mock_password_form_manager_for_ui.h
index ce857c4cf31..ff1fa8718ae 100644
--- a/chromium/components/password_manager/core/browser/mock_password_form_manager_for_ui.h
+++ b/chromium/components/password_manager/core/browser/mock_password_form_manager_for_ui.h
@@ -18,7 +18,7 @@ class MockPasswordFormManagerForUI : public PasswordFormManagerForUI {
MockPasswordFormManagerForUI();
~MockPasswordFormManagerForUI() override;
- MOCK_METHOD(const GURL&, GetOrigin, (), (const override));
+ MOCK_METHOD(const GURL&, GetURL, (), (const override));
MOCK_METHOD(const std::vector<const autofill::PasswordForm*>&,
GetBestMatches,
(),
@@ -45,6 +45,7 @@ class MockPasswordFormManagerForUI : public PasswordFormManagerForUI {
(),
(const override));
MOCK_METHOD(bool, IsBlacklisted, (), (const override));
+ MOCK_METHOD(bool, WasUnblacklisted, (), (const override));
MOCK_METHOD(bool, IsMovableToAccountStore, (), (const override));
MOCK_METHOD(void, Save, (), (override));
MOCK_METHOD(void, Update, (const autofill::PasswordForm&), (override));
diff --git a/chromium/components/password_manager/core/browser/multi_store_form_fetcher.cc b/chromium/components/password_manager/core/browser/multi_store_form_fetcher.cc
index 7e86b0ef914..33b2da12225 100644
--- a/chromium/components/password_manager/core/browser/multi_store_form_fetcher.cc
+++ b/chromium/components/password_manager/core/browser/multi_store_form_fetcher.cc
@@ -38,20 +38,23 @@ void MultiStoreFormFetcher::Fetch() {
need_to_refetch_ = true;
return;
}
- // Issue a fetch from the profile password store using the base class
- // FormFetcherImpl.
- FormFetcherImpl::Fetch();
- if (state_ == State::WAITING) {
- // Fetching from the profile password store is in progress.
- wait_counter_++;
- }
- // Issue a fetch from the account password store if available.
PasswordStore* account_password_store = client_->GetAccountPasswordStore();
+
+ // Issue a fetch from the profile store and, if it exists, also from the
+ // account store.
+ // Set up |wait_counter_| *before* triggering any of the fetches. This ensures
+ // that things work correctly (i.e. we don't notify of completion too early)
+ // even if the fetches return synchronously (which is the case in tests).
+ wait_counter_++;
+ if (account_password_store)
+ wait_counter_++;
+
+ // Let the base class handle the fetch from the profile store.
+ FormFetcherImpl::Fetch();
if (account_password_store) {
- account_password_store->GetLogins(form_digest_, this);
state_ = State::WAITING;
- wait_counter_++;
+ account_password_store->GetLogins(form_digest_, this);
}
}
@@ -98,9 +101,34 @@ std::unique_ptr<FormFetcher> MultiStoreFormFetcher::Clone() {
void MultiStoreFormFetcher::OnGetPasswordStoreResults(
std::vector<std::unique_ptr<PasswordForm>> results) {
+ // This class overrides OnGetPasswordStoreResultsFrom() (the version of this
+ // method that also receives the originating store), so the store-less version
+ // never gets called.
+ NOTREACHED();
+}
+
+void MultiStoreFormFetcher::OnGetPasswordStoreResultsFrom(
+ scoped_refptr<PasswordStore> store,
+ std::vector<std::unique_ptr<PasswordForm>> results) {
DCHECK_EQ(State::WAITING, state_);
DCHECK_GT(wait_counter_, 0);
+ if (store.get() == client_->GetProfilePasswordStore() &&
+ should_migrate_http_passwords_ && results.empty() &&
+ form_digest_.url.SchemeIs(url::kHttpsScheme)) {
+ // TODO(crbug.com/1095556): Consider also supporting HTTP->HTTPS migration
+ // for the account store.
+ http_migrator_ = std::make_unique<HttpPasswordStoreMigrator>(
+ url::Origin::Create(form_digest_.url), client_, this);
+ // The migrator will call us back at ProcessMigratedForms().
+ return;
+ }
+
+ AggregatePasswordStoreResults(std::move(results));
+}
+
+void MultiStoreFormFetcher::AggregatePasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>> results) {
// Store the results.
for (auto& form : results)
partial_results_.push_back(std::move(form));
@@ -125,6 +153,13 @@ void MultiStoreFormFetcher::OnGetPasswordStoreResults(
ProcessPasswordStoreResults(std::move(partial_results_));
}
+void MultiStoreFormFetcher::ProcessMigratedForms(
+ std::vector<std::unique_ptr<PasswordForm>> forms) {
+ // The migration from HTTP to HTTPS (within the profile store) was finished.
+ // Continue processing with the migrated results.
+ AggregatePasswordStoreResults(std::move(forms));
+}
+
void MultiStoreFormFetcher::SplitResults(
std::vector<std::unique_ptr<PasswordForm>> results) {
// Compute the |is_blacklisted_in_profile_store_| and
diff --git a/chromium/components/password_manager/core/browser/multi_store_form_fetcher.h b/chromium/components/password_manager/core/browser/multi_store_form_fetcher.h
index 1568bfb55ba..5402e6dcadc 100644
--- a/chromium/components/password_manager/core/browser/multi_store_form_fetcher.h
+++ b/chromium/components/password_manager/core/browser/multi_store_form_fetcher.h
@@ -31,8 +31,18 @@ class MultiStoreFormFetcher : public FormFetcherImpl {
// PasswordStoreConsumer:
void OnGetPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
+ void OnGetPasswordStoreResultsFrom(
+ scoped_refptr<PasswordStore> store,
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
private:
+ // HttpPasswordStoreMigrator::Consumer:
+ void ProcessMigratedForms(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms) override;
+
+ void AggregatePasswordStoreResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results);
+
// Splits |results| into |federated_|, |non_federated_|,
// |is_blacklisted_in_profile_store_| and |is_blacklisted_in_account_store_|.
void SplitResults(
diff --git a/chromium/components/password_manager/core/browser/multi_store_form_fetcher_unittest.cc b/chromium/components/password_manager/core/browser/multi_store_form_fetcher_unittest.cc
index aa0121aeaa8..8698a1d48eb 100644
--- a/chromium/components/password_manager/core/browser/multi_store_form_fetcher_unittest.cc
+++ b/chromium/components/password_manager/core/browser/multi_store_form_fetcher_unittest.cc
@@ -74,7 +74,7 @@ PasswordForm CreateHTMLForm(const std::string& origin_url,
base::Time date_last_used = base::Time::Now()) {
PasswordForm form;
form.scheme = PasswordForm::Scheme::kHtml;
- form.origin = GURL(origin_url);
+ form.url = GURL(origin_url);
form.signon_realm = origin_url;
form.username_value = ASCIIToUTF16(username_value);
form.password_value = ASCIIToUTF16(password_value);
@@ -201,8 +201,9 @@ TEST_F(MultiStoreFormFetcherTest, CloningMultiStoreFetcherClonesState) {
blacklisted.in_store = PasswordForm::Store::kAccountStore;
std::vector<std::unique_ptr<PasswordForm>> results;
results.push_back(std::make_unique<PasswordForm>(blacklisted));
- form_fetcher_->OnGetPasswordStoreResults(std::move(results));
- form_fetcher_->OnGetPasswordStoreResults({});
+ form_fetcher_->OnGetPasswordStoreResultsFrom(account_mock_store_,
+ std::move(results));
+ form_fetcher_->OnGetPasswordStoreResultsFrom(profile_mock_store_, {});
EXPECT_EQ(form_fetcher_->GetState(), FormFetcher::State::NOT_WAITING);
EXPECT_TRUE(form_fetcher_->IsBlacklisted());
@@ -234,8 +235,9 @@ TEST_F(MultiStoreFormFetcherTest, CloningMultiStoreFetcherResumesFetch) {
blacklisted.in_store = PasswordForm::Store::kAccountStore;
std::vector<std::unique_ptr<PasswordForm>> results;
results.push_back(std::make_unique<PasswordForm>(blacklisted));
- form_fetcher_->OnGetPasswordStoreResults(std::move(results));
- form_fetcher_->OnGetPasswordStoreResults({});
+ form_fetcher_->OnGetPasswordStoreResultsFrom(account_mock_store_,
+ std::move(results));
+ form_fetcher_->OnGetPasswordStoreResultsFrom(profile_mock_store_, {});
EXPECT_EQ(form_fetcher_->GetState(), FormFetcher::State::NOT_WAITING);
EXPECT_TRUE(form_fetcher_->IsBlacklisted());
@@ -247,12 +249,12 @@ TEST_F(MultiStoreFormFetcherTest, Empty) {
form_fetcher_->AddConsumer(&consumer_);
EXPECT_CALL(consumer_, OnFetchCompleted);
// Both profile and account respond with empty results.
- form_fetcher_->OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<PasswordForm>>());
+ form_fetcher_->OnGetPasswordStoreResultsFrom(
+ profile_mock_store_, std::vector<std::unique_ptr<PasswordForm>>());
// We should be still waiting for the second store to respond.
EXPECT_EQ(FormFetcher::State::WAITING, form_fetcher_->GetState());
- form_fetcher_->OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<PasswordForm>>());
+ form_fetcher_->OnGetPasswordStoreResultsFrom(
+ account_mock_store_, std::vector<std::unique_ptr<PasswordForm>>());
EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
EXPECT_THAT(form_fetcher_->GetNonFederatedMatches(), IsEmpty());
EXPECT_THAT(form_fetcher_->GetFederatedMatches(), IsEmpty());
@@ -282,7 +284,8 @@ TEST_F(MultiStoreFormFetcherTest, MergeFromBothStores) {
results.push_back(std::make_unique<PasswordForm>(federated2));
results.push_back(std::make_unique<PasswordForm>(non_federated1));
results.push_back(std::make_unique<PasswordForm>(blacklisted));
- form_fetcher_->OnGetPasswordStoreResults(std::move(results));
+ form_fetcher_->OnGetPasswordStoreResultsFrom(profile_mock_store_,
+ std::move(results));
// We should be still waiting for the second store to respond.
EXPECT_EQ(FormFetcher::State::WAITING, form_fetcher_->GetState());
@@ -294,7 +297,8 @@ TEST_F(MultiStoreFormFetcherTest, MergeFromBothStores) {
results.push_back(std::make_unique<PasswordForm>(non_federated3));
EXPECT_CALL(consumer_, OnFetchCompleted);
- form_fetcher_->OnGetPasswordStoreResults(std::move(results));
+ form_fetcher_->OnGetPasswordStoreResultsFrom(account_mock_store_,
+ std::move(results));
EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
@@ -318,9 +322,10 @@ TEST_F(MultiStoreFormFetcherTest, BlacklistEntryInTheAccountStore) {
// Pass response from the first store.
std::vector<std::unique_ptr<PasswordForm>> results;
results.push_back(std::make_unique<PasswordForm>(blacklisted));
- form_fetcher_->OnGetPasswordStoreResults(std::move(results));
+ form_fetcher_->OnGetPasswordStoreResultsFrom(account_mock_store_,
+ std::move(results));
// Pass empty response from the second store.
- form_fetcher_->OnGetPasswordStoreResults({});
+ form_fetcher_->OnGetPasswordStoreResultsFrom(profile_mock_store_, {});
// Simulate a user in the account mode.
ON_CALL(*client()->GetPasswordFeatureManager(), IsOptedInForAccountStorage())
@@ -357,9 +362,10 @@ TEST_F(MultiStoreFormFetcherTest, BlacklistEntryInTheProfileStore) {
// Pass response from the first store.
std::vector<std::unique_ptr<PasswordForm>> results;
results.push_back(std::make_unique<PasswordForm>(blacklisted));
- form_fetcher_->OnGetPasswordStoreResults(std::move(results));
+ form_fetcher_->OnGetPasswordStoreResultsFrom(profile_mock_store_,
+ std::move(results));
// Pass empty response from the second store.
- form_fetcher_->OnGetPasswordStoreResults({});
+ form_fetcher_->OnGetPasswordStoreResultsFrom(account_mock_store_, {});
// Simulate a user in the account mode.
ON_CALL(*client()->GetPasswordFeatureManager(), IsOptedInForAccountStorage())
@@ -415,9 +421,10 @@ TEST_F(MultiStoreFormFetcherTest, MovingToAccountStoreIsBlocked) {
results.push_back(std::make_unique<PasswordForm>(blocked_form));
results.push_back(std::make_unique<PasswordForm>(unblocked_form));
results.push_back(std::make_unique<PasswordForm>(psl_form));
- form_fetcher_->OnGetPasswordStoreResults(std::move(results));
+ form_fetcher_->OnGetPasswordStoreResultsFrom(profile_mock_store_,
+ std::move(results));
// Pass empty response from the account store.
- form_fetcher_->OnGetPasswordStoreResults({});
+ form_fetcher_->OnGetPasswordStoreResultsFrom(account_mock_store_, {});
// Moving should be blocked for |kUser| and |form1|.
EXPECT_TRUE(
diff --git a/chromium/components/password_manager/core/browser/multi_store_password_save_manager.cc b/chromium/components/password_manager/core/browser/multi_store_password_save_manager.cc
index a65c60f1efc..3aeb6fd22b1 100644
--- a/chromium/components/password_manager/core/browser/multi_store_password_save_manager.cc
+++ b/chromium/components/password_manager/core/browser/multi_store_password_save_manager.cc
@@ -4,12 +4,14 @@
#include "components/password_manager/core/browser/multi_store_password_save_manager.h"
+#include "base/metrics/histogram_functions.h"
#include "components/autofill/core/common/gaia_id_hash.h"
#include "components/password_manager/core/browser/form_fetcher.h"
#include "components/password_manager/core/browser/form_saver.h"
#include "components/password_manager/core/browser/form_saver_impl.h"
#include "components/password_manager/core/browser/password_feature_manager_impl.h"
#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_manager_util.h"
using autofill::PasswordForm;
@@ -92,6 +94,20 @@ PendingCredentialsState ResolvePendingCredentialsStates(
return PendingCredentialsState::NONE;
}
+// Returns a PasswordForm that has all fields taken from |update| except
+// date_created, date_synced, times_used and moving_blocked_for_list that are
+// taken from |original_form|.
+PasswordForm UpdateFormPreservingDifferentFieldsAcrossStores(
+ const PasswordForm& original_form,
+ const PasswordForm& update) {
+ PasswordForm result(update);
+ result.date_created = original_form.date_created;
+ result.date_synced = original_form.date_synced;
+ result.times_used = original_form.times_used;
+ result.moving_blocked_for_list = original_form.moving_blocked_for_list;
+ return result;
+}
+
} // namespace
MultiStorePasswordSaveManager::MultiStorePasswordSaveManager(
@@ -150,11 +166,18 @@ void MultiStorePasswordSaveManager::SavePendingToStoreImpl(
case PendingCredentialsState::EQUAL_TO_SAVED_MATCH: {
// If the submitted credentials exists in both stores,
// |pending_credentials_| might be from the account store (and thus not
- // have a moving_blocked_for_list). We need to preserve any existing list,
- // so explicitly copy it over from the profile store match.
- PasswordForm form_to_update(pending_credentials_);
- form_to_update.moving_blocked_for_list =
- states.similar_saved_form_from_profile_store->moving_blocked_for_list;
+ // have a moving_blocked_for_list). We need to preserve any existing list.
+ // Same applies for other fields. Check the comment on
+ // UpdateFormPreservingDifferentFieldsAcrossStores().
+ PasswordForm form_to_update =
+ UpdateFormPreservingDifferentFieldsAcrossStores(
+ *states.similar_saved_form_from_profile_store,
+ pending_credentials_);
+ // For other cases, |pending_credentials_.times_used| is updated in
+ // UpdateMetadataForUsage() invoked from UploadVotesAndMetrics().
+ // UpdateFormPreservingDifferentFieldsAcrossStores() preserved the
+ // original times_used, and hence we should increment it here.
+ form_to_update.times_used++;
form_saver_->Update(form_to_update, profile_matches,
old_profile_password);
} break;
@@ -177,10 +200,18 @@ void MultiStorePasswordSaveManager::SavePendingToStoreImpl(
case PendingCredentialsState::EQUAL_TO_SAVED_MATCH: {
// If the submitted credentials exists in both stores,
// .|pending_credentials_| might be from the profile store (and thus
- // has a moving_blocked_for_list). We need to clear it before storing to
- // the account store.
- PasswordForm form_to_update(pending_credentials_);
- form_to_update.moving_blocked_for_list.clear();
+ // has a moving_blocked_for_list). We need to preserve any existing
+ // values. Same applies for other fields. Check the comment on
+ // UpdateFormPreservingDifferentFieldsAcrossStores().
+ PasswordForm form_to_update =
+ UpdateFormPreservingDifferentFieldsAcrossStores(
+ *states.similar_saved_form_from_account_store,
+ pending_credentials_);
+ // For other cases, |pending_credentials_.times_used| is updated in
+ // UpdateMetadataForUsage() invoked from UploadVotesAndMetrics().
+ // UpdateFormPreservingDifferentFieldsAcrossStores() preserved the
+ // original times_used, and hence we should increment it here.
+ form_to_update.times_used++;
account_store_form_saver_->Update(form_to_update, account_matches,
old_account_password);
} break;
@@ -220,7 +251,11 @@ std::unique_ptr<PasswordSaveManager> MultiStorePasswordSaveManager::Clone() {
return result;
}
-void MultiStorePasswordSaveManager::MoveCredentialsToAccountStore() {
+void MultiStorePasswordSaveManager::MoveCredentialsToAccountStore(
+ metrics_util::MoveToAccountStoreTrigger trigger) {
+ base::UmaHistogramEnumeration(
+ "PasswordManager.AccountStorage.MoveToAccountStoreFlowAccepted", trigger);
+
// TODO(crbug.com/1032992): Moving credentials upon an update. FormFetch will
// have an outdated credentials. Fix it if this turns out to be a product
// requirement.
diff --git a/chromium/components/password_manager/core/browser/multi_store_password_save_manager.h b/chromium/components/password_manager/core/browser/multi_store_password_save_manager.h
index 095081df059..d90047f8ed5 100644
--- a/chromium/components/password_manager/core/browser/multi_store_password_save_manager.h
+++ b/chromium/components/password_manager/core/browser/multi_store_password_save_manager.h
@@ -33,7 +33,8 @@ class MultiStorePasswordSaveManager : public PasswordSaveManagerImpl {
std::unique_ptr<PasswordSaveManager> Clone() override;
- void MoveCredentialsToAccountStore() override;
+ void MoveCredentialsToAccountStore(
+ metrics_util::MoveToAccountStoreTrigger trigger) override;
void BlockMovingToAccountStoreFor(
const autofill::GaiaIdHash& gaia_id_hash) override;
diff --git a/chromium/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc b/chromium/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc
index 99278caec5e..9a9bc080c33 100644
--- a/chromium/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc
@@ -6,9 +6,11 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
#include "components/autofill/core/common/renderer_id.h"
#include "components/password_manager/core/browser/fake_form_fetcher.h"
#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/stub_form_saver.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "components/password_manager/core/browser/votes_uploader.h"
@@ -35,6 +37,9 @@ MATCHER_P2(MatchesUsernameAndPassword, username, password, "") {
const int kUsernameFieldIndex = 1;
const int kPasswordFieldIndex = 2;
+const auto kTrigger = metrics_util::MoveToAccountStoreTrigger::
+ kSuccessfulLoginWithProfileStorePassword;
+
} // namespace
class MockFormSaver : public StubFormSaver {
@@ -69,17 +74,6 @@ class MockFormSaver : public StubFormSaver {
DISALLOW_COPY_AND_ASSIGN(MockFormSaver);
};
-class MockPasswordManagerClient : public StubPasswordManagerClient {
- public:
- MockPasswordManagerClient() = default;
- ~MockPasswordManagerClient() override = default;
-
- MOCK_CONST_METHOD0(IsMainFrameSecure, bool());
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerClient);
-};
-
class MultiStorePasswordSaveManagerTest : public testing::Test {
public:
MultiStorePasswordSaveManagerTest()
@@ -122,7 +116,7 @@ class MultiStorePasswordSaveManagerTest : public testing::Test {
submitted_form_.fields[kUsernameFieldIndex].value = ASCIIToUTF16("user1");
submitted_form_.fields[kPasswordFieldIndex].value = ASCIIToUTF16("secret1");
- saved_match_.origin = origin;
+ saved_match_.url = origin;
saved_match_.action = action;
saved_match_.signon_realm = "https://accounts.google.com/";
saved_match_.username_value = ASCIIToUTF16("test@gmail.com");
@@ -133,7 +127,7 @@ class MultiStorePasswordSaveManagerTest : public testing::Test {
saved_match_.scheme = PasswordForm::Scheme::kHtml;
psl_saved_match_ = saved_match_;
- psl_saved_match_.origin = psl_origin;
+ psl_saved_match_.url = psl_origin;
psl_saved_match_.action = psl_action;
psl_saved_match_.signon_realm = "https://myaccounts.google.com/";
psl_saved_match_.is_public_suffix_match = true;
@@ -156,7 +150,8 @@ class MultiStorePasswordSaveManagerTest : public testing::Test {
fetcher_->Fetch();
metrics_recorder_ = base::MakeRefCounted<PasswordFormMetricsRecorder>(
- client_.IsMainFrameSecure(), client_.GetUkmSourceId());
+ client_.IsCommittedMainFrameSecure(), client_.GetUkmSourceId(),
+ /*pref_service=*/nullptr);
auto mock_profile_form_saver = std::make_unique<NiceMock<MockFormSaver>>();
mock_profile_form_saver_ = mock_profile_form_saver.get();
@@ -195,7 +190,7 @@ class MultiStorePasswordSaveManagerTest : public testing::Test {
PasswordForm CreateSavedFederated() {
autofill::PasswordForm federated;
- federated.origin = GURL("https://example.in/login");
+ federated.url = GURL("https://example.in/login");
federated.signon_realm = "federation://example.in/google.com";
federated.type = autofill::PasswordForm::Type::kApi;
federated.federation_origin =
@@ -204,7 +199,7 @@ class MultiStorePasswordSaveManagerTest : public testing::Test {
return federated;
}
- MockPasswordManagerClient* client() { return &client_; }
+ StubPasswordManagerClient* client() { return &client_; }
MockFormSaver* mock_account_form_saver() { return mock_account_form_saver_; }
MockFormSaver* mock_profile_form_saver() { return mock_profile_form_saver_; }
FakeFormFetcher* fetcher() { return fetcher_.get(); }
@@ -220,7 +215,7 @@ class MultiStorePasswordSaveManagerTest : public testing::Test {
PasswordForm parsed_submitted_form_;
private:
- NiceMock<MockPasswordManagerClient> client_;
+ StubPasswordManagerClient client_;
VotesUploader votes_uploader_;
scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder_;
@@ -411,15 +406,26 @@ TEST_F(MultiStorePasswordSaveManagerTest, UpdateInBothStores) {
TEST_F(MultiStorePasswordSaveManagerTest, AutomaticSaveInBothStores) {
SetAccountStoreEnabled(/*is_enabled=*/true);
+ // Set different values for the fields that should be preserved per store
+ // (namely: date_created, date_synced, times_used, moving_blocked_for_list)
PasswordForm saved_match_in_profile_store(saved_match_);
saved_match_in_profile_store.username_value =
parsed_submitted_form_.username_value;
saved_match_in_profile_store.password_value =
parsed_submitted_form_.password_value;
saved_match_in_profile_store.in_store = PasswordForm::Store::kProfileStore;
+ saved_match_in_profile_store.date_created =
+ base::Time::Now() - base::TimeDelta::FromDays(10);
+ saved_match_in_profile_store.times_used = 10;
+ saved_match_in_profile_store.moving_blocked_for_list.push_back(
+ autofill::GaiaIdHash::FromGaiaId("email@gmail.com"));
PasswordForm saved_match_in_account_store(saved_match_in_profile_store);
saved_match_in_account_store.in_store = PasswordForm::Store::kAccountStore;
+ saved_match_in_account_store.date_created = base::Time::Now();
+ saved_match_in_account_store.date_synced = base::Time::Now();
+ saved_match_in_account_store.times_used = 5;
+ saved_match_in_account_store.moving_blocked_for_list.clear();
SetNonFederatedAndNotifyFetchCompleted(
{&saved_match_in_profile_store, &saved_match_in_account_store});
@@ -435,6 +441,7 @@ TEST_F(MultiStorePasswordSaveManagerTest, AutomaticSaveInBothStores) {
// We still should update both credentials to update the |date_last_used| and
// |times_used|. Note that |in_store| is irrelevant since it's not persisted.
+ // All other fields should be preserved.
PasswordForm expected_profile_update_form(saved_match_in_profile_store);
expected_profile_update_form.times_used++;
expected_profile_update_form.date_last_used =
@@ -754,6 +761,36 @@ TEST_F(MultiStorePasswordSaveManagerTest,
}
TEST_F(MultiStorePasswordSaveManagerTest,
+ MoveCredentialsFromProfileToAccountStoreRecordsFlowAccepted) {
+ base::HistogramTester histogram_tester;
+
+ PasswordForm saved_match_in_profile_store(saved_match_);
+ saved_match_in_profile_store.in_store = PasswordForm::Store::kProfileStore;
+ saved_match_in_profile_store.moving_blocked_for_list.push_back(
+ autofill::GaiaIdHash::FromGaiaId("user@gmail.com"));
+ SetNonFederatedAndNotifyFetchCompleted({&saved_match_in_profile_store});
+
+ password_save_manager()->CreatePendingCredentials(
+ saved_match_in_profile_store, observed_form_, submitted_form_,
+ /*is_http_auth=*/false,
+ /*is_credential_api_save=*/false);
+
+ PasswordForm saved_match_without_moving_blocked_list(
+ saved_match_in_profile_store);
+ saved_match_without_moving_blocked_list.moving_blocked_for_list.clear();
+
+ EXPECT_CALL(*mock_profile_form_saver(), Remove(saved_match_in_profile_store));
+ EXPECT_CALL(*mock_account_form_saver(),
+ Save(saved_match_without_moving_blocked_list, _, _));
+
+ password_save_manager()->MoveCredentialsToAccountStore(kTrigger);
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStorage.MoveToAccountStoreFlowAccepted", kTrigger,
+ 1);
+}
+
+TEST_F(MultiStorePasswordSaveManagerTest,
MoveCredentialsFromProfileToAccountStoreWhenExistsOnlyInProfileStore) {
PasswordForm saved_match_in_profile_store(saved_match_);
saved_match_in_profile_store.in_store = PasswordForm::Store::kProfileStore;
@@ -774,7 +811,7 @@ TEST_F(MultiStorePasswordSaveManagerTest,
EXPECT_CALL(*mock_account_form_saver(),
Save(saved_match_without_moving_blocked_list, _, _));
- password_save_manager()->MoveCredentialsToAccountStore();
+ password_save_manager()->MoveCredentialsToAccountStore(kTrigger);
}
TEST_F(
@@ -797,7 +834,7 @@ TEST_F(
Save(saved_match_in_profile_store, _, _))
.Times(0);
- password_save_manager()->MoveCredentialsToAccountStore();
+ password_save_manager()->MoveCredentialsToAccountStore(kTrigger);
}
TEST_F(MultiStorePasswordSaveManagerTest,
@@ -823,7 +860,7 @@ TEST_F(MultiStorePasswordSaveManagerTest,
EXPECT_CALL(*mock_account_form_saver(),
Save(psl_saved_match_in_profile_store, _, _));
- password_save_manager()->MoveCredentialsToAccountStore();
+ password_save_manager()->MoveCredentialsToAccountStore(kTrigger);
}
TEST_F(MultiStorePasswordSaveManagerTest,
@@ -845,7 +882,7 @@ TEST_F(MultiStorePasswordSaveManagerTest,
EXPECT_CALL(*mock_account_form_saver(),
Save(federated_match_in_profile_store, _, _));
- password_save_manager()->MoveCredentialsToAccountStore();
+ password_save_manager()->MoveCredentialsToAccountStore(kTrigger);
}
TEST_F(MultiStorePasswordSaveManagerTest,
@@ -865,7 +902,7 @@ TEST_F(MultiStorePasswordSaveManagerTest,
EXPECT_CALL(*mock_profile_form_saver(), Remove(saved_match_in_profile_store));
EXPECT_CALL(*mock_account_form_saver(), Save).Times(0);
- password_save_manager()->MoveCredentialsToAccountStore();
+ password_save_manager()->MoveCredentialsToAccountStore(kTrigger);
}
TEST_F(MultiStorePasswordSaveManagerTest,
@@ -896,7 +933,7 @@ TEST_F(MultiStorePasswordSaveManagerTest,
EXPECT_CALL(*mock_account_form_saver(),
Save(saved_match_in_profile_store, _, _));
- password_save_manager()->MoveCredentialsToAccountStore();
+ password_save_manager()->MoveCredentialsToAccountStore(kTrigger);
}
TEST_F(MultiStorePasswordSaveManagerTest, BlockMovingWhenExistsInProfileStore) {
diff --git a/chromium/components/password_manager/core/browser/origin_credential_store.cc b/chromium/components/password_manager/core/browser/origin_credential_store.cc
index 7e9f73026b7..12e75c3e583 100644
--- a/chromium/components/password_manager/core/browser/origin_credential_store.cc
+++ b/chromium/components/password_manager/core/browser/origin_credential_store.cc
@@ -35,9 +35,8 @@ UiCredential::UiCredential(const PasswordForm& form,
const url::Origin& affiliated_origin)
: username_(form.username_value),
password_(form.password_value),
- origin_(form.is_affiliation_based_match
- ? affiliated_origin
- : url::Origin::Create(form.origin)),
+ origin_(form.is_affiliation_based_match ? affiliated_origin
+ : url::Origin::Create(form.url)),
is_public_suffix_match_(form.is_public_suffix_match),
is_affiliation_based_match_(form.is_affiliation_based_match) {}
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager.cc b/chromium/components/password_manager/core/browser/password_autofill_manager.cc
index 48fb58924f8..a4960edf387 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager.cc
@@ -8,6 +8,7 @@
#include <algorithm>
#include <string>
+#include <tuple>
#include <utility>
#include <vector>
@@ -20,6 +21,7 @@
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/util/ranges/algorithm.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_driver.h"
@@ -52,6 +54,8 @@ namespace password_manager {
namespace {
+using AutoselectFirstSuggestion =
+ autofill::AutofillClient::PopupOpenArgs::AutoselectFirstSuggestion;
using IsLoading = autofill::Suggestion::IsLoading;
constexpr base::char16 kPasswordReplacementChar = 0x2022;
@@ -224,8 +228,8 @@ autofill::Suggestion CreateEntryToOptInToAccountStorageThenFill() {
// Entry for opting in to password account storage and then generating password.
autofill::Suggestion CreateEntryToOptInToAccountStorageThenGenerate() {
- autofill::Suggestion suggestion(l10n_util::GetStringUTF16(
- IDS_PASSWORD_MANAGER_OPT_INTO_ACCOUNT_STORED_GENERATION));
+ autofill::Suggestion suggestion(
+ l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_GENERATE_PASSWORD));
suggestion.frontend_id =
autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE;
suggestion.icon = "google";
@@ -302,6 +306,19 @@ std::vector<autofill::Suggestion> SetUnlockLoadingState(
return new_suggestions;
}
+void LogAccountStoredPasswordsCountInFillDataAfterUnlock(
+ const autofill::PasswordFormFillData& fill_data) {
+ int account_store_passwords_count =
+ util::ranges::count_if(fill_data.additional_logins,
+ [](const autofill::PasswordAndMetadata& metadata) {
+ return metadata.uses_account_store;
+ });
+ if (fill_data.uses_account_store)
+ ++account_store_passwords_count;
+ metrics_util::LogPasswordsCountFromAccountStoreAfterUnlock(
+ account_store_passwords_count);
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -345,6 +362,7 @@ void PasswordAutofillManager::DidSelectSuggestion(const base::string16& value,
void PasswordAutofillManager::OnUnlockItemAccepted(
autofill::PopupItemId unlock_item) {
+ using metrics_util::PasswordDropdownSelectedOption;
DCHECK(
unlock_item == autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN ||
unlock_item ==
@@ -352,10 +370,15 @@ void PasswordAutofillManager::OnUnlockItemAccepted(
UpdatePopup(SetUnlockLoadingState(autofill_client_->GetPopupSuggestions(),
unlock_item, IsLoading(true)));
- autofill_client_->PinPopupView();
+ signin_metrics::ReauthAccessPoint reauth_access_point =
+ unlock_item == autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN
+ ? signin_metrics::ReauthAccessPoint::kAutofillDropdown
+ : signin_metrics::ReauthAccessPoint::kGeneratePasswordDropdown;
password_client_->TriggerReauthForPrimaryAccount(
+ reauth_access_point,
base::BindOnce(&PasswordAutofillManager::OnUnlockReauthCompleted,
- weak_ptr_factory_.GetWeakPtr(), unlock_item));
+ weak_ptr_factory_.GetWeakPtr(), unlock_item,
+ autofill_client_->GetReopenPopupArgs()));
}
void PasswordAutofillManager::DidAcceptSuggestion(const base::string16& value,
@@ -389,18 +412,25 @@ void PasswordAutofillManager::DidAcceptSuggestion(const base::string16& value,
autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_RE_SIGNIN) {
password_client_->TriggerSignIn(
signin_metrics::AccessPoint::ACCESS_POINT_AUTOFILL_DROPDOWN);
+ metrics_util::LogPasswordDropdownItemSelected(
+ PasswordDropdownSelectedOption::kResigninToUnlockAccountStore,
+ password_client_->IsIncognito());
} else if (
identifier == autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN ||
identifier ==
autofill::
POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE) {
OnUnlockItemAccepted(static_cast<autofill::PopupItemId>(identifier));
- return; // Do not hide the popup while loading data.
+ metrics_util::LogPasswordDropdownItemSelected(
+ identifier == autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN
+ ? PasswordDropdownSelectedOption::kUnlockAccountStorePasswords
+ : PasswordDropdownSelectedOption::kUnlockAccountStoreGeneration,
+ password_client_->IsIncognito());
} else {
+ bool success = FillSuggestion(GetUsernameFromSuggestion(value), identifier);
metrics_util::LogPasswordDropdownItemSelected(
PasswordDropdownSelectedOption::kPassword,
password_client_->IsIncognito());
- bool success = FillSuggestion(GetUsernameFromSuggestion(value), identifier);
DCHECK(success);
}
@@ -453,10 +483,16 @@ void PasswordAutofillManager::OnAddPasswordFillData(
return;
fill_data_ = std::make_unique<autofill::PasswordFormFillData>(fill_data);
- RequestFavicon(fill_data.origin);
+ RequestFavicon(fill_data.url);
if (!autofill_client_ || autofill_client_->GetPopupSuggestions().empty())
return;
+ // Only log account-stored passwords if the unlock just happened.
+ if (HasLoadingSuggestion(
+ autofill_client_->GetPopupSuggestions(),
+ autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN)) {
+ LogAccountStoredPasswordsCountInFillDataAfterUnlock(fill_data);
+ }
UpdatePopup(BuildSuggestions(base::string16(),
ForPasswordField(AreSuggestionForPasswordField(
autofill_client_->GetPopupSuggestions())),
@@ -470,6 +506,8 @@ void PasswordAutofillManager::OnNoCredentialsFound() {
autofill_client_->GetPopupSuggestions(),
autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN))
return;
+ metrics_util::LogPasswordsCountFromAccountStoreAfterUnlock(
+ /*account_store_passwords_count=*/0);
UpdatePopup({CreateAccountStorageEmptyEntry()});
}
@@ -618,9 +656,10 @@ bool PasswordAutofillManager::ShowPopup(
return false;
}
LogMetricsForSuggestions(suggestions);
- autofill_client_->ShowAutofillPopup(bounds, text_direction, suggestions,
- /*autoselect_first_suggestion=*/false,
- autofill::PopupType::kPasswords,
+ autofill::AutofillClient::PopupOpenArgs open_args(
+ bounds, text_direction, suggestions, AutoselectFirstSuggestion(false),
+ autofill::PopupType::kPasswords);
+ autofill_client_->ShowAutofillPopup(open_args,
weak_ptr_factory_.GetWeakPtr());
return true;
}
@@ -725,7 +764,11 @@ void PasswordAutofillManager::OnFaviconReady(
void PasswordAutofillManager::OnUnlockReauthCompleted(
autofill::PopupItemId unlock_item,
+ autofill::AutofillClient::PopupOpenArgs reopen_args,
PasswordManagerClient::ReauthSucceeded reauth_succeeded) {
+ autofill_client_->ShowAutofillPopup(reopen_args,
+ weak_ptr_factory_.GetWeakPtr());
+ autofill_client_->PinPopupView();
if (reauth_succeeded) {
if (unlock_item ==
autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE) {
@@ -735,8 +778,8 @@ void PasswordAutofillManager::OnUnlockReauthCompleted(
}
return;
}
- UpdatePopup(SetUnlockLoadingState(autofill_client_->GetPopupSuggestions(),
- unlock_item, IsLoading(false)));
+ UpdatePopup(SetUnlockLoadingState(reopen_args.suggestions, unlock_item,
+ IsLoading(false)));
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager.h b/chromium/components/password_manager/core/browser/password_autofill_manager.h
index e0dc5e9517e..d52c7091afa 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager.h
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager.h
@@ -169,8 +169,8 @@ class PasswordAutofillManager : public autofill::AutofillPopupDelegate {
void OnFaviconReady(const favicon_base::FaviconImageResult& result);
// Replaces |unlock_item| with a loading symbol and triggers a reauth flow to
- // opt in for passwords account storage, with OnUnlockReauthCompleted as
- // callback.
+ // opt in for the account-scoped password storage, with
+ // OnUnlockReauthCompleted as callback.
void OnUnlockItemAccepted(autofill::PopupItemId unlock_item);
// If reauth failed, resets the suggestions to show the |unlock_item| again.
@@ -178,6 +178,7 @@ class PasswordAutofillManager : public autofill::AutofillPopupDelegate {
// that was clicked.
void OnUnlockReauthCompleted(
autofill::PopupItemId unlock_item,
+ autofill::AutofillClient::PopupOpenArgs reopen_args,
PasswordManagerClient::ReauthSucceeded reauth_succeeded);
std::unique_ptr<autofill::PasswordFormFillData> fill_data_;
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc
index eb355514ce0..e23bdd2e9c2 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -94,24 +94,29 @@ constexpr char kDropdownSelectedHistogram[] =
"PasswordManager.PasswordDropdownItemSelected";
constexpr char kDropdownShownHistogram[] =
"PasswordManager.PasswordDropdownShown";
+constexpr char kCredentialsCountFromAccountStoreAfterUnlockHistogram[] =
+ "PasswordManager.CredentialsCountFromAccountStoreAfterUnlock";
const gfx::Image kTestFavicon = gfx::test::CreateImage(16, 16);
class MockPasswordManagerDriver : public StubPasswordManagerDriver {
public:
- MOCK_METHOD2(FillSuggestion,
- void(const base::string16&, const base::string16&));
- MOCK_METHOD2(PreviewSuggestion,
- void(const base::string16&, const base::string16&));
- MOCK_METHOD0(GetPasswordManager, PasswordManager*());
+ MOCK_METHOD(void,
+ FillSuggestion,
+ (const base::string16&, const base::string16&),
+ (override));
+ MOCK_METHOD(void,
+ PreviewSuggestion,
+ (const base::string16&, const base::string16&),
+ (override));
+ MOCK_METHOD(PasswordManager*, GetPasswordManager, (), (override));
};
class TestPasswordManagerClient : public StubPasswordManagerClient {
public:
TestPasswordManagerClient() : main_frame_url_(kMainFrameUrl) {}
- ~TestPasswordManagerClient() override = default;
MockPasswordManagerDriver* mock_driver() { return &driver_; }
- const GURL& GetMainFrameURL() const override { return main_frame_url_; }
+ const GURL& GetLastCommittedURL() const override { return main_frame_url_; }
const MockPasswordFeatureManager* GetPasswordFeatureManager() const override {
return feature_manager_.get();
@@ -139,12 +144,18 @@ class TestPasswordManagerClient : public StubPasswordManagerClient {
.WillByDefault(Return(needs_signin));
}
- MOCK_METHOD0(GeneratePassword, void());
- MOCK_METHOD1(TriggerReauthForPrimaryAccount,
- void(base::OnceCallback<void(ReauthSucceeded)>));
- MOCK_METHOD1(TriggerSignIn, void(signin_metrics::AccessPoint));
- MOCK_METHOD0(GetFaviconService, favicon::FaviconService*());
- MOCK_METHOD1(NavigateToManagePasswordsPage, void(ManagePasswordsReferrer));
+ MOCK_METHOD(void, GeneratePassword, (), (override));
+ MOCK_METHOD(void,
+ TriggerReauthForPrimaryAccount,
+ (signin_metrics::ReauthAccessPoint,
+ base::OnceCallback<void(ReauthSucceeded)>),
+ (override));
+ MOCK_METHOD(void, TriggerSignIn, (signin_metrics::AccessPoint), (override));
+ MOCK_METHOD(favicon::FaviconService*, GetFaviconService, (), (override));
+ MOCK_METHOD(void,
+ NavigateToManagePasswordsPage,
+ (ManagePasswordsReferrer),
+ (override));
private:
MockPasswordManagerDriver driver_;
@@ -157,20 +168,26 @@ class TestPasswordManagerClient : public StubPasswordManagerClient {
class MockAutofillClient : public autofill::TestAutofillClient {
public:
MockAutofillClient() = default;
- MOCK_METHOD6(ShowAutofillPopup,
- void(const gfx::RectF& element_bounds,
- base::i18n::TextDirection text_direction,
- const std::vector<Suggestion>& suggestions,
- bool autoselect_first_suggestion,
- PopupType popup_type,
- base::WeakPtr<autofill::AutofillPopupDelegate> delegate));
- MOCK_METHOD0(PinPopupView, void());
- MOCK_CONST_METHOD0(GetPopupSuggestions,
- base::span<const autofill::Suggestion>());
- MOCK_METHOD2(UpdatePopup,
- void(const std::vector<autofill::Suggestion>&, PopupType));
- MOCK_METHOD1(HideAutofillPopup, void(autofill::PopupHidingReason));
- MOCK_METHOD1(ExecuteCommand, void(int));
+ MOCK_METHOD(void,
+ ShowAutofillPopup,
+ (const autofill::AutofillClient::PopupOpenArgs& open_args,
+ base::WeakPtr<autofill::AutofillPopupDelegate> delegate),
+ (override));
+ MOCK_METHOD(void, PinPopupView, (), (override));
+ MOCK_METHOD(PopupOpenArgs, GetReopenPopupArgs, (), (const, override));
+ MOCK_METHOD(base::span<const autofill::Suggestion>,
+ GetPopupSuggestions,
+ (),
+ (const, override));
+ MOCK_METHOD(void,
+ UpdatePopup,
+ (const std::vector<autofill::Suggestion>&, PopupType),
+ (override));
+ MOCK_METHOD(void,
+ HideAutofillPopup,
+ (autofill::PopupHidingReason),
+ (override));
+ MOCK_METHOD(void, ExecuteCommand, (int), (override));
};
base::CancelableTaskTracker::TaskId
@@ -186,33 +203,53 @@ std::vector<autofill::Suggestion> CreateTestSuggestions(
bool has_opt_in_and_generate,
bool has_re_signin) {
std::vector<Suggestion> suggestions;
- suggestions.push_back(
- Suggestion(/*value=*/"User1", /*label=*/"PW1", /*icon=*/"",
- /*fronend_id=*/autofill::POPUP_ITEM_ID_PASSWORD_ENTRY));
- suggestions.push_back(Suggestion(
+ suggestions.emplace_back(
+ /*value=*/"User1", /*label=*/"PW1", /*icon=*/"",
+ /*frontend_id=*/autofill::POPUP_ITEM_ID_PASSWORD_ENTRY);
+ suggestions.emplace_back(
/*value=*/"Show all pwds", /*label=*/"", /*icon=*/"",
- /*fronend_id=*/autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
+ /*frontend_id=*/autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY);
if (has_opt_in_and_fill) {
- suggestions.push_back(Suggestion(
+ suggestions.emplace_back(
/*value=*/"Unlock passwords and fill", /*label=*/"", /*icon=*/"",
- /*fronend_id=*/
- autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN));
+ /*frontend_id=*/
+ autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN);
}
if (has_opt_in_and_generate) {
- suggestions.push_back(Suggestion(
+ suggestions.emplace_back(
/*value=*/"Unlock passwords and generate", /*label=*/"", /*icon=*/"",
- /*fronend_id=*/
- autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE));
+ /*frontend_id=*/
+ autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE);
}
if (has_re_signin) {
- suggestions.push_back(Suggestion(
+ suggestions.emplace_back(
/*value=*/"Sign in to access passwords", /*label=*/"", /*icon=*/"",
- /*fronend_id=*/
- autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_RE_SIGNIN));
+ /*frontend_id=*/
+ autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_RE_SIGNIN);
}
return suggestions;
}
+std::vector<autofill::Suggestion> SetLoading(
+ std::vector<autofill::Suggestion> suggestions,
+ int index_of_loading_element) {
+ suggestions[index_of_loading_element].is_loading =
+ Suggestion::IsLoading(true);
+ return suggestions;
+}
+
+autofill::AutofillClient::PopupOpenArgs CreateReopenArgsWithTestSuggestions(
+ bool has_opt_in_and_fill,
+ bool has_opt_in_and_generate,
+ bool has_re_signin) {
+ return {
+ gfx::RectF(), base::i18n::LEFT_TO_RIGHT,
+ CreateTestSuggestions(has_opt_in_and_fill, has_opt_in_and_generate,
+ has_re_signin),
+ autofill::AutofillClient::PopupOpenArgs::AutoselectFirstSuggestion(false),
+ autofill::PopupType::kPasswords};
+}
+
} // namespace
class PasswordAutofillManagerTest : public testing::Test {
@@ -242,7 +279,7 @@ class PasswordAutofillManagerTest : public testing::Test {
EXPECT_CALL(*client, GetFaviconService())
.WillOnce(Return(&favicon_service));
EXPECT_CALL(favicon_service,
- GetFaviconImageForPageURL(fill_data_.origin, _, _));
+ GetFaviconImageForPageURL(fill_data_.url, _, _));
password_autofill_manager_->OnAddPasswordFillData(fill_data_);
testing::Mock::VerifyAndClearExpectations(client);
// Suppress the warnings in the tests.
@@ -261,6 +298,17 @@ class PasswordAutofillManagerTest : public testing::Test {
return l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_MANAGE_PASSWORDS);
}
+ std::string GetManagePasswordsIcon() {
+ // The "Manage passwords" entry only has an icon if
+ // kEnablePasswordsAccountStorage is enabled.
+ std::string settings_icon;
+ if (base::FeatureList::IsEnabled(
+ password_manager::features::kEnablePasswordsAccountStorage)) {
+ return "settingsIcon";
+ }
+ return std::string();
+ }
+
protected:
autofill::PasswordFormFillData& fill_data() { return fill_data_; }
@@ -330,31 +378,29 @@ TEST_F(PasswordAutofillManagerTest, ExternalDelegatePasswordSuggestions) {
data.uses_account_store = false;
favicon::MockFaviconService favicon_service;
EXPECT_CALL(client, GetFaviconService()).WillOnce(Return(&favicon_service));
- EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(data.origin, _, _))
+ EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(data.url, _, _))
.WillOnce(Invoke(RespondWithTestIcon));
password_autofill_manager_->OnAddPasswordFillData(data);
// Show the popup and verify the suggestions.
- std::vector<Suggestion> suggestions;
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(
- _, _,
- SuggestionVectorIdsAre(
- ElementsAre(is_suggestion_on_password_field
- ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY
- : autofill::POPUP_ITEM_ID_USERNAME_ENTRY,
- autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)),
- /*autoselect_first_suggestion=*/false, PopupType::kPasswords, _))
- .WillOnce(testing::SaveArg<2>(&suggestions));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
int show_suggestion_options =
is_suggestion_on_password_field ? autofill::IS_PASSWORD_FIELD : 0;
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::string16(), show_suggestion_options,
gfx::RectF());
- ASSERT_GE(suggestions.size(), 1u);
- EXPECT_TRUE(AreImagesEqual(suggestions[0].custom_icon, kTestFavicon));
+ ASSERT_GE(open_args.suggestions.size(), 1u);
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorIdsAre(ElementsAre(
+ is_suggestion_on_password_field
+ ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY
+ : autofill::POPUP_ITEM_ID_USERNAME_ENTRY,
+ autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+ EXPECT_TRUE(
+ AreImagesEqual(open_args.suggestions[0].custom_icon, kTestFavicon));
EXPECT_CALL(*client.mock_driver(),
FillSuggestion(test_username_, test_password_));
@@ -396,33 +442,33 @@ TEST_F(PasswordAutofillManagerTest,
data.additional_logins.push_back(duplicate);
favicon::MockFaviconService favicon_service;
EXPECT_CALL(client, GetFaviconService()).WillOnce(Return(&favicon_service));
- EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(data.origin, _, _))
+ EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(data.url, _, _))
.WillOnce(Invoke(RespondWithTestIcon));
password_autofill_manager_->OnAddPasswordFillData(data);
// Show the popup and verify local and account-stored suggestion coexist.
- std::vector<Suggestion> suggestions;
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(
- _, _,
- SuggestionVectorIdsAre(ElementsAre(
- is_suggestion_on_password_field
- ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY
- : autofill::POPUP_ITEM_ID_USERNAME_ENTRY,
- is_suggestion_on_password_field
- ? autofill::POPUP_ITEM_ID_ACCOUNT_STORAGE_PASSWORD_ENTRY
- : autofill::POPUP_ITEM_ID_ACCOUNT_STORAGE_USERNAME_ENTRY,
- autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)),
- /*autoselect_first_suggestion=*/false, PopupType::kPasswords, _))
- .WillOnce(testing::SaveArg<2>(&suggestions));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::string16(),
is_suggestion_on_password_field ? autofill::IS_PASSWORD_FIELD : 0,
gfx::RectF());
- ASSERT_GE(suggestions.size(), 2u);
- EXPECT_TRUE(AreImagesEqual(suggestions[0].custom_icon, kTestFavicon));
- EXPECT_TRUE(AreImagesEqual(suggestions[1].custom_icon, kTestFavicon));
+ ASSERT_GE(open_args.suggestions.size(), 2u);
+ EXPECT_THAT(
+ open_args.suggestions,
+ SuggestionVectorIdsAre(ElementsAre(
+ is_suggestion_on_password_field
+ ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY
+ : autofill::POPUP_ITEM_ID_USERNAME_ENTRY,
+ is_suggestion_on_password_field
+ ? autofill::POPUP_ITEM_ID_ACCOUNT_STORAGE_PASSWORD_ENTRY
+ : autofill::POPUP_ITEM_ID_ACCOUNT_STORAGE_USERNAME_ENTRY,
+ autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)));
+ EXPECT_TRUE(
+ AreImagesEqual(open_args.suggestions[0].custom_icon, kTestFavicon));
+ EXPECT_TRUE(
+ AreImagesEqual(open_args.suggestions[1].custom_icon, kTestFavicon));
// When selecting the account-stored credential, make sure the filled
// password belongs to the selected credential (and not to the first match).
@@ -448,18 +494,19 @@ TEST_F(PasswordAutofillManagerTest, ShowOptInAndFillButton) {
client.SetAccountStorageOptIn(false);
// Show the popup and verify the suggestions.
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(
- _, _,
- SuggestionVectorIdsAre(ElementsAre(
- autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
- autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY,
- autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN)),
- /*autoselect_first_suggestion=*/false, PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::string16(),
autofill::SHOW_ALL | autofill::IS_PASSWORD_FIELD, gfx::RectF());
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorIdsAre(ElementsAre(
+ autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
+ autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY,
+ autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN)));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPasswords);
}
// Test that a popup without entries doesn't show "Manage all Passwords".
@@ -471,16 +518,17 @@ TEST_F(PasswordAutofillManagerTest, SuppressManageAllWithoutPasswords) {
client.SetAccountStorageOptIn(false);
// Show the popup and verify the suggestions.
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(
- _, _,
- SuggestionVectorIdsAre(ElementsAre(
- autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN)),
- /*autoselect_first_suggestion=*/false, PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::string16(),
autofill::SHOW_ALL | autofill::IS_PASSWORD_FIELD, gfx::RectF());
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorIdsAre(ElementsAre(
+ autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN)));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPasswords);
}
// Test that the popup is updated once account-stored suggestions are unlocked.
@@ -491,18 +539,19 @@ TEST_F(PasswordAutofillManagerTest, ShowResigninButton) {
client.SetNeedsReSigninForAccountStorage(true);
// Show the popup and verify the suggestions.
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(
- _, _,
- SuggestionVectorIdsAre(ElementsAre(
- autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
- autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY,
- autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_RE_SIGNIN)),
- /*autoselect_first_suggestion=*/false, PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::string16(),
autofill::SHOW_ALL | autofill::IS_PASSWORD_FIELD, gfx::RectF());
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorIdsAre(ElementsAre(
+ autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
+ autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY,
+ autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_RE_SIGNIN)));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPasswords);
}
// Test that the popup is updated once "opt in and fill" is clicked.
@@ -525,7 +574,6 @@ TEST_F(PasswordAutofillManagerTest,
autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN)),
PopupType::kPasswords))
.WillOnce(testing::SaveArg<0>(&suggestions));
- EXPECT_CALL(autofill_client, PinPopupView);
EXPECT_CALL(client, TriggerReauthForPrimaryAccount);
EXPECT_CALL(autofill_client, GetPopupSuggestions())
.WillOnce(Return(CreateTestSuggestions(/*has_opt_in_and_fill=*/true,
@@ -560,7 +608,6 @@ TEST_F(PasswordAutofillManagerTest,
POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE)),
PopupType::kPasswords))
.WillOnce(testing::SaveArg<0>(&suggestions));
- EXPECT_CALL(autofill_client, PinPopupView);
EXPECT_CALL(client, TriggerReauthForPrimaryAccount);
EXPECT_CALL(autofill_client, GetPopupSuggestions())
.WillOnce(Return(CreateTestSuggestions(/*has_opt_in_and_fill=*/false,
@@ -606,19 +653,21 @@ TEST_F(PasswordAutofillManagerTest, FailedOptInAndFillUpdatesPopup) {
.WillOnce(Return(CreateTestSuggestions(/*has_opt_in_and_fill=*/true,
/*has_opt_in_and_generate*/ false,
/*has_re_signin=*/false)));
- EXPECT_CALL(autofill_client, UpdatePopup);
-
// As soon as the waiting state is pending, the next update resets the popup.
- EXPECT_CALL(autofill_client, PinPopupView).WillOnce([&] {
+ EXPECT_CALL(autofill_client, UpdatePopup).WillOnce([&] {
testing::Mock::VerifyAndClear(&autofill_client);
- EXPECT_CALL(autofill_client, GetPopupSuggestions)
- .WillOnce(Return(CreateTestSuggestions(
+ EXPECT_CALL(autofill_client, GetReopenPopupArgs)
+ .WillOnce(Return(CreateReopenArgsWithTestSuggestions(
/*has_opt_in_and_fill=*/true, /*has_opt_in_and_generate*/ false,
/*has_re_signin=*/false)));
- EXPECT_CALL(client, TriggerReauthForPrimaryAccount)
- .WillOnce([](auto reauth_callback) {
+ EXPECT_CALL(client,
+ TriggerReauthForPrimaryAccount(
+ signin_metrics::ReauthAccessPoint::kAutofillDropdown, _))
+ .WillOnce([](auto, auto reauth_callback) {
std::move(reauth_callback).Run(ReauthSucceeded(false));
});
+ EXPECT_CALL(autofill_client, ShowAutofillPopup);
+ EXPECT_CALL(autofill_client, PinPopupView);
EXPECT_CALL(
autofill_client,
UpdatePopup(
@@ -653,19 +702,22 @@ TEST_F(PasswordAutofillManagerTest, FailedOptInAndGenerateUpdatesPopup) {
.WillOnce(Return(CreateTestSuggestions(/*has_opt_in_and_fill=*/false,
/*has_opt_in_and_generate*/ true,
/*has_re_signin=*/false)));
- EXPECT_CALL(autofill_client, UpdatePopup);
-
// As soon as the waiting state is pending, the next update resets the popup.
- EXPECT_CALL(autofill_client, PinPopupView).WillOnce([&] {
+ EXPECT_CALL(autofill_client, UpdatePopup).WillOnce([&] {
testing::Mock::VerifyAndClear(&autofill_client);
- EXPECT_CALL(autofill_client, GetPopupSuggestions)
- .WillOnce(Return(CreateTestSuggestions(/*has_opt_in_and_fill=*/false,
- /*has_opt_in_and_generate*/ true,
- /*has_re_signin=*/false)));
- EXPECT_CALL(client, TriggerReauthForPrimaryAccount)
- .WillOnce([](auto reauth_callback) {
+ EXPECT_CALL(autofill_client, GetReopenPopupArgs)
+ .WillOnce(Return(CreateReopenArgsWithTestSuggestions(
+ /*has_opt_in_and_fill=*/false, /*has_opt_in_and_generate*/ true,
+ /*has_re_signin=*/false)));
+ EXPECT_CALL(
+ client,
+ TriggerReauthForPrimaryAccount(
+ signin_metrics::ReauthAccessPoint::kGeneratePasswordDropdown, _))
+ .WillOnce([](auto, auto reauth_callback) {
std::move(reauth_callback).Run(ReauthSucceeded(false));
});
+ EXPECT_CALL(autofill_client, ShowAutofillPopup);
+ EXPECT_CALL(autofill_client, PinPopupView);
EXPECT_CALL(
autofill_client,
UpdatePopup(
@@ -700,12 +752,18 @@ TEST_F(PasswordAutofillManagerTest, SuccessfullOptInAndFillHidesPopup) {
/*has_opt_in_and_generate*/ false,
/*has_re_signin=*/false)));
EXPECT_CALL(autofill_client, UpdatePopup);
- EXPECT_CALL(autofill_client, PinPopupView);
-
- EXPECT_CALL(client, TriggerReauthForPrimaryAccount)
- .WillOnce([](auto reauth_callback) {
+ EXPECT_CALL(autofill_client, GetReopenPopupArgs)
+ .WillOnce(Return(CreateReopenArgsWithTestSuggestions(
+ /*has_opt_in_and_fill=*/true, /*has_opt_in_and_generate*/ false,
+ /*has_re_signin=*/false)));
+ EXPECT_CALL(client,
+ TriggerReauthForPrimaryAccount(
+ signin_metrics::ReauthAccessPoint::kAutofillDropdown, _))
+ .WillOnce([](auto, auto reauth_callback) {
std::move(reauth_callback).Run(ReauthSucceeded(true));
});
+ EXPECT_CALL(autofill_client, ShowAutofillPopup);
+ EXPECT_CALL(autofill_client, PinPopupView);
password_autofill_manager_->DidAcceptSuggestion(
test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN,
@@ -728,15 +786,22 @@ TEST_F(PasswordAutofillManagerTest,
/*has_opt_in_and_generate*/ true,
/*has_re_signin=*/false)));
EXPECT_CALL(autofill_client, UpdatePopup);
- EXPECT_CALL(autofill_client, PinPopupView);
-
- EXPECT_CALL(client, TriggerReauthForPrimaryAccount)
- .WillOnce([](auto reauth_callback) {
+ EXPECT_CALL(autofill_client, GetReopenPopupArgs)
+ .WillOnce(Return(CreateReopenArgsWithTestSuggestions(
+ /*has_opt_in_and_fill=*/false, /*has_opt_in_and_generate*/ true,
+ /*has_re_signin=*/false)));
+ EXPECT_CALL(
+ client,
+ TriggerReauthForPrimaryAccount(
+ signin_metrics::ReauthAccessPoint::kGeneratePasswordDropdown, _))
+ .WillOnce([](auto, auto reauth_callback) {
std::move(reauth_callback).Run(ReauthSucceeded(true));
});
- EXPECT_CALL(
- autofill_client,
- HideAutofillPopup(autofill::PopupHidingReason::kAcceptSuggestion));
+ EXPECT_CALL(autofill_client, ShowAutofillPopup);
+ EXPECT_CALL(autofill_client, PinPopupView);
+ EXPECT_CALL(autofill_client,
+ HideAutofillPopup(autofill::PopupHidingReason::kAcceptSuggestion))
+ .Times(testing::AtLeast(1));
EXPECT_CALL(client, GeneratePassword());
password_autofill_manager_->DidAcceptSuggestion(
@@ -748,6 +813,7 @@ TEST_F(PasswordAutofillManagerTest,
TEST_F(PasswordAutofillManagerTest, SuccessfullOptInMayShowEmptyState) {
TestPasswordManagerClient client;
NiceMock<MockAutofillClient> autofill_client;
+ base::HistogramTester histograms;
InitializePasswordAutofillManager(&client, &autofill_client);
client.SetAccountStorageOptIn(true);
testing::Mock::VerifyAndClearExpectations(&autofill_client);
@@ -771,6 +837,8 @@ TEST_F(PasswordAutofillManagerTest, SuccessfullOptInMayShowEmptyState) {
password_autofill_manager_->DeleteFillData();
password_autofill_manager_->OnNoCredentialsFound();
+ histograms.ExpectBucketCount(
+ kCredentialsCountFromAccountStoreAfterUnlockHistogram, 0, 1);
}
// Test that the popup is updated once "opt in and fill" is clicked".
@@ -778,6 +846,7 @@ TEST_F(PasswordAutofillManagerTest,
AddOnFillDataAfterOptInAndFillPopulatesPopup) {
TestPasswordManagerClient client;
NiceMock<MockAutofillClient> autofill_client;
+ base::HistogramTester histograms;
InitializePasswordAutofillManager(&client, &autofill_client);
client.SetAccountStorageOptIn(true);
testing::Mock::VerifyAndClearExpectations(&autofill_client);
@@ -790,9 +859,11 @@ TEST_F(PasswordAutofillManagerTest,
additional.username = base::ASCIIToUTF16("bar.foo@example.com");
new_data.additional_logins.push_back(std::move(additional));
EXPECT_CALL(autofill_client, GetPopupSuggestions())
- .WillRepeatedly(Return(CreateTestSuggestions(
- /*has_opt_in_and_fill=*/false, /*has_opt_in_and_generate*/ false,
- /*has_re_signin=*/false)));
+ .WillRepeatedly(Return(SetLoading(
+ CreateTestSuggestions(
+ /*has_opt_in_and_fill=*/true, /*has_opt_in_and_generate*/ false,
+ /*has_re_signin=*/false),
+ /*index_of_loading_element=*/2))); // Opt-in is at third position.
EXPECT_CALL(autofill_client,
HideAutofillPopup(autofill::PopupHidingReason::kStaleData));
EXPECT_CALL(
@@ -805,6 +876,8 @@ TEST_F(PasswordAutofillManagerTest,
password_autofill_manager_->DeleteFillData();
password_autofill_manager_->OnAddPasswordFillData(new_data);
+ histograms.ExpectBucketCount(
+ kCredentialsCountFromAccountStoreAfterUnlockHistogram, 1, 1);
}
// Test that OnShowPasswordSuggestions correctly matches the given FormFieldData
@@ -827,44 +900,40 @@ TEST_F(PasswordAutofillManagerTest, ExtractSuggestions) {
// First, simulate displaying suggestions matching an empty prefix. Also
// verify that both the values and labels are filled correctly. The 'value'
// should be the user name; the 'label' should be the realm.
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(
- element_bounds, _,
- testing::AllOf(
- SuggestionVectorValuesAre(testing::UnorderedElementsAre(
- test_username_, additional.username,
- GetManagePasswordsTitle())),
- SuggestionVectorLabelsAre(testing::AllOf(
- testing::Contains(base::UTF8ToUTF16("foo.com")),
- testing::Contains(base::UTF8ToUTF16("foobarrealm.org"))))),
- /*autoselect_first_suggestion=*/false, PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::string16(), 0, element_bounds);
+ EXPECT_THAT(
+ open_args.suggestions,
+ SuggestionVectorValuesAre(testing::UnorderedElementsAre(
+ test_username_, additional.username, GetManagePasswordsTitle())));
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorLabelsAre(
+ testing::Contains(base::UTF8ToUTF16("foo.com"))));
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorLabelsAre(
+ testing::Contains(base::UTF8ToUTF16("foobarrealm.org"))));
// Now simulate displaying suggestions matching "John".
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(element_bounds, _,
- SuggestionVectorValuesAre(ElementsAre(
- additional.username, GetManagePasswordsTitle())),
- /*autoselect_first_suggestion=*/false,
- PopupType::kPasswords, _));
-
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("John"), 0, element_bounds);
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorValuesAre(
+ ElementsAre(additional.username, GetManagePasswordsTitle())));
// Finally, simulate displaying all suggestions, without any prefix matching.
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(
- element_bounds, _,
- SuggestionVectorValuesAre(ElementsAre(
- test_username_, additional.username, GetManagePasswordsTitle())),
- /*autoselect_first_suggestion=*/false, PopupType::kPasswords, _));
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("xyz"), autofill::SHOW_ALL,
element_bounds);
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorValuesAre(ElementsAre(
+ test_username_, additional.username,
+ GetManagePasswordsTitle())));
}
// Verify that, for Android application credentials, the prettified realms of
@@ -886,17 +955,19 @@ TEST_F(PasswordAutofillManagerTest, PrettifiedAndroidRealmsAreShownAsLabels) {
password_autofill_manager_->OnAddPasswordFillData(data);
- EXPECT_CALL(autofill_client,
- ShowAutofillPopup(_, _,
- SuggestionVectorLabelsAre(testing::AllOf(
- testing::Contains(base::ASCIIToUTF16(
- "android://com.example1.android/")),
- testing::Contains(base::ASCIIToUTF16(
- "android://com.example2.android/")))),
- /*autoselect_first_suggestion=*/false,
- PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::string16(), 0, gfx::RectF());
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorLabelsAre(testing::Contains(
+ base::ASCIIToUTF16("android://com.example2.android/"))));
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorLabelsAre(testing::Contains(
+ base::ASCIIToUTF16("android://com.example1.android/"))));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPasswords);
}
TEST_F(PasswordAutofillManagerTest, FillSuggestionPasswordField) {
@@ -914,15 +985,17 @@ TEST_F(PasswordAutofillManagerTest, FillSuggestionPasswordField) {
password_autofill_manager_->OnAddPasswordFillData(data);
- EXPECT_CALL(autofill_client,
- ShowAutofillPopup(element_bounds, _,
- SuggestionVectorValuesAre(ElementsAre(
- test_username_, GetManagePasswordsTitle())),
- /*autoselect_first_suggestion=*/false,
- PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, test_username_, autofill::IS_PASSWORD_FIELD,
element_bounds);
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorValuesAre(
+ ElementsAre(test_username_, GetManagePasswordsTitle())));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPasswords);
}
// Verify that typing "foo" into the username field will match usernames
@@ -950,15 +1023,16 @@ TEST_F(PasswordAutofillManagerTest, DisplaySuggestionsWithMatchingTokens) {
password_autofill_manager_->OnAddPasswordFillData(data);
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(
- element_bounds, _,
- SuggestionVectorValuesAre(testing::UnorderedElementsAre(
- username, additional.username, GetManagePasswordsTitle())),
- /*autoselect_first_suggestion=*/false, PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo"), 0, element_bounds);
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorValuesAre(testing::UnorderedElementsAre(
+ username, additional.username, GetManagePasswordsTitle())));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPasswords);
}
// Verify that typing "oo" into the username field will not match any usernames
@@ -1018,16 +1092,17 @@ TEST_F(PasswordAutofillManagerTest,
password_autofill_manager_->OnAddPasswordFillData(data);
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(element_bounds, _,
- SuggestionVectorValuesAre(ElementsAre(
- additional.username, GetManagePasswordsTitle())),
- /*autoselect_first_suggestion=*/false,
- PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo@exam"), 0,
element_bounds);
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorValuesAre(
+ ElementsAre(additional.username, GetManagePasswordsTitle())));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPasswords);
}
// Verify that typing "example" into the username field will match and order
@@ -1057,16 +1132,17 @@ TEST_F(PasswordAutofillManagerTest,
password_autofill_manager_->OnAddPasswordFillData(data);
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(
- element_bounds, _,
- SuggestionVectorValuesAre(ElementsAre(username, additional.username,
- GetManagePasswordsTitle())),
- /*autoselect_first_suggestion=*/false, PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo"), false,
element_bounds);
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorValuesAre(ElementsAre(
+ username, additional.username, GetManagePasswordsTitle())));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPasswords);
}
TEST_F(PasswordAutofillManagerTest, PreviewAndFillEmptyUsernameSuggestion) {
@@ -1126,12 +1202,9 @@ TEST_F(PasswordAutofillManagerTest, ShowAllPasswordsOptionOnPasswordField) {
password_autofill_manager_->OnAddPasswordFillData(data);
- EXPECT_CALL(autofill_client,
- ShowAutofillPopup(element_bounds, _,
- SuggestionVectorValuesAre(ElementsAre(
- test_username_, GetManagePasswordsTitle())),
- /*autoselect_first_suggestion=*/false,
- PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, test_username_, autofill::IS_PASSWORD_FIELD,
@@ -1139,6 +1212,9 @@ TEST_F(PasswordAutofillManagerTest, ShowAllPasswordsOptionOnPasswordField) {
histograms.ExpectUniqueSample(kDropdownShownHistogram,
metrics_util::PasswordDropdownState::kStandard,
1);
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorValuesAre(
+ ElementsAre(test_username_, GetManagePasswordsTitle())));
// Expect a sample only in the shown histogram.
histograms.ExpectUniqueSample(
@@ -1193,14 +1269,16 @@ TEST_F(PasswordAutofillManagerTest, ShowAllPasswordsOptionOnNonPasswordField) {
password_autofill_manager_->OnAddPasswordFillData(data);
- EXPECT_CALL(autofill_client,
- ShowAutofillPopup(element_bounds, _,
- SuggestionVectorValuesAre(ElementsAre(
- test_username_, GetManagePasswordsTitle())),
- /*autoselect_first_suggestion=*/false,
- PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, test_username_, 0, element_bounds);
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorValuesAre(
+ ElementsAre(test_username_, GetManagePasswordsTitle())));
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPasswords);
}
TEST_F(PasswordAutofillManagerTest,
@@ -1230,22 +1308,15 @@ TEST_F(PasswordAutofillManagerTest,
favicon::MockFaviconService favicon_service;
EXPECT_CALL(client, GetFaviconService()).WillOnce(Return(&favicon_service));
- EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(data.origin, _, _));
+ EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(data.url, _, _));
password_autofill_manager_->OnAddPasswordFillData(data);
- // Bring up the drop-down with the generaion option.
+ // Bring up the drop-down with the generation option.
base::string16 generation_string =
l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_GENERATE_PASSWORD);
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(element_bounds, base::i18n::RIGHT_TO_LEFT,
- AllOf(SuggestionVectorValuesAre(
- ElementsAre(test_username_, generation_string,
- GetManagePasswordsTitle())),
- SuggestionVectorIconsAre(ElementsAre(
- "globeIcon", "keyIcon", std::string()))),
- /*autoselect_first_suggestion=*/false,
- PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
EXPECT_TRUE(
password_autofill_manager_->MaybeShowPasswordSuggestionsWithGeneration(
element_bounds, base::i18n::RIGHT_TO_LEFT,
@@ -1253,6 +1324,12 @@ TEST_F(PasswordAutofillManagerTest,
histograms.ExpectUniqueSample(
kDropdownShownHistogram,
metrics_util::PasswordDropdownState::kStandardGenerate, 1);
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorIconsAre(ElementsAre("globeIcon", "keyIcon",
+ GetManagePasswordsIcon())));
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorValuesAre(ElementsAre(
+ test_username_, generation_string,
+ GetManagePasswordsTitle())));
// Click "Generate password".
EXPECT_CALL(client, GeneratePassword());
@@ -1277,26 +1354,25 @@ TEST_F(PasswordAutofillManagerTest,
favicon::MockFaviconService favicon_service;
EXPECT_CALL(client, GetFaviconService()).WillOnce(Return(&favicon_service));
- EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(data.origin, _, _));
+ EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(data.url, _, _));
password_autofill_manager_->OnAddPasswordFillData(data);
base::string16 generation_string =
l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_GENERATE_PASSWORD);
- EXPECT_CALL(
- autofill_client,
- ShowAutofillPopup(
- element_bounds, base::i18n::RIGHT_TO_LEFT,
- AllOf(
- SuggestionVectorValuesAre(
- ElementsAre(generation_string, GetManagePasswordsTitle())),
- SuggestionVectorIconsAre(ElementsAre("keyIcon", std::string()))),
- /*autoselect_first_suggestion=*/false, PopupType::kPasswords, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
EXPECT_TRUE(
password_autofill_manager_->MaybeShowPasswordSuggestionsWithGeneration(
element_bounds, base::i18n::RIGHT_TO_LEFT,
/*show_password_suggestions=*/false));
+ EXPECT_THAT(open_args.suggestions, SuggestionVectorIconsAre(ElementsAre(
+ "keyIcon", GetManagePasswordsIcon())));
+ EXPECT_THAT(open_args.suggestions,
+ SuggestionVectorValuesAre(
+ ElementsAre(generation_string, GetManagePasswordsTitle())));
}
// Test that if the "opt in and generate" button gets displayed, the regular
@@ -1316,25 +1392,26 @@ TEST_F(PasswordAutofillManagerTest,
favicon::MockFaviconService favicon_service;
EXPECT_CALL(client, GetFaviconService()).WillOnce(Return(&favicon_service));
- EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(data.origin, _, _));
+ EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(data.url, _, _));
password_autofill_manager_->OnAddPasswordFillData(data);
auto opt_in_and_generate_id = static_cast<int>(
autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE);
auto regular_generate_id =
static_cast<int>(autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY);
- EXPECT_CALL(autofill_client,
- ShowAutofillPopup(
- _, _,
- AllOf(Contains(Field(&autofill::Suggestion::frontend_id,
- Eq(opt_in_and_generate_id))),
- Not(Contains(Field(&autofill::Suggestion::frontend_id,
- Eq(regular_generate_id))))),
- _, _, _));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->MaybeShowPasswordSuggestionsWithGeneration(
gfx::RectF(), base::i18n::RIGHT_TO_LEFT,
/*show_password_suggestions=*/true);
+ EXPECT_THAT(open_args.suggestions,
+ Not(Contains(Field(&autofill::Suggestion::frontend_id,
+ Eq(regular_generate_id)))));
+ EXPECT_THAT(open_args.suggestions,
+ Contains(Field(&autofill::Suggestion::frontend_id,
+ Eq(opt_in_and_generate_id))));
}
TEST_F(PasswordAutofillManagerTest, DisplayAccountSuggestionsIndicatorIcon) {
@@ -1353,16 +1430,16 @@ TEST_F(PasswordAutofillManagerTest, DisplayAccountSuggestionsIndicatorIcon) {
password_autofill_manager_->OnAddPasswordFillData(data);
- std::vector<autofill::Suggestion> suggestions;
- EXPECT_CALL(autofill_client,
- ShowAutofillPopup(element_bounds, _, _,
- /*autoselect_first_suggestion=*/false,
- PopupType::kPasswords, _))
- .WillOnce(testing::SaveArg<2>(&suggestions));
+ autofill::AutofillClient::PopupOpenArgs open_args;
+ EXPECT_CALL(autofill_client, ShowAutofillPopup)
+ .WillOnce(testing::SaveArg<0>(&open_args));
password_autofill_manager_->OnShowPasswordSuggestions(
base::i18n::RIGHT_TO_LEFT, base::string16(), false, element_bounds);
- ASSERT_THAT(suggestions.size(), testing::Ge(1u)); // No footer on Android.
- EXPECT_THAT(suggestions[0].store_indicator_icon, "google");
+ ASSERT_THAT(open_args.suggestions.size(),
+ testing::Ge(1u)); // No footer on Android.
+ EXPECT_THAT(open_args.suggestions[0].store_indicator_icon, "google");
+ EXPECT_FALSE(open_args.autoselect_first_suggestion);
+ EXPECT_EQ(open_args.popup_type, PopupType::kPasswords);
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_bubble_experiment_unittest.cc b/chromium/components/password_manager/core/browser/password_bubble_experiment_unittest.cc
index d2643e08e9b..044be044686 100644
--- a/chromium/components/password_manager/core/browser/password_bubble_experiment_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_bubble_experiment_unittest.cc
@@ -6,6 +6,7 @@
#include <ostream>
+#include "base/feature_list.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "components/password_manager/core/common/password_manager_features.h"
@@ -108,6 +109,13 @@ TEST_F(PasswordManagerPasswordBubbleExperimentTest,
#if !defined(OS_CHROMEOS)
TEST_F(PasswordManagerPasswordBubbleExperimentTest, ReviveSignInPasswordPromo) {
+ // If kEnablePasswordsAccountStorage is enabled, then the password manager
+ // bubble never shows Sync promos, so this test doesn't apply.
+ if (base::FeatureList::IsEnabled(
+ password_manager::features::kEnablePasswordsAccountStorage)) {
+ return;
+ }
+
sync_service()->SetDisableReasons(syncer::SyncService::DisableReasonSet());
sync_service()->SetFirstSetupComplete(false);
sync_service()->SetTransportState(
diff --git a/chromium/components/password_manager/core/browser/password_feature_manager.h b/chromium/components/password_manager/core/browser/password_feature_manager.h
index 00c9775763c..b6dce401651 100644
--- a/chromium/components/password_manager/core/browser/password_feature_manager.h
+++ b/chromium/components/password_manager/core/browser/password_feature_manager.h
@@ -44,11 +44,12 @@ class PasswordFeatureManager {
// associated settings (e.g. default store choice).
virtual void OptOutOfAccountStorageAndClearSettings() = 0;
- // Whether it makes sense to ask the user about the store when saving a
- // password (i.e. profile or account store). This is true if the user has
- // opted in already, or hasn't opted in but all other requirements are met
- // (i.e. there is a signed-in user, Sync-the-feature is not enabled, etc).
- virtual bool ShouldShowPasswordStorePicker() const = 0;
+ // Whether it makes sense to ask the user to move a password or about the
+ // store when saving a password (i.e. profile or account store). This is true
+ // if the user has opted in already, or hasn't opted in but all other
+ // requirements are met (i.e. there is a signed-in user, Sync-the-feature is
+ // not enabled, etc).
+ virtual bool ShouldShowAccountStorageBubbleUi() const = 0;
// Sets the default password store selected by user in prefs. This store is
// used for saving new credentials and adding blacking listing entries.
diff --git a/chromium/components/password_manager/core/browser/password_feature_manager_impl.cc b/chromium/components/password_manager/core/browser/password_feature_manager_impl.cc
index b04e8b1479f..ed983ea7a67 100644
--- a/chromium/components/password_manager/core/browser/password_feature_manager_impl.cc
+++ b/chromium/components/password_manager/core/browser/password_feature_manager_impl.cc
@@ -59,9 +59,9 @@ void PasswordFeatureManagerImpl::SetDefaultPasswordStore(
features_util::SetDefaultPasswordStore(pref_service_, sync_service_, store);
}
-bool PasswordFeatureManagerImpl::ShouldShowPasswordStorePicker() const {
- return features_util::ShouldShowPasswordStorePicker(pref_service_,
- sync_service_);
+bool PasswordFeatureManagerImpl::ShouldShowAccountStorageBubbleUi() const {
+ return features_util::ShouldShowAccountStorageBubbleUi(pref_service_,
+ sync_service_);
}
PasswordForm::Store PasswordFeatureManagerImpl::GetDefaultPasswordStore()
diff --git a/chromium/components/password_manager/core/browser/password_feature_manager_impl.h b/chromium/components/password_manager/core/browser/password_feature_manager_impl.h
index 9793f1bfc86..8505e3c343c 100644
--- a/chromium/components/password_manager/core/browser/password_feature_manager_impl.h
+++ b/chromium/components/password_manager/core/browser/password_feature_manager_impl.h
@@ -32,7 +32,7 @@ class PasswordFeatureManagerImpl : public PasswordFeatureManager {
void OptInToAccountStorage() override;
void OptOutOfAccountStorageAndClearSettings() override;
- bool ShouldShowPasswordStorePicker() const override;
+ bool ShouldShowAccountStorageBubbleUi() const override;
void SetDefaultPasswordStore(
const autofill::PasswordForm::Store& store) override;
diff --git a/chromium/components/password_manager/core/browser/password_form_filling.cc b/chromium/components/password_manager/core/browser/password_form_filling.cc
index b4c65f63292..b6158b072dc 100644
--- a/chromium/components/password_manager/core/browser/password_form_filling.cc
+++ b/chromium/components/password_manager/core/browser/password_form_filling.cc
@@ -4,6 +4,8 @@
#include "components/password_manager/core/browser/password_form_filling.h"
+#include <memory>
+
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
@@ -13,6 +15,7 @@
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
+#include "components/password_manager/core/browser/password_feature_manager.h"
#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
@@ -94,8 +97,8 @@ void Autofill(PasswordManagerClient* client,
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client->GetLogManager()));
+ logger = std::make_unique<BrowserSavePasswordProgressLogger>(
+ client->GetLogManager());
logger->LogMessage(Logger::STRING_PASSWORDMANAGER_AUTOFILL);
}
@@ -110,7 +113,8 @@ void Autofill(PasswordManagerClient* client,
PreferredRealmIsFromAndroid(fill_data));
driver->FillPasswordForm(fill_data);
- client->PasswordWasAutofilled(best_matches, form_for_autofill.origin,
+ client->PasswordWasAutofilled(best_matches,
+ url::Origin::Create(form_for_autofill.url),
&federated_matches);
}
@@ -138,7 +142,10 @@ LikelyFormFilling SendFillInformationToRenderer(
}
if (best_matches.empty()) {
- driver->InformNoSavedCredentials();
+ bool should_show_popup_without_passwords =
+ client->GetPasswordFeatureManager()->ShouldShowAccountStorageOptIn() ||
+ client->GetPasswordFeatureManager()->ShouldShowAccountStorageReSignin();
+ driver->InformNoSavedCredentials(should_show_popup_without_passwords);
metrics_recorder->RecordFillEvent(
PasswordFormMetricsRecorder::kManagerFillEventNoCredential);
return LikelyFormFilling::kNoFilling;
@@ -169,7 +176,7 @@ LikelyFormFilling SendFillInformationToRenderer(
} else if (no_sign_in_form) {
// If the parser did not find a current password element, don't fill.
wait_for_username_reason = WaitForUsernameReason::kFormNotGoodForFilling;
- } else if (!client->IsMainFrameSecure()) {
+ } else if (!client->IsCommittedMainFrameSecure()) {
wait_for_username_reason = WaitForUsernameReason::kInsecureOrigin;
} else if (autofill::IsTouchToFillEnabled()) {
wait_for_username_reason = WaitForUsernameReason::kTouchToFill;
@@ -217,7 +224,7 @@ PasswordFormFillData CreatePasswordFormFillData(
result.form_renderer_id = form_on_page.form_data.unique_renderer_id;
result.name = form_on_page.form_data.name;
- result.origin = form_on_page.origin;
+ result.url = form_on_page.url;
result.action = form_on_page.action;
result.uses_account_store = preferred_match.IsUsingAccountStore();
result.wait_for_username = wait_for_username;
diff --git a/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc b/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc
index a65babb7577..98935fe7b0d 100644
--- a/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc
@@ -52,26 +52,23 @@ constexpr char kSyncedPassword[] = "password";
class MockPasswordManagerDriver : public StubPasswordManagerDriver {
public:
- MockPasswordManagerDriver() {}
-
- ~MockPasswordManagerDriver() override = default;
-
- MOCK_CONST_METHOD0(GetId, int());
- MOCK_METHOD1(FillPasswordForm, void(const PasswordFormFillData&));
- MOCK_METHOD0(InformNoSavedCredentials, void());
- MOCK_METHOD1(ShowInitialPasswordAccountSuggestions,
- void(const PasswordFormFillData&));
- MOCK_METHOD1(AllowPasswordGenerationForForm, void(const PasswordForm&));
+ MOCK_METHOD(int, GetId, (), (const, override));
+ MOCK_METHOD(void,
+ FillPasswordForm,
+ (const PasswordFormFillData&),
+ (override));
+ MOCK_METHOD(void, InformNoSavedCredentials, (bool), (override));
};
class MockPasswordManagerClient : public StubPasswordManagerClient {
public:
- MOCK_METHOD3(PasswordWasAutofilled,
- void(const std::vector<const PasswordForm*>&,
- const GURL&,
- const std::vector<const PasswordForm*>*));
-
- MOCK_CONST_METHOD0(IsMainFrameSecure, bool());
+ MOCK_METHOD(void,
+ PasswordWasAutofilled,
+ (const std::vector<const PasswordForm*>&,
+ const url::Origin&,
+ const std::vector<const PasswordForm*>*),
+ (override));
+ MOCK_METHOD(bool, IsCommittedMainFrameSecure, (), (const, override));
};
PasswordForm CreateForm(std::string username,
@@ -105,9 +102,9 @@ PasswordFormFillData::LoginCollection::const_iterator FindPasswordByUsername(
class PasswordFormFillingTest : public testing::Test {
public:
PasswordFormFillingTest() {
- ON_CALL(client_, IsMainFrameSecure()).WillByDefault(Return(true));
+ ON_CALL(client_, IsCommittedMainFrameSecure()).WillByDefault(Return(true));
- observed_form_.origin = GURL("https://accounts.google.com/a/LoginAuth");
+ observed_form_.url = GURL("https://accounts.google.com/a/LoginAuth");
observed_form_.action = GURL("https://accounts.google.com/a/Login");
observed_form_.username_element = ASCIIToUTF16("Email");
observed_form_.username_element_renderer_id =
@@ -120,21 +117,20 @@ class PasswordFormFillingTest : public testing::Test {
observed_form_.form_data.name = ASCIIToUTF16("the-form-name");
saved_match_ = observed_form_;
- saved_match_.origin =
- GURL("https://accounts.google.com/a/ServiceLoginAuth");
+ saved_match_.url = GURL("https://accounts.google.com/a/ServiceLoginAuth");
saved_match_.action = GURL("https://accounts.google.com/a/ServiceLogin");
saved_match_.username_value = ASCIIToUTF16("test@gmail.com");
saved_match_.password_value = ASCIIToUTF16("test1");
psl_saved_match_ = saved_match_;
psl_saved_match_.is_public_suffix_match = true;
- psl_saved_match_.origin =
+ psl_saved_match_.url =
GURL("https://m.accounts.google.com/a/ServiceLoginAuth");
psl_saved_match_.action = GURL("https://m.accounts.google.com/a/Login");
psl_saved_match_.signon_realm = "https://m.accounts.google.com";
metrics_recorder_ = base::MakeRefCounted<PasswordFormMetricsRecorder>(
- true, client_.GetUkmSourceId());
+ true, client_.GetUkmSourceId(), /*pref_service=*/nullptr);
}
protected:
@@ -150,9 +146,8 @@ class PasswordFormFillingTest : public testing::Test {
TEST_F(PasswordFormFillingTest, NoSavedCredentials) {
std::vector<const PasswordForm*> best_matches;
- EXPECT_CALL(driver_, InformNoSavedCredentials());
+ EXPECT_CALL(driver_, InformNoSavedCredentials(_));
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
- EXPECT_CALL(driver_, ShowInitialPasswordAccountSuggestions(_)).Times(0);
LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
&client_, &driver_, observed_form_, best_matches, federated_matches_,
@@ -168,11 +163,10 @@ TEST_F(PasswordFormFillingTest, Autofill) {
another_saved_match.password_value += ASCIIToUTF16("1");
best_matches.push_back(&another_saved_match);
- EXPECT_CALL(driver_, InformNoSavedCredentials()).Times(0);
+ EXPECT_CALL(driver_, InformNoSavedCredentials(_)).Times(0);
PasswordFormFillData fill_data;
EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
- EXPECT_CALL(driver_, ShowInitialPasswordAccountSuggestions(_)).Times(0);
- EXPECT_CALL(client_, PasswordWasAutofilled(_, _, _));
+ EXPECT_CALL(client_, PasswordWasAutofilled);
LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
&client_, &driver_, observed_form_, best_matches, federated_matches_,
@@ -181,7 +175,7 @@ TEST_F(PasswordFormFillingTest, Autofill) {
// Check that the message to the renderer (i.e. |fill_data|) is filled
// correctly.
- EXPECT_EQ(observed_form_.origin, fill_data.origin);
+ EXPECT_EQ(observed_form_.url, fill_data.url);
EXPECT_FALSE(fill_data.wait_for_username);
EXPECT_EQ(observed_form_.username_element, fill_data.username_field.name);
EXPECT_EQ(saved_match_.username_value, fill_data.username_field.value);
@@ -237,7 +231,7 @@ TEST_F(PasswordFormFillingTest, TestFillOnLoadSuggestion) {
PasswordFormFillData fill_data;
EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
- EXPECT_CALL(client_, PasswordWasAutofilled(_, _, _));
+ EXPECT_CALL(client_, PasswordWasAutofilled);
LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
&client_, &driver_, observed_form, best_matches, federated_matches_,
@@ -256,11 +250,10 @@ TEST_F(PasswordFormFillingTest, TestFillOnLoadSuggestion) {
TEST_F(PasswordFormFillingTest, AutofillPSLMatch) {
std::vector<const PasswordForm*> best_matches = {&psl_saved_match_};
- EXPECT_CALL(driver_, InformNoSavedCredentials()).Times(0);
+ EXPECT_CALL(driver_, InformNoSavedCredentials(_)).Times(0);
PasswordFormFillData fill_data;
EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
- EXPECT_CALL(driver_, ShowInitialPasswordAccountSuggestions(_)).Times(0);
- EXPECT_CALL(client_, PasswordWasAutofilled(_, _, _));
+ EXPECT_CALL(client_, PasswordWasAutofilled);
LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
&client_, &driver_, observed_form_, best_matches, federated_matches_,
@@ -269,7 +262,7 @@ TEST_F(PasswordFormFillingTest, AutofillPSLMatch) {
// Check that the message to the renderer (i.e. |fill_data|) is filled
// correctly.
- EXPECT_EQ(observed_form_.origin, fill_data.origin);
+ EXPECT_EQ(observed_form_.url, fill_data.url);
EXPECT_TRUE(fill_data.wait_for_username);
EXPECT_EQ(psl_saved_match_.signon_realm, fill_data.preferred_realm);
EXPECT_EQ(observed_form_.username_element, fill_data.username_field.name);
@@ -280,20 +273,19 @@ TEST_F(PasswordFormFillingTest, AutofillPSLMatch) {
TEST_F(PasswordFormFillingTest, NoAutofillOnHttp) {
PasswordForm observed_http_form = observed_form_;
- observed_http_form.origin = GURL("http://accounts.google.com/a/LoginAuth");
+ observed_http_form.url = GURL("http://accounts.google.com/a/LoginAuth");
observed_http_form.action = GURL("http://accounts.google.com/a/Login");
observed_http_form.signon_realm = "http://accounts.google.com";
PasswordForm saved_http_match = saved_match_;
- saved_http_match.origin =
- GURL("http://accounts.google.com/a/ServiceLoginAuth");
+ saved_http_match.url = GURL("http://accounts.google.com/a/ServiceLoginAuth");
saved_http_match.action = GURL("http://accounts.google.com/a/ServiceLogin");
saved_http_match.signon_realm = "http://accounts.google.com";
ASSERT_FALSE(GURL(saved_http_match.signon_realm).SchemeIsCryptographic());
std::vector<const PasswordForm*> best_matches = {&saved_http_match};
- EXPECT_CALL(client_, IsMainFrameSecure).WillOnce(Return(false));
+ EXPECT_CALL(client_, IsCommittedMainFrameSecure).WillOnce(Return(false));
LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
&client_, &driver_, observed_http_form, best_matches, federated_matches_,
&saved_http_match, metrics_recorder_.get());
@@ -326,7 +318,7 @@ TEST_F(PasswordFormFillingTest, TouchToFill) {
TEST(PasswordFormFillDataTest, TestSinglePreferredMatch) {
// Create the current form on the page.
PasswordForm form_on_page;
- form_on_page.origin = GURL("https://foo.com/");
+ form_on_page.url = GURL("https://foo.com/");
form_on_page.action = GURL("https://foo.com/login");
form_on_page.username_element = ASCIIToUTF16("username");
form_on_page.username_value = ASCIIToUTF16(kPreferredUsername);
@@ -338,7 +330,7 @@ TEST(PasswordFormFillDataTest, TestSinglePreferredMatch) {
// Create an exact match in the database.
PasswordForm preferred_match;
- preferred_match.origin = GURL("https://foo.com/");
+ preferred_match.url = GURL("https://foo.com/");
preferred_match.action = GURL("https://foo.com/login");
preferred_match.username_element = ASCIIToUTF16("username");
preferred_match.username_value = ASCIIToUTF16(kPreferredUsername);
@@ -375,7 +367,7 @@ TEST(PasswordFormFillDataTest, TestSinglePreferredMatch) {
TEST(PasswordFormFillDataTest, TestPublicSuffixDomainMatching) {
// Create the current form on the page.
PasswordForm form_on_page;
- form_on_page.origin = GURL("https://foo.com/");
+ form_on_page.url = GURL("https://foo.com/");
form_on_page.action = GURL("https://foo.com/login");
form_on_page.username_element = ASCIIToUTF16("username");
form_on_page.username_value = ASCIIToUTF16(kPreferredUsername);
@@ -387,7 +379,7 @@ TEST(PasswordFormFillDataTest, TestPublicSuffixDomainMatching) {
// Create a match from the database that matches using public suffix.
PasswordForm preferred_match;
- preferred_match.origin = GURL("https://mobile.foo.com/");
+ preferred_match.url = GURL("https://mobile.foo.com/");
preferred_match.action = GURL("https://mobile.foo.com/login");
preferred_match.username_element = ASCIIToUTF16("username");
preferred_match.username_value = ASCIIToUTF16(kPreferredUsername);
@@ -401,7 +393,7 @@ TEST(PasswordFormFillDataTest, TestPublicSuffixDomainMatching) {
// Create a match that matches exactly, so |is_public_suffix_match| has a
// default value false.
PasswordForm exact_match;
- exact_match.origin = GURL("https://foo.com/");
+ exact_match.url = GURL("https://foo.com/");
exact_match.action = GURL("https://foo.com/login");
exact_match.username_element = ASCIIToUTF16("username");
exact_match.username_value = ASCIIToUTF16("test1@gmail.com");
@@ -414,7 +406,7 @@ TEST(PasswordFormFillDataTest, TestPublicSuffixDomainMatching) {
// Create a match that was matched using public suffix, so
// |is_public_suffix_match| == true.
PasswordForm public_suffix_match;
- public_suffix_match.origin = GURL("https://foo.com/");
+ public_suffix_match.url = GURL("https://foo.com/");
public_suffix_match.action = GURL("https://foo.com/login");
public_suffix_match.username_element = ASCIIToUTF16("username");
public_suffix_match.username_value = ASCIIToUTF16("test2@gmail.com");
@@ -456,7 +448,7 @@ TEST(PasswordFormFillDataTest, TestPublicSuffixDomainMatching) {
TEST(PasswordFormFillDataTest, TestAffiliationMatch) {
// Create the current form on the page.
PasswordForm form_on_page;
- form_on_page.origin = GURL("https://foo.com/");
+ form_on_page.url = GURL("https://foo.com/");
form_on_page.action = GURL("https://foo.com/login");
form_on_page.username_element = ASCIIToUTF16("username");
form_on_page.username_value = ASCIIToUTF16(kPreferredUsername);
@@ -468,7 +460,7 @@ TEST(PasswordFormFillDataTest, TestAffiliationMatch) {
// Create a match from the database that matches using affiliation.
PasswordForm preferred_match;
- preferred_match.origin = GURL("android://hash@foo.com/");
+ preferred_match.url = GURL("android://hash@foo.com/");
preferred_match.username_value = ASCIIToUTF16(kPreferredUsername);
preferred_match.password_value = ASCIIToUTF16(kPreferredPassword);
preferred_match.signon_realm = "android://hash@foo.com/";
@@ -477,7 +469,7 @@ TEST(PasswordFormFillDataTest, TestAffiliationMatch) {
// Create a match that matches exactly, so |is_affiliation_based_match| has a
// default value false.
PasswordForm exact_match;
- exact_match.origin = GURL("https://foo.com/");
+ exact_match.url = GURL("https://foo.com/");
exact_match.action = GURL("https://foo.com/login");
exact_match.username_element = ASCIIToUTF16("username");
exact_match.username_value = ASCIIToUTF16("test1@gmail.com");
@@ -490,7 +482,7 @@ TEST(PasswordFormFillDataTest, TestAffiliationMatch) {
// Create a match that was matched using public suffix, so
// |is_public_suffix_match| == true.
PasswordForm affiliated_match;
- affiliated_match.origin = GURL("android://hash@foo1.com/");
+ affiliated_match.url = GURL("android://hash@foo1.com/");
affiliated_match.username_value = ASCIIToUTF16("test2@gmail.com");
affiliated_match.password_value = ASCIIToUTF16(kPreferredPassword);
affiliated_match.is_affiliation_based_match = true;
@@ -524,7 +516,7 @@ TEST(PasswordFormFillDataTest, TestAffiliationMatch) {
TEST(PasswordFormFillDataTest, RendererIDs) {
// Create the current form on the page.
PasswordForm form_on_page;
- form_on_page.origin = GURL("https://foo.com/");
+ form_on_page.url = GURL("https://foo.com/");
form_on_page.action = GURL("https://foo.com/login");
form_on_page.username_element = ASCIIToUTF16("username");
form_on_page.password_element = ASCIIToUTF16("password");
@@ -561,7 +553,7 @@ TEST(PasswordFormFillDataTest, RendererIDs) {
TEST(PasswordFormFillDataTest, NoPasswordElement) {
// Create the current form on the page.
PasswordForm form_on_page;
- form_on_page.origin = GURL("https://foo.com/");
+ form_on_page.url = GURL("https://foo.com/");
form_on_page.has_renderer_ids = true;
form_on_page.username_element_renderer_id = FieldRendererId(123);
// Set no password element.
diff --git a/chromium/components/password_manager/core/browser/password_form_manager.cc b/chromium/components/password_manager/core/browser/password_form_manager.cc
index a60398c9070..05fba4ff31f 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager.cc
@@ -27,6 +27,7 @@
#include "components/password_manager/core/browser/password_generation_manager.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_manager_util.h"
#include "components/password_manager/core/browser/possible_username_data.h"
#include "components/password_manager/core/browser/statistics_table.h"
@@ -34,8 +35,10 @@
#include "components/signin/public/identity_manager/identity_manager.h"
#include "google_apis/gaia/core_account_id.h"
+using autofill::FieldRendererId;
using autofill::FormData;
using autofill::FormFieldData;
+using autofill::FormRendererId;
using autofill::FormSignature;
using autofill::FormStructure;
using autofill::GaiaIdHash;
@@ -188,13 +191,7 @@ bool PasswordFormManager::DoesManageAccordingToRendererId(
const PasswordManagerDriver* driver) const {
if (driver != driver_.get())
return false;
-#if defined(OS_IOS)
- NOTREACHED();
- // On iOS form name is used as the form identifier.
- return false;
-#else
return observed_form_.unique_renderer_id == form_renderer_id;
-#endif
}
bool PasswordFormManager::IsEqualToSubmittedForm(
@@ -229,8 +226,8 @@ bool PasswordFormManager::IsEqualToSubmittedForm(
return false;
}
-const GURL& PasswordFormManager::GetOrigin() const {
- return observed_not_web_form_digest_ ? observed_not_web_form_digest_->origin
+const GURL& PasswordFormManager::GetURL() const {
+ return observed_not_web_form_digest_ ? observed_not_web_form_digest_->url
: observed_form_.url;
}
@@ -271,18 +268,21 @@ bool PasswordFormManager::IsBlacklisted() const {
return form_fetcher_->IsBlacklisted() || newly_blacklisted_;
}
+bool PasswordFormManager::WasUnblacklisted() const {
+ return was_unblacklisted_while_on_page_;
+}
+
bool PasswordFormManager::IsMovableToAccountStore() const {
+ DCHECK(
+ client_->GetPasswordFeatureManager()->ShouldShowAccountStorageBubbleUi())
+ << "Ensure that the client supports moving passwords for this user!";
signin::IdentityManager* identity_manager = client_->GetIdentityManager();
- if (!identity_manager)
- return false;
+ DCHECK(identity_manager);
const std::string gaia_id =
identity_manager
->GetPrimaryAccountInfo(signin::ConsentLevel::kNotRequired)
.gaia;
- // If there is no signed in user, we cannot move the credentials to the
- // account store.
- if (gaia_id.empty())
- return false;
+ DCHECK(!gaia_id.empty()) << "Cannot move without signed in user";
const base::string16& username = GetPendingCredentials().username_value;
const base::string16& password = GetPendingCredentials().password_value;
@@ -418,18 +418,18 @@ void PasswordFormManager::PermanentlyBlacklist() {
PasswordStore::FormDigest PasswordFormManager::ConstructObservedFormDigest() {
std::string signon_realm;
- GURL origin;
+ GURL url;
if (observed_not_web_form_digest_) {
- origin = observed_not_web_form_digest_->origin;
+ url = observed_not_web_form_digest_->url;
// GetSignonRealm is not suitable for http auth credentials.
signon_realm = IsHttpAuth()
? observed_not_web_form_digest_->signon_realm
- : GetSignonRealm(observed_not_web_form_digest_->origin);
+ : GetSignonRealm(observed_not_web_form_digest_->url);
} else {
- origin = observed_form_.url;
+ url = observed_form_.url;
signon_realm = GetSignonRealm(observed_form_.url);
}
- return PasswordStore::FormDigest(GetScheme(), signon_realm, origin);
+ return PasswordStore::FormDigest(GetScheme(), signon_realm, url);
}
void PasswordFormManager::OnPasswordsRevealed() {
@@ -437,7 +437,10 @@ void PasswordFormManager::OnPasswordsRevealed() {
}
void PasswordFormManager::MoveCredentialsToAccountStore() {
- password_save_manager_->MoveCredentialsToAccountStore();
+ DCHECK(client_->GetPasswordFeatureManager()->IsOptedInForAccountStorage());
+ password_save_manager_->MoveCredentialsToAccountStore(
+ metrics_util::MoveToAccountStoreTrigger::
+ kSuccessfulLoginWithProfileStorePassword);
}
void PasswordFormManager::BlockMovingCredentialsToAccountStore() {
@@ -497,7 +500,7 @@ void PasswordFormManager::SetGenerationPopupWasShown(
}
void PasswordFormManager::SetGenerationElement(
- const base::string16& generation_element) {
+ FieldRendererId generation_element) {
votes_uploader_.set_generation_element(generation_element);
}
@@ -523,22 +526,22 @@ void PasswordFormManager::PresaveGeneratedPassword(
PasswordManagerDriver* driver,
const FormData& form,
const base::string16& generated_password,
- const base::string16& generation_element) {
+ FieldRendererId generation_element) {
observed_form_ = form;
PresaveGeneratedPasswordInternal(form, generated_password);
votes_uploader_.set_generation_element(generation_element);
}
bool PasswordFormManager::UpdateStateOnUserInput(
- const base::string16& form_identifier,
- const base::string16& field_identifier,
+ FormRendererId form_id,
+ FieldRendererId field_id,
const base::string16& field_value) {
- if (observed_form_.name != form_identifier)
+ if (observed_form_.unique_renderer_id != form_id)
return false;
bool form_data_changed = false;
for (FormFieldData& field : observed_form_.fields) {
- if (field.unique_id == field_identifier) {
+ if (field.unique_renderer_id == field_id) {
field.value = field_value;
form_data_changed = true;
break;
@@ -550,7 +553,7 @@ bool PasswordFormManager::UpdateStateOnUserInput(
base::string16 generated_password =
password_save_manager_->GetGeneratedPassword();
- if (votes_uploader_.get_generation_element() == field_identifier) {
+ if (votes_uploader_.get_generation_element() == field_id) {
generated_password = field_value;
form_data_changed = true;
}
@@ -596,8 +599,8 @@ std::unique_ptr<PasswordFormManager> PasswordFormManager::Clone() {
result->parser_.set_predictions(*parser_.predictions());
if (parsed_submitted_form_) {
- result->parsed_submitted_form_.reset(
- new PasswordForm(*parsed_submitted_form_));
+ result->parsed_submitted_form_ =
+ std::make_unique<PasswordForm>(*parsed_submitted_form_);
}
result->is_submitted_ = is_submitted_;
result->password_save_manager_->Init(result->client_, result->form_fetcher_,
@@ -637,7 +640,7 @@ void PasswordFormManager::OnFetchCompleted() {
return;
}
- client_->UpdateCredentialCache(observed_form_.url.GetOrigin(),
+ client_->UpdateCredentialCache(url::Origin::Create(observed_form_.url),
form_fetcher_->GetBestMatches(),
form_fetcher_->IsBlacklisted());
@@ -723,7 +726,7 @@ bool PasswordFormManager::ProvisionallySaveHttpAuthForm(
PasswordStore::FormDigest(submitted_form)))
return false;
- parsed_submitted_form_.reset(new PasswordForm(submitted_form));
+ parsed_submitted_form_ = std::make_unique<PasswordForm>(submitted_form);
is_submitted_ = true;
CreatePendingCredentials();
return true;
@@ -788,7 +791,6 @@ void PasswordFormManager::Fill() {
driver_->FormEligibleForGenerationFound(
{/*form_renderer_id*/ observed_password_form->form_data
.unique_renderer_id,
- /*new_password_element*/ observed_password_form->new_password_element,
/*new_password_element_renderer_id*/
observed_password_form->new_password_element_renderer_id,
/*confirmation_password_element_renderer_id*/
@@ -845,14 +847,18 @@ void PasswordFormManager::OnGeneratedPasswordAccepted(
ParseFormAndMakeLogging(form_data, FormDataParser::Mode::kSaving);
if (!parsed_form) {
// Create a password form with a minimum data.
- parsed_form.reset(new PasswordForm);
- parsed_form->origin = form_data.url;
+ parsed_form = std::make_unique<PasswordForm>();
+ parsed_form->url = form_data.url;
parsed_form->signon_realm = GetSignonRealm(form_data.url);
}
parsed_form->password_value = password;
password_save_manager_->GeneratedPasswordAccepted(*parsed_form, driver_);
}
+void PasswordFormManager::MarkWasUnblacklisted() {
+ was_unblacklisted_while_on_page_ = true;
+}
+
PasswordFormManager::PasswordFormManager(
PasswordManagerClient* client,
FormFetcher* form_fetcher,
@@ -874,7 +880,8 @@ PasswordFormManager::PasswordFormManager(
votes_uploader_(client, false /* is_possible_change_password_form */) {
if (!metrics_recorder_) {
metrics_recorder_ = base::MakeRefCounted<PasswordFormMetricsRecorder>(
- client_->IsMainFrameSecure(), client_->GetUkmSourceId());
+ client_->IsCommittedMainFrameSecure(), client_->GetUkmSourceId(),
+ client_->GetPrefs());
}
password_save_manager_->Init(client_, form_fetcher_, metrics_recorder_,
&votes_uploader_);
@@ -936,8 +943,8 @@ void PasswordFormManager::PresaveGeneratedPasswordInternal(
if (!parsed_form) {
// Create a password form with a minimum data.
- parsed_form.reset(new PasswordForm());
- parsed_form->origin = form.url;
+ parsed_form = std::make_unique<PasswordForm>();
+ parsed_form->url = form.url;
parsed_form->signon_realm = GetSignonRealm(form.url);
}
// Set |password_value| to the generated password in order to ensure that
diff --git a/chromium/components/password_manager/core/browser/password_form_manager.h b/chromium/components/password_manager/core/browser/password_form_manager.h
index f045bafce00..74888661cca 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.h
+++ b/chromium/components/password_manager/core/browser/password_form_manager.h
@@ -134,8 +134,11 @@ class PasswordFormManager : public PasswordFormManagerForUI,
autofill::FieldRendererId generation_element_id,
const base::string16& password);
+ // Sets |was_unblacklisted_while_on_page| to true.
+ void MarkWasUnblacklisted();
+
// PasswordFormManagerForUI:
- const GURL& GetOrigin() const override;
+ const GURL& GetURL() const override;
const std::vector<const autofill::PasswordForm*>& GetBestMatches()
const override;
std::vector<const autofill::PasswordForm*> GetFederatedMatches()
@@ -147,6 +150,7 @@ class PasswordFormManager : public PasswordFormManagerForUI,
base::span<const CompromisedCredentials> GetCompromisedCredentials()
const override;
bool IsBlacklisted() const override;
+ bool WasUnblacklisted() const override;
bool IsMovableToAccountStore() const override;
void Save() override;
@@ -170,7 +174,7 @@ class PasswordFormManager : public PasswordFormManagerForUI,
void PasswordNoLongerGenerated();
bool HasGeneratedPassword() const;
void SetGenerationPopupWasShown(bool is_manual_generation);
- void SetGenerationElement(const base::string16& generation_element);
+ void SetGenerationElement(autofill::FieldRendererId generation_element);
bool IsPossibleChangePasswordFormWithoutUsername() const;
bool IsPasswordUpdate() const;
base::WeakPtr<PasswordManagerDriver> GetDriver() const;
@@ -186,14 +190,14 @@ class PasswordFormManager : public PasswordFormManagerForUI,
void PresaveGeneratedPassword(PasswordManagerDriver* driver,
const autofill::FormData& form,
const base::string16& generated_password,
- const base::string16& generation_element);
+ autofill::FieldRendererId generation_element);
// Return false and do nothing if |form_identifier| does not correspond to
// |observed_form_|. Otherwise set a value of the field with
// |field_identifier| of |observed_form_| to |field_value|. In case if there
// is a presaved credential this function updates the presaved credential.
- bool UpdateStateOnUserInput(const base::string16& form_identifier,
- const base::string16& field_identifier,
+ bool UpdateStateOnUserInput(autofill::FormRendererId form_id,
+ autofill::FieldRendererId field_id,
const base::string16& field_value);
void SetDriver(const base::WeakPtr<PasswordManagerDriver>& driver);
@@ -313,6 +317,11 @@ class PasswordFormManager : public PasswordFormManagerForUI,
// this boolean to false again.
bool newly_blacklisted_ = false;
+ // Set to true when the user unblacklists the origin while on the page.
+ // This is used to decide when to record
+ // |PasswordManager.ResultOfSavingAfterUnblacklisting|.
+ bool was_unblacklisted_while_on_page_ = false;
+
// Takes care of recording metrics and events for |*this|.
scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder_;
diff --git a/chromium/components/password_manager/core/browser/password_form_manager_for_ui.h b/chromium/components/password_manager/core/browser/password_form_manager_for_ui.h
index d75801ab615..e070e3ee520 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager_for_ui.h
+++ b/chromium/components/password_manager/core/browser/password_form_manager_for_ui.h
@@ -28,8 +28,8 @@ class PasswordFormManagerForUI {
public:
virtual ~PasswordFormManagerForUI() = default;
- // Returns origin of the initially observed form.
- virtual const GURL& GetOrigin() const = 0;
+ // Returns URL of the initially observed form.
+ virtual const GURL& GetURL() const = 0;
// Returns the best saved matches for the observed form.
virtual const std::vector<const autofill::PasswordForm*>& GetBestMatches()
@@ -63,6 +63,9 @@ class PasswordFormManagerForUI {
// Determines if the user opted to 'never remember' passwords for this form.
virtual bool IsBlacklisted() const = 0;
+ // Checks if the user unblacklisted the origin of the form for saving.
+ virtual bool WasUnblacklisted() const = 0;
+
// Determines whether the submitted credentials returned by
// GetPendingCredentials() can be moved to the signed in account store.
// Returns true if the submitted credentials are stored in the profile store
diff --git a/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
index 40e181ca6ef..09874961a3a 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -4,6 +4,8 @@
#include "components/password_manager/core/browser/password_form_manager.h"
+#include <memory>
+
#include <string>
#include <type_traits>
#include <utility>
@@ -29,6 +31,7 @@
#include "components/password_manager/core/browser/field_info_manager.h"
#include "components/password_manager/core/browser/multi_store_password_save_manager.h"
#include "components/password_manager/core/browser/password_form_manager_for_ui.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_manager_util.h"
#include "components/password_manager/core/browser/password_save_manager_impl.h"
#include "components/password_manager/core/browser/password_store.h"
@@ -38,6 +41,11 @@
#include "components/password_manager/core/browser/stub_password_manager_driver.h"
#include "components/password_manager/core/browser/vote_uploads_test_matchers.h"
#include "components/password_manager/core/common/password_manager_features.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_registry.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/testing_pref_service.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "components/ukm/test_ukm_recorder.h"
@@ -46,6 +54,7 @@
using autofill::AutofillUploadContents;
using autofill::FieldPropertiesFlags;
+using autofill::FieldRendererId;
using autofill::FormData;
using autofill::FormFieldData;
using autofill::FormRendererId;
@@ -102,10 +111,6 @@ MATCHER_P(FormDataEqualTo, form_data, "") {
class MockPasswordManagerDriver : public StubPasswordManagerDriver {
public:
- MockPasswordManagerDriver() {}
-
- ~MockPasswordManagerDriver() override {}
-
MOCK_METHOD1(FillPasswordForm, void(const PasswordFormFillData&));
MOCK_METHOD1(AllowPasswordGenerationForForm, void(const PasswordForm&));
MOCK_METHOD1(FormEligibleForGenerationFound,
@@ -129,7 +134,7 @@ class MockAutofillDownloadManager : public autofill::AutofillDownloadManager {
class StubObserver : public AutofillDownloadManager::Observer {
void OnLoadedServerPredictions(
std::string response,
- const std::vector<std::string>& form_signatures) override {}
+ const autofill::FormAndFieldSignatures& form_signatures) override {}
};
StubObserver fake_observer;
@@ -138,30 +143,27 @@ class MockAutofillDownloadManager : public autofill::AutofillDownloadManager {
class MockPasswordManagerClient : public StubPasswordManagerClient {
public:
- MockPasswordManagerClient() = default;
- ~MockPasswordManagerClient() override = default;
-
- MOCK_CONST_METHOD0(IsIncognito, bool());
-
- MOCK_METHOD0(GetAutofillDownloadManager,
- autofill::AutofillDownloadManager*());
-
- MOCK_METHOD0(UpdateFormManagers, void());
-
- MOCK_METHOD2(AutofillHttpAuth,
- void(const PasswordForm&, const PasswordFormManagerForUI*));
-
- MOCK_CONST_METHOD0(IsMainFrameSecure, bool());
-
- MOCK_CONST_METHOD0(GetFieldInfoManager, FieldInfoManager*());
-
- MOCK_METHOD0(GetIdentityManager, signin::IdentityManager*());
+ MOCK_METHOD(bool, IsIncognito, (), (const, override));
+ MOCK_METHOD(autofill::AutofillDownloadManager*,
+ GetAutofillDownloadManager,
+ (),
+ (override));
+ MOCK_METHOD(void, UpdateFormManagers, (), (override));
+ MOCK_METHOD(void,
+ AutofillHttpAuth,
+ (const PasswordForm&, const PasswordFormManagerForUI*),
+ (override));
+ MOCK_METHOD(SyncState, GetPasswordSyncState, (), (const, override));
+ MOCK_METHOD(bool, IsCommittedMainFrameSecure, (), (const, override));
+ MOCK_METHOD(FieldInfoManager*, GetFieldInfoManager, (), (const, override));
+ MOCK_METHOD(signin::IdentityManager*, GetIdentityManager, (), (override));
+ MOCK_METHOD(PrefService*, GetPrefs, (), (const, override));
};
void CheckPendingCredentials(const PasswordForm& expected,
const PasswordForm& actual) {
EXPECT_EQ(expected.signon_realm, actual.signon_realm);
- EXPECT_EQ(expected.origin, actual.origin);
+ EXPECT_EQ(expected.url, actual.url);
EXPECT_EQ(expected.action, actual.action);
EXPECT_EQ(expected.username_value, actual.username_value);
EXPECT_EQ(expected.password_value, actual.password_value);
@@ -290,6 +292,11 @@ class PasswordFormManagerTest : public testing::Test,
public testing::WithParamInterface<bool> {
public:
PasswordFormManagerTest() {
+ pref_service_.registry()->RegisterTimePref(
+ prefs::kProfileStoreDateLastUsedForFilling, base::Time());
+ pref_service_.registry()->RegisterTimePref(
+ prefs::kAccountStoreDateLastUsedForFilling, base::Time());
+
form_manager_->set_wait_for_server_predictions_for_filling(true);
GURL origin = GURL("https://accounts.google.com/a/ServiceLoginAuth");
@@ -360,7 +367,7 @@ class PasswordFormManagerTest : public testing::Test,
submitted_non_password_form_.fields[kUsernameFieldIndex].value =
ASCIIToUTF16("user1");
- saved_match_.origin = origin;
+ saved_match_.url = origin;
saved_match_.action = action;
saved_match_.signon_realm = "https://accounts.google.com/";
saved_match_.username_value = ASCIIToUTF16("test@gmail.com");
@@ -372,7 +379,7 @@ class PasswordFormManagerTest : public testing::Test,
saved_match_.in_store = PasswordForm::Store::kProfileStore;
psl_saved_match_ = saved_match_;
- psl_saved_match_.origin = psl_origin;
+ psl_saved_match_.url = psl_origin;
psl_saved_match_.action = psl_action;
psl_saved_match_.signon_realm = "https://myaccounts.google.com/";
psl_saved_match_.is_public_suffix_match = true;
@@ -393,14 +400,18 @@ class PasswordFormManagerTest : public testing::Test,
EXPECT_CALL(client_, GetAutofillDownloadManager())
.WillRepeatedly(Return(&mock_autofill_download_manager_));
- ON_CALL(client_, IsMainFrameSecure()).WillByDefault(Return(true));
+ ON_CALL(client_, GetPrefs()).WillByDefault(Return(&pref_service_));
+ ON_CALL(client_, IsCommittedMainFrameSecure()).WillByDefault(Return(true));
+ ON_CALL(*client_.GetPasswordFeatureManager(),
+ ShouldShowAccountStorageBubbleUi)
+ .WillByDefault(Return(true));
ON_CALL(mock_autofill_download_manager_,
StartUploadRequest(_, _, _, _, _, _))
.WillByDefault(Return(true));
ON_CALL(*client_.GetPasswordFeatureManager(), GetDefaultPasswordStore)
.WillByDefault(Return(PasswordForm::Store::kProfileStore));
- fetcher_.reset(new FakeFormFetcher());
+ fetcher_ = std::make_unique<FakeFormFetcher>();
fetcher_->Fetch();
}
@@ -420,6 +431,7 @@ class PasswordFormManagerTest : public testing::Test,
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
signin::IdentityTestEnvironment identity_test_env_;
+ TestingPrefServiceSimple pref_service_;
MockPasswordManagerClient client_;
MockPasswordManagerDriver driver_;
@@ -440,9 +452,9 @@ class PasswordFormManagerTest : public testing::Test,
: std::make_unique<PasswordSaveManagerImpl>(
std::make_unique<NiceMock<MockFormSaver>>());
- form_manager_.reset(new PasswordFormManager(
+ form_manager_ = std::make_unique<PasswordFormManager>(
&client_, driver_.AsWeakPtr(), observed_form, fetcher_.get(),
- std::move(password_save_manager), nullptr));
+ std::move(password_save_manager), nullptr);
}
// Creates PasswordFormManager and sets it to |form_manager_| for
@@ -459,9 +471,9 @@ class PasswordFormManagerTest : public testing::Test,
std::make_unique<NiceMock<MockFormSaver>>());
fetcher_->set_scheme(
PasswordStore::FormDigest(base_auth_observed_form).scheme);
- form_manager_.reset(new PasswordFormManager(
+ form_manager_ = std::make_unique<PasswordFormManager>(
&client_, PasswordStore::FormDigest(base_auth_observed_form),
- fetcher_.get(), std::move(password_save_manager)));
+ fetcher_.get(), std::move(password_save_manager));
}
void SetNonFederatedAndNotifyFetchCompleted(
@@ -492,7 +504,7 @@ TEST_P(PasswordFormManagerTest, DoesManageNoFormTag) {
FormData another_form = observed_form_;
// Simulate that new input was added by JavaScript.
- another_form.fields.push_back(FormFieldData());
+ another_form.fields.emplace_back();
EXPECT_TRUE(form_manager_->DoesManage(another_form, &driver_));
// Forms on other drivers are not considered managed.
EXPECT_FALSE(form_manager_->DoesManage(another_form, nullptr));
@@ -508,7 +520,7 @@ TEST_P(PasswordFormManagerTest, Autofill) {
task_environment_.FastForwardUntilNoTasksRemain();
- EXPECT_EQ(observed_form_.url, fill_data.origin);
+ EXPECT_EQ(observed_form_.url, fill_data.url);
EXPECT_FALSE(fill_data.wait_for_username);
EXPECT_EQ(observed_form_.fields[1].name, fill_data.username_field.name);
EXPECT_EQ(saved_match_.username_value, fill_data.username_field.value);
@@ -559,7 +571,6 @@ TEST_P(PasswordFormManagerTest, AutofillSignUpForm) {
#if defined(OS_IOS)
EXPECT_EQ(observed_form_.unique_renderer_id,
generation_data.form_renderer_id);
- EXPECT_EQ(ASCIIToUTF16("password"), generation_data.new_password_element);
#else
EXPECT_EQ(observed_form_.fields.back().unique_renderer_id,
generation_data.new_password_renderer_id);
@@ -594,7 +605,6 @@ TEST_P(PasswordFormManagerTest, GenerationOnNewAndConfirmPasswordFields) {
#if defined(OS_IOS)
EXPECT_EQ(observed_form_.unique_renderer_id,
generation_data.form_renderer_id);
- EXPECT_EQ(ASCIIToUTF16("password"), generation_data.new_password_element);
#else
EXPECT_EQ(new_password_render_id, generation_data.new_password_renderer_id);
EXPECT_EQ(confirm_password_render_id,
@@ -611,7 +621,7 @@ TEST_P(PasswordFormManagerTest, AutofillWithBlacklistedMatch) {
task_environment_.FastForwardUntilNoTasksRemain();
- EXPECT_EQ(observed_form_.url, fill_data.origin);
+ EXPECT_EQ(observed_form_.url, fill_data.url);
EXPECT_EQ(saved_match_.username_value, fill_data.username_field.value);
EXPECT_EQ(saved_match_.password_value, fill_data.password_field.value);
}
@@ -770,7 +780,7 @@ TEST_P(PasswordFormManagerTest, CreatePendingCredentialsAlreadySaved) {
TEST_P(PasswordFormManagerTest, CreatePendingCredentialsPSLMatchSaved) {
PasswordForm expected = saved_match_;
- saved_match_.origin = GURL("https://m.accounts.google.com/auth");
+ saved_match_.url = GURL("https://m.accounts.google.com/auth");
saved_match_.signon_realm = "https://m.accounts.google.com/";
saved_match_.is_public_suffix_match = true;
@@ -925,7 +935,7 @@ TEST_P(PasswordFormManagerTest, SaveNewCredentials) {
form_manager_->Save();
std::string expected_signon_realm = submitted_form.url.GetOrigin().spec();
- EXPECT_EQ(submitted_form.url, saved_form.origin);
+ EXPECT_EQ(submitted_form.url, saved_form.url);
EXPECT_EQ(expected_signon_realm, saved_form.signon_realm);
EXPECT_EQ(new_username, saved_form.username_value);
EXPECT_EQ(new_password, saved_form.password_value);
@@ -972,7 +982,7 @@ TEST_P(PasswordFormManagerTest, SavePSLToAlreadySaved) {
form_manager_->Save();
- EXPECT_EQ(submitted_form.url, saved_form.origin);
+ EXPECT_EQ(submitted_form.url, saved_form.url);
EXPECT_EQ(GetSignonRealm(submitted_form.url), saved_form.signon_realm);
EXPECT_EQ(saved_form.username_value, psl_saved_match_.username_value);
EXPECT_EQ(saved_form.password_value, psl_saved_match_.password_value);
@@ -1829,7 +1839,7 @@ TEST_P(PasswordFormManagerTest, GenerationUploadOnNoInteraction) {
fetcher_->NotifyFetchCompleted();
if (generation_popup_shown) {
- form_manager_->SetGenerationElement(ASCIIToUTF16("password"));
+ form_manager_->SetGenerationElement(FieldRendererId(3));
form_manager_->SetGenerationPopupWasShown(false /*is_manual_generation*/);
}
EXPECT_TRUE(
@@ -1852,7 +1862,7 @@ TEST_P(PasswordFormManagerTest, GenerationUploadOnNeverClicked) {
fetcher_->NotifyFetchCompleted();
if (generation_popup_shown) {
- form_manager_->SetGenerationElement(ASCIIToUTF16("password"));
+ form_manager_->SetGenerationElement(FieldRendererId(3));
form_manager_->SetGenerationPopupWasShown(false /*is_manual_generation*/);
}
EXPECT_TRUE(
@@ -1999,7 +2009,7 @@ TEST_P(PasswordFormManagerTest, iOSPresavedGeneratedPassword) {
const base::string16 generated_password = ASCIIToUTF16("gen_pw");
// Use different |unique_id| and |name| to test that |unique_id| is taken.
password_field.unique_id = password_field.name + ASCIIToUTF16("1");
- const base::string16 generation_element = password_field.unique_id;
+ FieldRendererId generation_element = password_field.unique_renderer_id;
PasswordForm saved_form;
EXPECT_CALL(form_saver, Save(_, IsEmpty(), base::string16()))
@@ -2015,7 +2025,7 @@ TEST_P(PasswordFormManagerTest, iOSPresavedGeneratedPassword) {
EXPECT_CALL(form_saver, UpdateReplace(_, _, base::string16(), _))
.WillOnce(SaveArg<0>(&saved_form));
- form_manager_->UpdateStateOnUserInput(form_to_presave.name,
+ form_manager_->UpdateStateOnUserInput(form_to_presave.unique_renderer_id,
generation_element, changed_password);
EXPECT_EQ(username_field.value, saved_form.username_value);
EXPECT_EQ(changed_password, saved_form.password_value);
@@ -2025,15 +2035,15 @@ TEST_P(PasswordFormManagerTest, iOSUpdateStateWithoutPresaving) {
fetcher_->NotifyFetchCompleted();
MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
- const base::string16 password_field =
- observed_form_.fields[kPasswordFieldIndex].unique_id;
+ FieldRendererId password_field =
+ observed_form_.fields[kPasswordFieldIndex].unique_renderer_id;
const base::string16 new_field_value = ASCIIToUTF16("some_password");
// Check that nothing is saved on changing password, in case when there was no
// pre-saving.
EXPECT_CALL(form_saver, Save(_, _, _)).Times(0);
EXPECT_TRUE(form_manager_->UpdateStateOnUserInput(
- observed_form_.name, password_field, new_field_value));
+ observed_form_.unique_renderer_id, password_field, new_field_value));
EXPECT_EQ(new_field_value,
form_manager_->observed_form().fields[kPasswordFieldIndex].value);
@@ -2257,7 +2267,7 @@ TEST_P(PasswordFormManagerTest, ProvisinallySavedOnSingleUsernameForm) {
&driver_, nullptr));
}
-TEST_P(PasswordFormManagerTest, NotMovableToAccountStore) {
+TEST_P(PasswordFormManagerTest, NotMovableToAccountStoreWhenBlocked) {
const std::string kEmail = "email@gmail.com";
const std::string kGaiaId = signin::GetTestGaiaIdForEmail(kEmail);
@@ -2277,12 +2287,9 @@ TEST_P(PasswordFormManagerTest, NotMovableToAccountStore) {
EXPECT_TRUE(
form_manager_->ProvisionallySave(submitted_form_, &driver_, nullptr));
+ // Even with |kEmail| is signed in, credentials should NOT be movable.
ON_CALL(client_, GetIdentityManager())
.WillByDefault(Return(identity_test_env_.identity_manager()));
- // If not user is signed in, the credentials should NOT be movable.
- EXPECT_FALSE(form_manager_->IsMovableToAccountStore());
-
- // When |kEmail| is signed in, credentials should NOT be movable.
identity_test_env_.SetPrimaryAccount(kEmail);
EXPECT_FALSE(form_manager_->IsMovableToAccountStore());
}
@@ -2356,7 +2363,8 @@ class MockPasswordSaveManager : public PasswordSaveManager {
std::unique_ptr<PasswordSaveManager> Clone() override {
return std::make_unique<MockPasswordSaveManager>();
}
- MOCK_METHOD0(MoveCredentialsToAccountStore, void());
+ MOCK_METHOD1(MoveCredentialsToAccountStore,
+ void(metrics_util::MoveToAccountStoreTrigger));
MOCK_METHOD1(BlockMovingToAccountStoreFor, void(const autofill::GaiaIdHash&));
private:
@@ -2378,9 +2386,9 @@ class PasswordFormManagerTestWithMockedSaver : public PasswordFormManagerTest {
std::make_unique<NiceMock<MockPasswordSaveManager>>();
mock_password_save_manager_ = mock_password_save_manager.get();
EXPECT_CALL(*mock_password_save_manager_, Init(_, _, _, _));
- form_manager_.reset(new PasswordFormManager(
+ form_manager_ = std::make_unique<PasswordFormManager>(
&client_, driver_.AsWeakPtr(), observed_form, fetcher_.get(),
- std::move(mock_password_save_manager), nullptr));
+ std::move(mock_password_save_manager), nullptr);
}
// Creates PasswordFormManager and sets it to |form_manager_| for
@@ -2393,9 +2401,9 @@ class PasswordFormManagerTestWithMockedSaver : public PasswordFormManagerTest {
std::make_unique<NiceMock<MockPasswordSaveManager>>();
mock_password_save_manager_ = mock_password_save_manager.get();
EXPECT_CALL(*mock_password_save_manager_, Init(_, _, _, _));
- form_manager_.reset(new PasswordFormManager(
+ form_manager_ = std::make_unique<PasswordFormManager>(
&client_, PasswordStore::FormDigest(base_auth_observed_form),
- fetcher_.get(), std::move(mock_password_save_manager)));
+ fetcher_.get(), std::move(mock_password_save_manager));
}
private:
@@ -2431,7 +2439,7 @@ TEST_F(PasswordFormManagerTestWithMockedSaver, SaveCredentials) {
EXPECT_CALL(client_, UpdateFormManagers());
form_manager_->Save();
std::string expected_signon_realm = submitted_form.url.GetOrigin().spec();
- EXPECT_EQ(submitted_form.url, updated_form.origin);
+ EXPECT_EQ(submitted_form.url, updated_form.url);
EXPECT_EQ(expected_signon_realm, updated_form.signon_realm);
EXPECT_EQ(new_username, updated_form.username_value);
EXPECT_EQ(new_password, updated_form.password_value);
@@ -2543,7 +2551,12 @@ TEST_F(PasswordFormManagerTestWithMockedSaver, PermanentlyBlacklist) {
}
TEST_F(PasswordFormManagerTestWithMockedSaver, MoveCredentialsToAccountStore) {
- EXPECT_CALL(*mock_password_save_manager(), MoveCredentialsToAccountStore());
+ ON_CALL(*client_.GetPasswordFeatureManager(), IsOptedInForAccountStorage)
+ .WillByDefault(Return(true));
+ EXPECT_CALL(*mock_password_save_manager(),
+ MoveCredentialsToAccountStore(
+ metrics_util::MoveToAccountStoreTrigger::
+ kSuccessfulLoginWithProfileStorePassword));
form_manager_->MoveCredentialsToAccountStore();
}
diff --git a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc
index dfd469f5dbf..0bea0c0a8a4 100644
--- a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc
+++ b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc
@@ -4,6 +4,8 @@
#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
+#include <stdint.h>
+
#include <algorithm>
#include "base/check_op.h"
@@ -13,12 +15,15 @@
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/stl_util.h"
+#include "base/time/default_clock.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/password_generation_util.h"
#include "components/password_manager/core/browser/form_fetcher.h"
#include "components/password_manager/core/browser/password_bubble_experiment.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/statistics_table.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_service.h"
using autofill::FieldPropertiesFlags;
using autofill::FormData;
@@ -183,17 +188,34 @@ bool BlacklistedBySmartBubble(
return false;
}
+PasswordFormMetricsRecorder::FillingSource ComputeFillingSource(
+ bool filled_from_profile_store,
+ bool filled_from_account_store) {
+ using FillingSource = PasswordFormMetricsRecorder::FillingSource;
+ if (filled_from_profile_store) {
+ if (filled_from_account_store)
+ return FillingSource::kFilledFromBothStores;
+ return FillingSource::kFilledFromProfileStore;
+ }
+ if (filled_from_account_store)
+ return FillingSource::kFilledFromAccountStore;
+ return FillingSource::kNotFilled;
+}
+
} // namespace
PasswordFormMetricsRecorder::PasswordFormMetricsRecorder(
bool is_main_frame_secure,
- ukm::SourceId source_id)
- : is_main_frame_secure_(is_main_frame_secure),
+ ukm::SourceId source_id,
+ PrefService* pref_service)
+ : clock_(base::DefaultClock::GetInstance()),
+ is_main_frame_secure_(is_main_frame_secure),
source_id_(source_id),
- ukm_entry_builder_(source_id) {}
+ ukm_entry_builder_(source_id),
+ pref_service_(pref_service) {}
PasswordFormMetricsRecorder::~PasswordFormMetricsRecorder() {
- if (submit_result_ == kSubmitResultNotSubmitted) {
+ if (submit_result_ == SubmitResult::kNotSubmitted) {
if (HasGeneratedPassword(generated_password_status_)) {
metrics_util::LogPasswordGenerationSubmissionEvent(
metrics_util::PASSWORD_NOT_SUBMITTED);
@@ -204,15 +226,17 @@ PasswordFormMetricsRecorder::~PasswordFormMetricsRecorder() {
ukm_entry_builder_.SetSubmission_Observed(0 /*false*/);
}
- if (submitted_form_type_ != kSubmittedFormTypeUnspecified) {
+ if (submitted_form_type_ != SubmittedFormType::kUnspecified) {
UMA_HISTOGRAM_ENUMERATION("PasswordManager.SubmittedFormType",
- submitted_form_type_, kSubmittedFormTypeMax);
+ submitted_form_type_, SubmittedFormType::kCount);
if (!is_main_frame_secure_) {
UMA_HISTOGRAM_ENUMERATION("PasswordManager.SubmittedNonSecureFormType",
- submitted_form_type_, kSubmittedFormTypeMax);
+ submitted_form_type_,
+ SubmittedFormType::kCount);
}
- ukm_entry_builder_.SetSubmission_SubmittedFormType(submitted_form_type_);
+ ukm_entry_builder_.SetSubmission_SubmittedFormType(
+ static_cast<int64_t>(submitted_form_type_));
}
ukm_entry_builder_.SetUpdating_Prompt_Shown(update_prompt_shown_);
@@ -273,7 +297,7 @@ PasswordFormMetricsRecorder::~PasswordFormMetricsRecorder() {
ukm_entry_builder_.SetDynamicFormChanges(*form_changes_bitmask_);
}
- if (submit_result_ == kSubmitResultPassed && filling_assistance_) {
+ if (submit_result_ == SubmitResult::kPassed && filling_assistance_) {
FillingAssistance filling_assistance = *filling_assistance_;
UMA_HISTOGRAM_ENUMERATION("PasswordManager.FillingAssistance",
filling_assistance);
@@ -304,10 +328,45 @@ PasswordFormMetricsRecorder::~PasswordFormMetricsRecorder() {
if (filling_source_) {
base::UmaHistogramEnumeration("PasswordManager.FillingSource",
*filling_source_);
+
+ // Update the "last used for filling" timestamp for the affected store(s).
+ base::Time now = clock_->Now();
+ if (*filling_source_ == FillingSource::kFilledFromProfileStore ||
+ *filling_source_ == FillingSource::kFilledFromBothStores) {
+ pref_service_->SetTime(prefs::kProfileStoreDateLastUsedForFilling, now);
+ }
+ if (*filling_source_ == FillingSource::kFilledFromAccountStore ||
+ *filling_source_ == FillingSource::kFilledFromBothStores) {
+ pref_service_->SetTime(prefs::kAccountStoreDateLastUsedForFilling, now);
+ }
+
+ // Determine which of the store(s) were used in the last 7/28 days.
+ base::Time profile_store_last_use =
+ pref_service_->GetTime(prefs::kProfileStoreDateLastUsedForFilling);
+ base::Time account_store_last_use =
+ pref_service_->GetTime(prefs::kAccountStoreDateLastUsedForFilling);
+
+ bool was_profile_store_used_in_last_7_days =
+ (now - profile_store_last_use) < base::TimeDelta::FromDays(7);
+ bool was_account_store_used_in_last_7_days =
+ (now - account_store_last_use) < base::TimeDelta::FromDays(7);
+ base::UmaHistogramEnumeration(
+ "PasswordManager.StoresUsedForFillingInLast7Days",
+ ComputeFillingSource(was_profile_store_used_in_last_7_days,
+ was_account_store_used_in_last_7_days));
+
+ bool was_profile_store_used_in_last_28_days =
+ (now - profile_store_last_use) < base::TimeDelta::FromDays(28);
+ bool was_account_store_used_in_last_28_days =
+ (now - account_store_last_use) < base::TimeDelta::FromDays(28);
+ base::UmaHistogramEnumeration(
+ "PasswordManager.StoresUsedForFillingInLast28Days",
+ ComputeFillingSource(was_profile_store_used_in_last_28_days,
+ was_account_store_used_in_last_28_days));
}
}
- if (submit_result_ == kSubmitResultPassed && js_only_input_) {
+ if (submit_result_ == SubmitResult::kPassed && js_only_input_) {
UMA_HISTOGRAM_ENUMERATION(
"PasswordManager.JavaScriptOnlyValueInSubmittedForm", *js_only_input_);
}
@@ -339,7 +398,7 @@ void PasswordFormMetricsRecorder::SetManagerAction(
}
void PasswordFormMetricsRecorder::LogSubmitPassed() {
- if (submit_result_ != kSubmitResultFailed) {
+ if (submit_result_ != SubmitResult::kFailed) {
if (HasGeneratedPassword(generated_password_status_)) {
metrics_util::LogPasswordGenerationSubmissionEvent(
metrics_util::PASSWORD_SUBMITTED);
@@ -350,8 +409,9 @@ void PasswordFormMetricsRecorder::LogSubmitPassed() {
}
base::RecordAction(base::UserMetricsAction("PasswordManager_LoginPassed"));
ukm_entry_builder_.SetSubmission_Observed(1 /*true*/);
- ukm_entry_builder_.SetSubmission_SubmissionResult(kSubmitResultPassed);
- submit_result_ = kSubmitResultPassed;
+ ukm_entry_builder_.SetSubmission_SubmissionResult(
+ static_cast<int64_t>(SubmitResult::kPassed));
+ submit_result_ = SubmitResult::kPassed;
}
void PasswordFormMetricsRecorder::LogSubmitFailed() {
@@ -364,8 +424,9 @@ void PasswordFormMetricsRecorder::LogSubmitFailed() {
}
base::RecordAction(base::UserMetricsAction("PasswordManager_LoginFailed"));
ukm_entry_builder_.SetSubmission_Observed(1 /*true*/);
- ukm_entry_builder_.SetSubmission_SubmissionResult(kSubmitResultFailed);
- submit_result_ = kSubmitResultFailed;
+ ukm_entry_builder_.SetSubmission_SubmissionResult(
+ static_cast<int64_t>(SubmitResult::kFailed));
+ submit_result_ = SubmitResult::kFailed;
}
void PasswordFormMetricsRecorder::SetPasswordGenerationPopupShown(
@@ -503,15 +564,10 @@ void PasswordFormMetricsRecorder::CalculateFillingAssistanceMetric(
// At this point, the password was filled from at least one of the two stores,
// so compute the filling source now.
- if (username_password_state.password_exists_in_profile_store &&
- username_password_state.password_exists_in_account_store) {
- filling_source_ = FillingSource::kFilledFromBothStores;
- } else if (username_password_state.password_exists_in_profile_store) {
- filling_source_ = FillingSource::kFilledFromProfileStore;
- } else {
- DCHECK(username_password_state.password_exists_in_account_store);
- filling_source_ = FillingSource::kFilledFromAccountStore;
- }
+ filling_source_ = ComputeFillingSource(
+ username_password_state.password_exists_in_profile_store,
+ username_password_state.password_exists_in_account_store);
+ DCHECK_NE(*filling_source_, FillingSource::kNotFilled);
if (username_password_state.saved_username_typed) {
filling_assistance_ = FillingAssistance::kUsernameTypedPasswordFilled;
diff --git a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.h b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.h
index 4431fd903d8..5c9e96c2e25 100644
--- a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.h
+++ b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.h
@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
+#include "base/time/clock.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/signatures.h"
@@ -23,6 +24,8 @@
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "url/gurl.h"
+class PrefService;
+
namespace autofill {
struct FormData;
}
@@ -50,7 +53,8 @@ class PasswordFormMetricsRecorder
// Records UKM metrics and reports them on destruction. The |source_id| is
// the ID of the WebContents document that the forms belong to.
PasswordFormMetricsRecorder(bool is_main_frame_secure,
- ukm::SourceId source_id);
+ ukm::SourceId source_id,
+ PrefService* pref_service);
// ManagerAction - What does the PasswordFormManager do with this form? Either
// it fills it, or it doesn't. If it doesn't fill it, that's either
@@ -65,11 +69,15 @@ class PasswordFormMetricsRecorder
};
// Result - What happens to the form?
- enum SubmitResult {
- kSubmitResultNotSubmitted = 0,
- kSubmitResultFailed,
- kSubmitResultPassed,
- kSubmitResultMax
+ //
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ //
+ // Needs to stay in sync with PasswordFormSubmissionResult in enums.xml.
+ enum class SubmitResult {
+ kNotSubmitted = 0,
+ kFailed = 1,
+ kPassed = 2,
};
// Whether the password manager filled a credential on a form.
@@ -85,37 +93,51 @@ class PasswordFormMetricsRecorder
kManagerFillEventAutofilled
};
- // What the form is used for. kSubmittedFormTypeUnspecified is only set before
- // the SetSubmittedFormType() is called, and should never be actually
+ // What the form is used for. SubmittedFormType::kUnspecified is only set
+ // before the SetSubmittedFormType() is called, and should never be actually
// uploaded.
- enum SubmittedFormType {
- kSubmittedFormTypeLogin,
- kSubmittedFormTypeLoginNoUsername,
- kSubmittedFormTypeChangePasswordEnabled,
- kSubmittedFormTypeChangePasswordDisabled,
- kSubmittedFormTypeChangePasswordNoUsername,
- kSubmittedFormTypeSignup,
- kSubmittedFormTypeSignupNoUsername,
- kSubmittedFormTypeLoginAndSignup,
- kSubmittedFormTypeUnspecified,
- kSubmittedFormTypeMax
+ //
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ //
+ // Needs to stay in sync with PasswordFormType in enums.xml.
+ enum class SubmittedFormType {
+ kLogin = 0,
+ kLoginNoUsername = 1,
+ kChangePasswordEnabled = 2,
+ kChangePasswordDisabled = 3,
+ kChangePasswordNoUsername = 4,
+ kSignup = 5,
+ kSignupNoUsername = 6,
+ kLoginAndSignup = 7,
+ kUnspecified = 8,
+ kCount = 9,
};
// The reason why a password bubble was shown on the screen.
+ //
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ //
+ // Needs to stay in sync with PasswordBubbleTrigger in enums.xml.
enum class BubbleTrigger {
kUnknown = 0,
// The password manager suggests the user to save a password and asks for
// confirmation.
- kPasswordManagerSuggestionAutomatic,
- kPasswordManagerSuggestionManual,
+ kPasswordManagerSuggestionAutomatic = 1,
+ kPasswordManagerSuggestionManual = 2,
// The site asked the user to save a password via the credential management
// API.
- kCredentialManagementAPIAutomatic,
- kCredentialManagementAPIManual,
- kMax,
+ kCredentialManagementAPIAutomatic = 3,
+ kCredentialManagementAPIManual = 4,
};
// The reason why a password bubble was dismissed.
+ //
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ //
+ // Needs to stay in sync with PasswordBubbleDismissalReason in enums.xml.
enum class BubbleDismissalReason {
kUnknown = 0,
kAccepted = 1,
@@ -138,32 +160,12 @@ class PasswordFormMetricsRecorder
kCorrectedUsernameInForm = 200,
};
- // Result of comparing of the old and new form parsing for filling.
- enum class ParsingComparisonResult {
- kSame,
- kDifferent,
- // Old and new parsers use different identification mechanism for unnamed
- // fields, so the difference in parsing of anonymous fields is expected.
- kAnonymousFields,
- kMax
- };
-
- // Result of comparing of the old and new form parsing for saving. Multiple
- // values are meant to be combined and reported in a single number as a
- // bitmask.
- enum class ParsingOnSavingDifference {
- // Different fields were identified for username or password.
- kFields = 1 << 0,
- // Signon_realms are different.
- kSignonRealm = 1 << 1,
- // One password form manager wants to update, the other to save as new.
- kNewLoginStatus = 1 << 2,
- // One password form manager thinks the password is generated, the other
- // does not.
- kGenerated = 1 << 3,
- };
-
// Indicator whether the user has seen a password generation popup and why.
+ //
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ //
+ // Needs to stay in sync with PasswordGenerationPopupShown in enums.xml.
enum class PasswordGenerationPopupShown {
kNotShown = 0,
kShownAutomatically = 1,
@@ -394,6 +396,8 @@ class PasswordFormMetricsRecorder
username_updated_in_bubble_ = value;
}
+ void set_clock_for_testing(base::Clock* clock) { clock_ = clock; }
+
private:
friend class base::RefCounted<PasswordFormMetricsRecorder>;
@@ -412,7 +416,11 @@ class PasswordFormMetricsRecorder
// RecordUkmMetric.
~PasswordFormMetricsRecorder();
- // True if the main frame's visible URL, at the time this PasswordFormManager
+ // Not owned. Points to base::DefaultClock::GetInstance() by default, but can
+ // be overridden for testing.
+ base::Clock* clock_;
+
+ // True if the main frame's committed URL, at the time PasswordFormManager
// was created, is secure.
const bool is_main_frame_secure_;
@@ -441,12 +449,12 @@ class PasswordFormMetricsRecorder
// the user with this form, and the result. They are combined and
// recorded in UMA when the PasswordFormMetricsRecorder is destroyed.
ManagerAction manager_action_ = kManagerActionNone;
- SubmitResult submit_result_ = kSubmitResultNotSubmitted;
+ SubmitResult submit_result_ = SubmitResult::kNotSubmitted;
// Form type of the form that the PasswordFormManager is managing. Set after
// submission as the classification of the form can change depending on what
// data the user has entered.
- SubmittedFormType submitted_form_type_ = kSubmittedFormTypeUnspecified;
+ SubmittedFormType submitted_form_type_ = SubmittedFormType::kUnspecified;
// The UKM SourceId of the document the form belongs to.
ukm::SourceId source_id_;
@@ -454,6 +462,8 @@ class PasswordFormMetricsRecorder
// Holds URL keyed metrics (UKMs) to be recorded on destruction.
ukm::builders::PasswordForm ukm_entry_builder_;
+ PrefService* const pref_service_;
+
// Counter for DetailedUserActions observed during the lifetime of a
// PasswordFormManager. Reported upon destruction.
std::map<DetailedUserAction, int64_t> detailed_user_actions_counts_;
diff --git a/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc b/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc
index d2eeb171933..c2b9d3e771f 100644
--- a/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc
@@ -4,17 +4,22 @@
#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
+#include <stdint.h>
+
#include "base/metrics/metrics_hashes.h"
#include "base/notreached.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
+#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
+#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/statistics_table.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/ukm/test_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
@@ -40,9 +45,9 @@ using UkmEntry = ukm::builders::PasswordForm;
// Create a UkmEntryBuilder with kTestSourceId.
scoped_refptr<PasswordFormMetricsRecorder> CreatePasswordFormMetricsRecorder(
bool is_main_frame_secure,
- ukm::TestUkmRecorder* test_ukm_recorder) {
- return base::MakeRefCounted<PasswordFormMetricsRecorder>(is_main_frame_secure,
- kTestSourceId);
+ PrefService* pref_service) {
+ return base::MakeRefCounted<PasswordFormMetricsRecorder>(
+ is_main_frame_secure, kTestSourceId, pref_service);
}
// TODO(crbug.com/738921) Replace this with generalized infrastructure.
@@ -71,28 +76,31 @@ void ExpectUkmValueCount(ukm::TestUkmRecorder* test_ukm_recorder,
// Test the metrics recorded around password generation and the user's
// interaction with the offer to generate passwords.
TEST(PasswordFormMetricsRecorder, Generation) {
- base::test::TaskEnvironment task_environment_;
+ base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
+
static constexpr struct {
bool generation_available;
bool has_generated_password;
PasswordFormMetricsRecorder::SubmitResult submission;
} kTests[] = {
- {false, false, PasswordFormMetricsRecorder::kSubmitResultNotSubmitted},
- {true, false, PasswordFormMetricsRecorder::kSubmitResultNotSubmitted},
- {true, true, PasswordFormMetricsRecorder::kSubmitResultNotSubmitted},
- {false, false, PasswordFormMetricsRecorder::kSubmitResultFailed},
- {true, false, PasswordFormMetricsRecorder::kSubmitResultFailed},
- {true, true, PasswordFormMetricsRecorder::kSubmitResultFailed},
- {false, false, PasswordFormMetricsRecorder::kSubmitResultPassed},
- {true, false, PasswordFormMetricsRecorder::kSubmitResultPassed},
- {true, true, PasswordFormMetricsRecorder::kSubmitResultPassed},
+ {false, false, PasswordFormMetricsRecorder::SubmitResult::kNotSubmitted},
+ {true, false, PasswordFormMetricsRecorder::SubmitResult::kNotSubmitted},
+ {true, true, PasswordFormMetricsRecorder::SubmitResult::kNotSubmitted},
+ {false, false, PasswordFormMetricsRecorder::SubmitResult::kFailed},
+ {true, false, PasswordFormMetricsRecorder::SubmitResult::kFailed},
+ {true, true, PasswordFormMetricsRecorder::SubmitResult::kFailed},
+ {false, false, PasswordFormMetricsRecorder::SubmitResult::kPassed},
+ {true, false, PasswordFormMetricsRecorder::SubmitResult::kPassed},
+ {true, true, PasswordFormMetricsRecorder::SubmitResult::kPassed},
};
for (const auto& test : kTests) {
SCOPED_TRACE(testing::Message()
<< "generation_available=" << test.generation_available
<< ", has_generated_password=" << test.has_generated_password
- << ", submission=" << test.submission);
+ << ", submission=" << static_cast<int64_t>(test.submission));
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
base::HistogramTester histogram_tester;
@@ -102,7 +110,7 @@ TEST(PasswordFormMetricsRecorder, Generation) {
// on destruction.
{
auto recorder = CreatePasswordFormMetricsRecorder(
- /*is_main_frame_secure*/ true, &test_ukm_recorder);
+ /*is_main_frame_secure*/ true, &pref_service);
if (test.generation_available)
recorder->MarkGenerationAvailable();
if (test.has_generated_password) {
@@ -111,96 +119,97 @@ TEST(PasswordFormMetricsRecorder, Generation) {
kPasswordAccepted);
}
switch (test.submission) {
- case PasswordFormMetricsRecorder::kSubmitResultNotSubmitted:
+ case PasswordFormMetricsRecorder::SubmitResult::kNotSubmitted:
// Do nothing.
break;
- case PasswordFormMetricsRecorder::kSubmitResultFailed:
+ case PasswordFormMetricsRecorder::SubmitResult::kFailed:
recorder->LogSubmitFailed();
break;
- case PasswordFormMetricsRecorder::kSubmitResultPassed:
+ case PasswordFormMetricsRecorder::SubmitResult::kPassed:
recorder->LogSubmitPassed();
break;
- case PasswordFormMetricsRecorder::kSubmitResultMax:
- NOTREACHED();
}
}
ExpectUkmValueCount(
&test_ukm_recorder, UkmEntry::kSubmission_ObservedName,
test.submission !=
- PasswordFormMetricsRecorder::kSubmitResultNotSubmitted
+ PasswordFormMetricsRecorder::SubmitResult::kNotSubmitted
? 1
: 0,
1);
int expected_login_failed =
- test.submission == PasswordFormMetricsRecorder::kSubmitResultFailed ? 1
- : 0;
+ test.submission == PasswordFormMetricsRecorder::SubmitResult::kFailed
+ ? 1
+ : 0;
EXPECT_EQ(expected_login_failed,
user_action_tester.GetActionCount("PasswordManager_LoginFailed"));
ExpectUkmValueCount(&test_ukm_recorder,
UkmEntry::kSubmission_SubmissionResultName,
- PasswordFormMetricsRecorder::kSubmitResultFailed,
+ static_cast<int64_t>(
+ PasswordFormMetricsRecorder::SubmitResult::kFailed),
expected_login_failed);
int expected_login_passed =
- test.submission == PasswordFormMetricsRecorder::kSubmitResultPassed ? 1
- : 0;
+ test.submission == PasswordFormMetricsRecorder::SubmitResult::kPassed
+ ? 1
+ : 0;
EXPECT_EQ(expected_login_passed,
user_action_tester.GetActionCount("PasswordManager_LoginPassed"));
ExpectUkmValueCount(&test_ukm_recorder,
UkmEntry::kSubmission_SubmissionResultName,
- PasswordFormMetricsRecorder::kSubmitResultPassed,
+ static_cast<int64_t>(
+ PasswordFormMetricsRecorder::SubmitResult::kPassed),
expected_login_passed);
if (test.has_generated_password) {
switch (test.submission) {
- case PasswordFormMetricsRecorder::kSubmitResultNotSubmitted:
+ case PasswordFormMetricsRecorder::SubmitResult::kNotSubmitted:
histogram_tester.ExpectBucketCount(
"PasswordGeneration.SubmissionEvent",
metrics_util::PASSWORD_NOT_SUBMITTED, 1);
break;
- case PasswordFormMetricsRecorder::kSubmitResultFailed:
+ case PasswordFormMetricsRecorder::SubmitResult::kFailed:
histogram_tester.ExpectBucketCount(
"PasswordGeneration.SubmissionEvent",
metrics_util::GENERATED_PASSWORD_FORCE_SAVED, 1);
break;
- case PasswordFormMetricsRecorder::kSubmitResultPassed:
+ case PasswordFormMetricsRecorder::SubmitResult::kPassed:
histogram_tester.ExpectBucketCount(
"PasswordGeneration.SubmissionEvent",
metrics_util::PASSWORD_SUBMITTED, 1);
break;
- case PasswordFormMetricsRecorder::kSubmitResultMax:
- NOTREACHED();
}
}
if (!test.has_generated_password && test.generation_available) {
switch (test.submission) {
- case PasswordFormMetricsRecorder::kSubmitResultNotSubmitted:
+ case PasswordFormMetricsRecorder::SubmitResult::kNotSubmitted:
histogram_tester.ExpectBucketCount(
"PasswordGeneration.SubmissionAvailableEvent",
metrics_util::PASSWORD_NOT_SUBMITTED, 1);
break;
- case PasswordFormMetricsRecorder::kSubmitResultFailed:
+ case PasswordFormMetricsRecorder::SubmitResult::kFailed:
histogram_tester.ExpectBucketCount(
"PasswordGeneration.SubmissionAvailableEvent",
metrics_util::PASSWORD_SUBMISSION_FAILED, 1);
break;
- case PasswordFormMetricsRecorder::kSubmitResultPassed:
+ case PasswordFormMetricsRecorder::SubmitResult::kPassed:
histogram_tester.ExpectBucketCount(
"PasswordGeneration.SubmissionAvailableEvent",
metrics_util::PASSWORD_SUBMITTED, 1);
break;
- case PasswordFormMetricsRecorder::kSubmitResultMax:
- NOTREACHED();
}
}
}
}
TEST(PasswordFormMetricsRecorder, SubmittedFormType) {
- base::test::TaskEnvironment task_environment_;
+ base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
+
static constexpr struct {
// Stimuli:
bool is_main_frame_secure;
@@ -211,15 +220,17 @@ TEST(PasswordFormMetricsRecorder, SubmittedFormType) {
// Expectation for PasswordManager.SubmittedNonSecureFormType:
int expected_submitted_non_secure_form_type;
} kTests[] = {
- {false, PasswordFormMetricsRecorder::kSubmittedFormTypeUnspecified, 0, 0},
- {true, PasswordFormMetricsRecorder::kSubmittedFormTypeUnspecified, 0, 0},
- {false, PasswordFormMetricsRecorder::kSubmittedFormTypeLogin, 1, 1},
- {true, PasswordFormMetricsRecorder::kSubmittedFormTypeLogin, 1, 0},
+ {false, PasswordFormMetricsRecorder::SubmittedFormType::kUnspecified, 0,
+ 0},
+ {true, PasswordFormMetricsRecorder::SubmittedFormType::kUnspecified, 0,
+ 0},
+ {false, PasswordFormMetricsRecorder::SubmittedFormType::kLogin, 1, 1},
+ {true, PasswordFormMetricsRecorder::SubmittedFormType::kLogin, 1, 0},
};
for (const auto& test : kTests) {
SCOPED_TRACE(testing::Message()
<< "is_main_frame_secure=" << test.is_main_frame_secure
- << ", form_type=" << test.form_type);
+ << ", form_type=" << static_cast<int64_t>(test.form_type));
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
base::HistogramTester histogram_tester;
@@ -228,15 +239,15 @@ TEST(PasswordFormMetricsRecorder, SubmittedFormType) {
// on destruction.
{
auto recorder = CreatePasswordFormMetricsRecorder(
- test.is_main_frame_secure, &test_ukm_recorder);
+ test.is_main_frame_secure, &pref_service);
recorder->SetSubmittedFormType(test.form_type);
}
if (test.form_type !=
- PasswordFormMetricsRecorder::kSubmittedFormTypeUnspecified) {
+ PasswordFormMetricsRecorder::SubmittedFormType::kUnspecified) {
ExpectUkmValueCount(&test_ukm_recorder,
UkmEntry::kSubmission_SubmittedFormTypeName,
- test.form_type, 1);
+ static_cast<int64_t>(test.form_type), 1);
}
if (test.expected_submitted_form_type) {
@@ -259,7 +270,10 @@ TEST(PasswordFormMetricsRecorder, SubmittedFormType) {
}
TEST(PasswordFormMetricsRecorder, RecordPasswordBubbleShown) {
- base::test::TaskEnvironment task_environment_;
+ base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
+
using Trigger = PasswordFormMetricsRecorder::BubbleTrigger;
static constexpr struct {
// Stimuli:
@@ -322,7 +336,7 @@ TEST(PasswordFormMetricsRecorder, RecordPasswordBubbleShown) {
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
{
auto recorder = CreatePasswordFormMetricsRecorder(
- true /*is_main_frame_secure*/, &test_ukm_recorder);
+ true /*is_main_frame_secure*/, &pref_service);
recorder->RecordPasswordBubbleShown(test.credential_source_type,
test.display_disposition);
}
@@ -354,7 +368,10 @@ TEST(PasswordFormMetricsRecorder, RecordPasswordBubbleShown) {
}
TEST(PasswordFormMetricsRecorder, RecordUIDismissalReason) {
- base::test::TaskEnvironment task_environment_;
+ base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
+
static constexpr struct {
// Stimuli:
metrics_util::UIDisplayDisposition display_disposition;
@@ -385,7 +402,7 @@ TEST(PasswordFormMetricsRecorder, RecordUIDismissalReason) {
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
{
auto recorder = CreatePasswordFormMetricsRecorder(
- true /*is_main_frame_secure*/, &test_ukm_recorder);
+ true /*is_main_frame_secure*/, &pref_service);
recorder->RecordPasswordBubbleShown(
metrics_util::CredentialSourceType::kPasswordManager,
test.display_disposition);
@@ -406,14 +423,17 @@ TEST(PasswordFormMetricsRecorder, RecordUIDismissalReason) {
// Verify that it is ok to open and close the password bubble more than once
// and still get accurate metrics.
TEST(PasswordFormMetricsRecorder, SequencesOfBubbles) {
- base::test::TaskEnvironment task_environment_;
+ base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
+
using BubbleDismissalReason =
PasswordFormMetricsRecorder::BubbleDismissalReason;
using BubbleTrigger = PasswordFormMetricsRecorder::BubbleTrigger;
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
{
auto recorder = CreatePasswordFormMetricsRecorder(
- true /*is_main_frame_secure*/, &test_ukm_recorder);
+ true /*is_main_frame_secure*/, &pref_service);
// Open and confirm an automatically triggered saving prompt.
recorder->RecordPasswordBubbleShown(
metrics_util::CredentialSourceType::kPasswordManager,
@@ -453,12 +473,15 @@ TEST(PasswordFormMetricsRecorder, SequencesOfBubbles) {
// Verify that one-time actions are only recorded once per life-cycle of a
// PasswordFormMetricsRecorder.
TEST(PasswordFormMetricsRecorder, RecordDetailedUserAction) {
- base::test::TaskEnvironment task_environment_;
+ base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
+
using Action = PasswordFormMetricsRecorder::DetailedUserAction;
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
{
auto recorder = CreatePasswordFormMetricsRecorder(
- true /*is_main_frame_secure*/, &test_ukm_recorder);
+ true /*is_main_frame_secure*/, &pref_service);
recorder->RecordDetailedUserAction(Action::kCorrectedUsernameInForm);
recorder->RecordDetailedUserAction(Action::kCorrectedUsernameInForm);
recorder->RecordDetailedUserAction(Action::kEditedUsernameInBubble);
@@ -479,7 +502,9 @@ TEST(PasswordFormMetricsRecorder, RecordDetailedUserAction) {
// Verify that the the mapping is correct and that metrics are actually
// recorded.
TEST(PasswordFormMetricsRecorder, RecordShowManualFallbackForSaving) {
- base::test::TaskEnvironment task_environment_;
+ base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
struct {
bool has_generated_password;
bool is_update;
@@ -494,7 +519,7 @@ TEST(PasswordFormMetricsRecorder, RecordShowManualFallbackForSaving) {
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
{
auto recorder = CreatePasswordFormMetricsRecorder(
- true /*is_main_frame_secure*/, &test_ukm_recorder);
+ true /*is_main_frame_secure*/, &pref_service);
recorder->RecordShowManualFallbackForSaving(test.has_generated_password,
test.is_update);
}
@@ -509,11 +534,13 @@ TEST(PasswordFormMetricsRecorder, RecordShowManualFallbackForSaving) {
// Verify that no 0 is recorded if now fallback icon is shown.
TEST(PasswordFormMetricsRecorder, NoRecordShowManualFallbackForSaving) {
- base::test::TaskEnvironment task_environment_;
+ base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
{
auto recorder = CreatePasswordFormMetricsRecorder(
- true /*is_main_frame_secure*/, &test_ukm_recorder);
+ true /*is_main_frame_secure*/, &pref_service);
}
auto entries = test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
ASSERT_EQ(1u, entries.size());
@@ -524,11 +551,13 @@ TEST(PasswordFormMetricsRecorder, NoRecordShowManualFallbackForSaving) {
// Verify that only the latest value is recorded
TEST(PasswordFormMetricsRecorder, RecordShowManualFallbackForSavingLatestOnly) {
- base::test::TaskEnvironment task_environment_;
+ base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
{
auto recorder = CreatePasswordFormMetricsRecorder(
- true /*is_main_frame_secure*/, &test_ukm_recorder);
+ true /*is_main_frame_secure*/, &pref_service);
recorder->RecordShowManualFallbackForSaving(true, false);
recorder->RecordShowManualFallbackForSaving(true, true);
}
@@ -541,17 +570,21 @@ TEST(PasswordFormMetricsRecorder, RecordShowManualFallbackForSavingLatestOnly) {
}
TEST(PasswordFormMetricsRecorder, FormChangeBitmapNoMetricRecorded) {
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
base::HistogramTester histogram_tester;
- auto recorder =
- CreatePasswordFormMetricsRecorder(true /*is_main_frame_secure*/, nullptr);
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ true /*is_main_frame_secure*/, &pref_service);
recorder.reset();
histogram_tester.ExpectTotalCount("PasswordManager.DynamicFormChanges", 0);
}
TEST(PasswordFormMetricsRecorder, FormChangeBitmapRecordedOnce) {
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
base::HistogramTester histogram_tester;
- auto recorder =
- CreatePasswordFormMetricsRecorder(true /*is_main_frame_secure*/, nullptr);
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ true /*is_main_frame_secure*/, &pref_service);
recorder->RecordFormChangeBitmask(PasswordFormMetricsRecorder::kFieldsNumber);
recorder.reset();
histogram_tester.ExpectUniqueSample("PasswordManager.DynamicFormChanges",
@@ -559,9 +592,11 @@ TEST(PasswordFormMetricsRecorder, FormChangeBitmapRecordedOnce) {
}
TEST(PasswordFormMetricsRecorder, FormChangeBitmapRecordedMultipleTimes) {
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
base::HistogramTester histogram_tester;
- auto recorder =
- CreatePasswordFormMetricsRecorder(true /*is_main_frame_secure*/, nullptr);
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ true /*is_main_frame_secure*/, &pref_service);
recorder->RecordFormChangeBitmask(PasswordFormMetricsRecorder::kFieldsNumber);
recorder->RecordFormChangeBitmask(
PasswordFormMetricsRecorder::kFormControlTypes);
@@ -685,6 +720,8 @@ void CheckFillingAssistanceTestCase(
<< ", is_mixed_form: " << std::boolalpha << sub_case.is_mixed_form);
base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
base::HistogramTester histogram_tester;
FormData form_data = ConvertToFormData(test_case.fields);
@@ -706,7 +743,7 @@ void CheckFillingAssistanceTestCase(
/*account_store_values=*/{});
auto recorder = CreatePasswordFormMetricsRecorder(
- sub_case.is_main_frame_secure, nullptr);
+ sub_case.is_main_frame_secure, &pref_service);
if (test_case.submission_detected) {
recorder->CalculateFillingAssistanceMetric(
form_data, saved_usernames, saved_passwords, test_case.is_blacklisted,
@@ -1091,6 +1128,8 @@ struct FillingSourceTestCase {
void CheckFillingSourceTestCase(const FillingSourceTestCase& test_case) {
base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
base::HistogramTester histogram_tester;
FormData form_data = ConvertToFormData(test_case.fields);
@@ -1104,7 +1143,7 @@ void CheckFillingSourceTestCase(const FillingSourceTestCase& test_case) {
{
auto recorder = CreatePasswordFormMetricsRecorder(
- /*is_main_frame_secure=*/true, nullptr);
+ /*is_main_frame_secure=*/true, &pref_service);
recorder->CalculateFillingAssistanceMetric(
form_data, saved_usernames, saved_passwords, /*is_blacklisted=*/false,
/*interactions_stats=*/{},
@@ -1201,4 +1240,315 @@ TEST(PasswordFormMetricsRecorder, FillingSourceBothDifferent) {
});
}
+TEST(PasswordFormMetricsRecorder, StoresUsedForFillingInLast7And28Days) {
+ base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
+
+ std::set<std::pair<base::string16, PasswordForm::Store>> saved_usernames =
+ ConvertToString16AndStoreSet({"profileuser"}, {"accountuser"});
+ std::set<std::pair<base::string16, PasswordForm::Store>> saved_passwords =
+ ConvertToString16AndStoreSet({"profilepass"}, {"accountpass"});
+
+ // Phase 1: The user manually enters a credential that's not stored.
+ {
+ base::HistogramTester histogram_tester;
+
+ FormData form_data = ConvertToFormData(
+ {{.value = "user", .manually_filled = true},
+ {.value = "pass", .manually_filled = true, .is_password = true}});
+ {
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ /*is_main_frame_secure=*/true, &pref_service);
+ recorder->CalculateFillingAssistanceMetric(
+ form_data, saved_usernames, saved_passwords, /*is_blacklisted=*/false,
+ /*interactions_stats=*/{},
+ PasswordAccountStorageUsageLevel::kUsingAccountStorage);
+ recorder->LogSubmitPassed();
+ }
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.FillingSource",
+ PasswordFormMetricsRecorder::FillingSource::kNotFilled, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast7Days",
+ PasswordFormMetricsRecorder::FillingSource::kNotFilled, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast28Days",
+ PasswordFormMetricsRecorder::FillingSource::kNotFilled, 1);
+ }
+
+ // Phase 2: A credential from the account store is filled.
+ {
+ base::HistogramTester histogram_tester;
+
+ FormData form_data = ConvertToFormData(
+ {{.value = "accountuser", .automatically_filled = true},
+ {.value = "accountpass",
+ .automatically_filled = true,
+ .is_password = true}});
+ {
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ /*is_main_frame_secure=*/true, &pref_service);
+ recorder->CalculateFillingAssistanceMetric(
+ form_data, saved_usernames, saved_passwords, /*is_blacklisted=*/false,
+ /*interactions_stats=*/{},
+ PasswordAccountStorageUsageLevel::kUsingAccountStorage);
+ recorder->LogSubmitPassed();
+ }
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.FillingSource",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromAccountStore, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast7Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromAccountStore, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast28Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromAccountStore, 1);
+ }
+
+ // Phase 3: A credential from the profile store is filled.
+ {
+ base::HistogramTester histogram_tester;
+
+ FormData form_data = ConvertToFormData(
+ {{.value = "profileuser", .automatically_filled = true},
+ {.value = "profilepass",
+ .automatically_filled = true,
+ .is_password = true}});
+ {
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ /*is_main_frame_secure=*/true, &pref_service);
+ recorder->CalculateFillingAssistanceMetric(
+ form_data, saved_usernames, saved_passwords, /*is_blacklisted=*/false,
+ /*interactions_stats=*/{},
+ PasswordAccountStorageUsageLevel::kUsingAccountStorage);
+ recorder->LogSubmitPassed();
+ }
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.FillingSource",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromProfileStore, 1);
+ // Even though this credential came from the profile store, a credential
+ // from the account store was also filled recently (in phase 2).
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast7Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromBothStores, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast28Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromBothStores, 1);
+ }
+
+ // Phase 4: The user again manually enters a credential that's not stored.
+ {
+ base::HistogramTester histogram_tester;
+
+ FormData form_data = ConvertToFormData(
+ {{.value = "user", .manually_filled = true},
+ {.value = "pass", .manually_filled = true, .is_password = true}});
+ {
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ /*is_main_frame_secure=*/true, &pref_service);
+ recorder->CalculateFillingAssistanceMetric(
+ form_data, saved_usernames, saved_passwords, /*is_blacklisted=*/false,
+ /*interactions_stats=*/{},
+ PasswordAccountStorageUsageLevel::kUsingAccountStorage);
+ recorder->LogSubmitPassed();
+ }
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.FillingSource",
+ PasswordFormMetricsRecorder::FillingSource::kNotFilled, 1);
+ // Even though this credential did not come from either store, both stores
+ // were used recently (in phases 2 and 3).
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast7Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromBothStores, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast28Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromBothStores, 1);
+ }
+}
+
+TEST(PasswordFormMetricsRecorder, StoresUsedForFillingInLast7And28DaysExpiry) {
+ base::test::TaskEnvironment task_environment;
+ sync_preferences::TestingPrefServiceSyncable pref_service;
+ PasswordManager::RegisterProfilePrefs(pref_service.registry());
+ base::SimpleTestClock clock;
+ clock.SetNow(base::Time::Now());
+
+ std::set<std::pair<base::string16, PasswordForm::Store>> saved_usernames =
+ ConvertToString16AndStoreSet({"profileuser"}, {"accountuser"});
+ std::set<std::pair<base::string16, PasswordForm::Store>> saved_passwords =
+ ConvertToString16AndStoreSet({"profilepass"}, {"accountpass"});
+
+ // Day 0: A credential from the profile store is filled.
+ {
+ base::HistogramTester histogram_tester;
+
+ FormData form_data = ConvertToFormData(
+ {{.value = "profileuser", .automatically_filled = true},
+ {.value = "profilepass",
+ .automatically_filled = true,
+ .is_password = true}});
+ {
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ /*is_main_frame_secure=*/true, &pref_service);
+ recorder->set_clock_for_testing(&clock);
+ recorder->CalculateFillingAssistanceMetric(
+ form_data, saved_usernames, saved_passwords, /*is_blacklisted=*/false,
+ /*interactions_stats=*/{},
+ PasswordAccountStorageUsageLevel::kUsingAccountStorage);
+ recorder->LogSubmitPassed();
+ }
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.FillingSource",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromProfileStore, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast7Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromProfileStore, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast28Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromProfileStore, 1);
+ }
+
+ clock.Advance(base::TimeDelta::FromDays(2));
+
+ // Day 2: A credential from the account store is filled.
+ {
+ base::HistogramTester histogram_tester;
+
+ FormData form_data = ConvertToFormData(
+ {{.value = "accountuser", .automatically_filled = true},
+ {.value = "accountpass",
+ .automatically_filled = true,
+ .is_password = true}});
+ {
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ /*is_main_frame_secure=*/true, &pref_service);
+ recorder->set_clock_for_testing(&clock);
+ recorder->CalculateFillingAssistanceMetric(
+ form_data, saved_usernames, saved_passwords, /*is_blacklisted=*/false,
+ /*interactions_stats=*/{},
+ PasswordAccountStorageUsageLevel::kUsingAccountStorage);
+ recorder->LogSubmitPassed();
+ }
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.FillingSource",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromAccountStore, 1);
+ // Even though this credential came from the account store, a credential
+ // from the profile store was also filled recently.
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast7Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromBothStores, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast28Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromBothStores, 1);
+ }
+
+ clock.Advance(base::TimeDelta::FromDays(6));
+
+ // Day 8: A credential from the account store is filled (again).
+ {
+ base::HistogramTester histogram_tester;
+
+ FormData form_data = ConvertToFormData(
+ {{.value = "accountuser", .automatically_filled = true},
+ {.value = "accountpass",
+ .automatically_filled = true,
+ .is_password = true}});
+ {
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ /*is_main_frame_secure=*/true, &pref_service);
+ recorder->set_clock_for_testing(&clock);
+ recorder->CalculateFillingAssistanceMetric(
+ form_data, saved_usernames, saved_passwords, /*is_blacklisted=*/false,
+ /*interactions_stats=*/{},
+ PasswordAccountStorageUsageLevel::kUsingAccountStorage);
+ recorder->LogSubmitPassed();
+ }
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.FillingSource",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromAccountStore, 1);
+ // A credential from the profile store was last filled 8 days ago, so this
+ // still shows up in the 28-day histogram but not the 7-day one.
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast7Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromAccountStore, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast28Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromBothStores, 1);
+ }
+
+ clock.Advance(base::TimeDelta::FromDays(27));
+
+ // Day 35: The user manually enters a credential that's not stored.
+ {
+ base::HistogramTester histogram_tester;
+
+ FormData form_data = ConvertToFormData(
+ {{.value = "user", .manually_filled = true},
+ {.value = "pass", .manually_filled = true, .is_password = true}});
+ {
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ /*is_main_frame_secure=*/true, &pref_service);
+ recorder->set_clock_for_testing(&clock);
+ recorder->CalculateFillingAssistanceMetric(
+ form_data, saved_usernames, saved_passwords, /*is_blacklisted=*/false,
+ /*interactions_stats=*/{},
+ PasswordAccountStorageUsageLevel::kUsingAccountStorage);
+ recorder->LogSubmitPassed();
+ }
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.FillingSource",
+ PasswordFormMetricsRecorder::FillingSource::kNotFilled, 1);
+ // The account store was used 27 days ago, so is still relevant for the
+ // 28-day histogram. The profile store was last used 35 days ago, so it's
+ // gone now.
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast7Days",
+ PasswordFormMetricsRecorder::FillingSource::kNotFilled, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast28Days",
+ PasswordFormMetricsRecorder::FillingSource::kFilledFromAccountStore, 1);
+ }
+
+ clock.Advance(base::TimeDelta::FromDays(2));
+
+ // Day 37: The user again manually enters a credential that's not stored.
+ {
+ base::HistogramTester histogram_tester;
+
+ FormData form_data = ConvertToFormData(
+ {{.value = "user", .manually_filled = true},
+ {.value = "pass", .manually_filled = true, .is_password = true}});
+ {
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ /*is_main_frame_secure=*/true, &pref_service);
+ recorder->set_clock_for_testing(&clock);
+ recorder->CalculateFillingAssistanceMetric(
+ form_data, saved_usernames, saved_passwords, /*is_blacklisted=*/false,
+ /*interactions_stats=*/{},
+ PasswordAccountStorageUsageLevel::kUsingAccountStorage);
+ recorder->LogSubmitPassed();
+ }
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.FillingSource",
+ PasswordFormMetricsRecorder::FillingSource::kNotFilled, 1);
+ // Now both usages are > 28 days ago.
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast7Days",
+ PasswordFormMetricsRecorder::FillingSource::kNotFilled, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.StoresUsedForFillingInLast28Days",
+ PasswordFormMetricsRecorder::FillingSource::kNotFilled, 1);
+ }
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_generation_frame_helper.cc b/chromium/components/password_manager/core/browser/password_generation_frame_helper.cc
index ae646ee6ff9..057922d8745 100644
--- a/chromium/components/password_manager/core/browser/password_generation_frame_helper.cc
+++ b/chromium/components/password_manager/core/browser/password_generation_frame_helper.cc
@@ -4,6 +4,8 @@
#include "components/password_manager/core/browser/password_generation_frame_helper.h"
+#include <memory>
+
#include "base/optional.h"
#include "base/strings/string_util.h"
#include "components/autofill/core/browser/field_types.h"
@@ -87,8 +89,8 @@ bool PasswordGenerationFrameHelper::IsGenerationEnabled(
bool log_debug_data) const {
std::unique_ptr<Logger> logger;
if (log_debug_data && password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+ logger = std::make_unique<BrowserSavePasswordProgressLogger>(
+ client_->GetLogManager());
}
GURL url = driver_->GetLastCommittedURL();
diff --git a/chromium/components/password_manager/core/browser/password_generation_frame_helper_unittest.cc b/chromium/components/password_manager/core/browser/password_generation_frame_helper_unittest.cc
index 05bdb27afd4..d96a762a26f 100644
--- a/chromium/components/password_manager/core/browser/password_generation_frame_helper_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_generation_frame_helper_unittest.cc
@@ -15,6 +15,7 @@
#include "base/test/task_environment.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/proto/password_requirements.pb.h"
#include "components/autofill/core/common/form_data.h"
@@ -62,7 +63,6 @@ class TestPasswordManagerDriver : public StubPasswordManagerDriver {
ON_CALL(*this, GetLastCommittedURL())
.WillByDefault(testing::ReturnRef(empty_url_));
}
- ~TestPasswordManagerDriver() override {}
// PasswordManagerDriver implementation.
PasswordGenerationFrameHelper* GetPasswordGenerationHelper() override {
@@ -140,9 +140,11 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
PasswordRequirementsService* GetPasswordRequirementsService() override {
return &password_requirements_service_;
}
- void SetLastCommittedEntryUrl(const GURL& url) { last_committed_url_ = url; }
- const GURL& GetLastCommittedEntryURL() const override {
- return last_committed_url_;
+ void SetLastCommittedEntryUrl(const GURL& url) {
+ last_committed_origin_ = url::Origin::Create(url);
+ }
+ url::Origin GetLastCommittedOrigin() const override {
+ return last_committed_origin_;
}
TestPasswordManagerDriver* test_driver() { return &driver_; }
@@ -152,7 +154,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
scoped_refptr<TestPasswordStore> store_;
TestPasswordManagerDriver driver_;
PasswordRequirementsService password_requirements_service_;
- GURL last_committed_url_;
+ url::Origin last_committed_origin_;
};
} // anonymous namespace
@@ -167,7 +169,7 @@ class PasswordGenerationFrameHelperTest : public testing::Test {
new TestingPrefServiceSimple());
prefs->registry()->RegisterBooleanPref(prefs::kCredentialsEnableService,
true);
- client_.reset(new MockPasswordManagerClient(std::move(prefs)));
+ client_ = std::make_unique<MockPasswordManagerClient>(std::move(prefs));
}
void TearDown() override { client_.reset(); }
@@ -305,8 +307,10 @@ TEST_F(PasswordGenerationFrameHelperTest, ProcessPasswordRequirements) {
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
- autofill::FormStructure::ParseQueryResponse(response_string, forms,
- nullptr);
+
+ autofill::FormStructure::ParseQueryResponse(
+ response_string, forms, autofill::test::GetEncodedSignatures(forms),
+ nullptr);
GetGenerationHelper()->PrefetchSpec(origin.GetOrigin());
diff --git a/chromium/components/password_manager/core/browser/password_generation_manager.cc b/chromium/components/password_manager/core/browser/password_generation_manager.cc
index cf50dbacd26..06509e7815f 100644
--- a/chromium/components/password_manager/core/browser/password_generation_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_generation_manager.cc
@@ -43,7 +43,7 @@ class PasswordDataForUI : public PasswordFormManagerForUI {
PasswordDataForUI& operator=(const PasswordDataForUI&) = delete;
// PasswordFormManagerForUI:
- const GURL& GetOrigin() const override;
+ const GURL& GetURL() const override;
const std::vector<const PasswordForm*>& GetBestMatches() const override;
std::vector<const PasswordForm*> GetFederatedMatches() const override;
const PasswordForm& GetPendingCredentials() const override;
@@ -53,6 +53,7 @@ class PasswordDataForUI : public PasswordFormManagerForUI {
base::span<const CompromisedCredentials> GetCompromisedCredentials()
const override;
bool IsBlacklisted() const override;
+ bool WasUnblacklisted() const override;
bool IsMovableToAccountStore() const override;
void Save() override;
void Update(const PasswordForm& credentials_to_update) override;
@@ -92,8 +93,8 @@ PasswordDataForUI::PasswordDataForUI(
matches_.push_back(&form);
}
-const GURL& PasswordDataForUI::GetOrigin() const {
- return pending_form_.origin;
+const GURL& PasswordDataForUI::GetURL() const {
+ return pending_form_.url;
}
const std::vector<const PasswordForm*>& PasswordDataForUI::GetBestMatches()
@@ -138,6 +139,11 @@ bool PasswordDataForUI::IsBlacklisted() const {
return false;
}
+bool PasswordDataForUI::WasUnblacklisted() const {
+ // This information should not be relevant hereconst.
+ return false;
+}
+
bool PasswordDataForUI::IsMovableToAccountStore() const {
// This is irrelevant for the generation conflict resolution bubble.
return false;
diff --git a/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc
index d3713c1584f..99ebefc7b06 100644
--- a/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc
@@ -38,8 +38,8 @@ constexpr time_t kAnotherTime = 987654321;
// Creates a dummy saved credential.
PasswordForm CreateSaved() {
PasswordForm form;
- form.origin = GURL(kURL);
- form.signon_realm = form.origin.spec();
+ form.url = GURL(kURL);
+ form.signon_realm = form.url.spec();
form.action = GURL("https://login.example.org");
form.username_value = ASCIIToUTF16("old_username");
form.password_value = ASCIIToUTF16("12345");
@@ -48,7 +48,7 @@ PasswordForm CreateSaved() {
PasswordForm CreateSavedFederated() {
autofill::PasswordForm federated;
- federated.origin = GURL(kURL);
+ federated.url = GURL(kURL);
federated.signon_realm = "federation://example.in/google.com";
federated.type = autofill::PasswordForm::Type::kApi;
federated.federation_origin =
@@ -60,8 +60,8 @@ PasswordForm CreateSavedFederated() {
// Creates a dummy saved PSL credential.
PasswordForm CreateSavedPSL() {
PasswordForm form;
- form.origin = GURL(kSubdomainURL);
- form.signon_realm = form.origin.spec();
+ form.url = GURL(kSubdomainURL);
+ form.signon_realm = form.url.spec();
form.action = GURL("https://login.example.org");
form.username_value = ASCIIToUTF16("old_username2");
form.password_value = ASCIIToUTF16("passw0rd");
@@ -72,8 +72,8 @@ PasswordForm CreateSavedPSL() {
// Creates a dummy generated password.
PasswordForm CreateGenerated() {
PasswordForm form;
- form.origin = GURL(kURL);
- form.signon_realm = form.origin.spec();
+ form.url = GURL(kURL);
+ form.signon_realm = form.url.spec();
form.action = GURL("https://signup.example.org");
form.username_value = ASCIIToUTF16("MyName");
form.password_value = ASCIIToUTF16("Strong password");
@@ -210,7 +210,7 @@ TEST_F(PasswordGenerationManagerTest, GeneratedPasswordAccepted_UpdateUI) {
std::unique_ptr<PasswordFormManagerForUI> ui_form =
SetUpOverwritingUI(driver.AsWeakPtr());
ASSERT_TRUE(ui_form);
- EXPECT_EQ(GURL(kURL), ui_form->GetOrigin());
+ EXPECT_EQ(GURL(kURL), ui_form->GetURL());
EXPECT_THAT(
ui_form->GetBestMatches(),
ElementsAre(Field(&PasswordForm::username_value, ASCIIToUTF16(""))));
diff --git a/chromium/components/password_manager/core/browser/password_list_sorter.cc b/chromium/components/password_manager/core/browser/password_list_sorter.cc
index a6aeea275ab..9b40dd536eb 100644
--- a/chromium/components/password_manager/core/browser/password_list_sorter.cc
+++ b/chromium/components/password_manager/core/browser/password_list_sorter.cc
@@ -27,7 +27,8 @@ constexpr char kSortKeyNoFederationSymbol = '-';
} // namespace
-std::string CreateSortKey(const autofill::PasswordForm& form) {
+std::string CreateSortKey(const autofill::PasswordForm& form,
+ IgnoreStore ignore_store) {
std::string shown_origin;
GURL link_url;
std::tie(shown_origin, link_url) = GetShownOriginAndLinkUrl(form);
@@ -74,7 +75,8 @@ std::string CreateSortKey(const autofill::PasswordForm& form) {
// To separate HTTP/HTTPS credentials, add the scheme to the key.
key += kSortKeyPartsSeparator + link_url.scheme();
- if (form.in_store == autofill::PasswordForm::Store::kAccountStore) {
+ if (!ignore_store &&
+ form.in_store == autofill::PasswordForm::Store::kAccountStore) {
key += kSortKeyPartsSeparator + std::string("account");
}
diff --git a/chromium/components/password_manager/core/browser/password_list_sorter.h b/chromium/components/password_manager/core/browser/password_list_sorter.h
index 4130d7b02a6..234875ce587 100644
--- a/chromium/components/password_manager/core/browser/password_list_sorter.h
+++ b/chromium/components/password_manager/core/browser/password_list_sorter.h
@@ -10,6 +10,8 @@
#include <string>
#include <vector>
+#include "base/util/type_safety/strong_alias.h"
+
namespace autofill {
struct PasswordForm;
}
@@ -19,6 +21,7 @@ namespace password_manager {
// Multimap from sort key to password forms.
using DuplicatesMap =
std::multimap<std::string, std::unique_ptr<autofill::PasswordForm>>;
+using IgnoreStore = util::StrongAlias<class IgnoreStoreTag, bool>;
// Creates key for sorting password or password exception entries. The key is
// eTLD+1 followed by the reversed list of domains (e.g.
@@ -26,7 +29,10 @@ using DuplicatesMap =
// the scheme. If |form| is not blacklisted, username, password and federation
// are appended to the key. If not, no further information is added. For Android
// credentials the canocial spec is included.
-std::string CreateSortKey(const autofill::PasswordForm& form);
+// If |ignore_store| is true, forms differing only by the originating password
+// store will map to the same key.
+std::string CreateSortKey(const autofill::PasswordForm& form,
+ IgnoreStore ignore_store = IgnoreStore(false));
// Sort entries of |list| based on sort key. The key is the concatenation of
// origin, entry type (non-Android credential, Android w/ affiliated web realm
diff --git a/chromium/components/password_manager/core/browser/password_list_sorter_unittest.cc b/chromium/components/password_manager/core/browser/password_list_sorter_unittest.cc
index 23c28b589cf..79af81964fa 100644
--- a/chromium/components/password_manager/core/browser/password_list_sorter_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_list_sorter_unittest.cc
@@ -31,7 +31,7 @@ void SortAndCheckPositions(const std::vector<SortEntry>& test_entries) {
for (const SortEntry& entry : test_entries) {
auto form = std::make_unique<autofill::PasswordForm>();
form->signon_realm = entry.origin;
- form->origin = GURL(entry.origin);
+ form->url = GURL(entry.origin);
form->blacklisted_by_user = entry.is_blacklisted;
if (!entry.is_blacklisted) {
form->username_value = base::ASCIIToUTF16(entry.username);
@@ -56,7 +56,7 @@ void SortAndCheckPositions(const std::vector<SortEntry>& test_entries) {
if (entry.expected_position >= 0) {
SCOPED_TRACE(testing::Message("position in sorted list: ")
<< entry.expected_position);
- EXPECT_EQ(GURL(entry.origin), list[entry.expected_position]->origin);
+ EXPECT_EQ(GURL(entry.origin), list[entry.expected_position]->url);
if (!entry.is_blacklisted) {
EXPECT_EQ(base::ASCIIToUTF16(entry.username),
list[entry.expected_position]->username_value);
@@ -189,4 +189,18 @@ TEST(PasswordListSorterTest, Sorting_SpecialCharacters) {
SortAndCheckPositions(test_cases);
}
+TEST(PasswordListSorterTest, EntriesDifferingByStoreShouldMapToSameKey) {
+ autofill::PasswordForm account_form;
+ account_form.signon_realm = "https://g.com/";
+ account_form.url = GURL(account_form.signon_realm);
+ account_form.blacklisted_by_user = false;
+ account_form.in_store = autofill::PasswordForm::Store::kAccountStore;
+
+ autofill::PasswordForm profile_form(account_form);
+ profile_form.in_store = autofill::PasswordForm::Store::kProfileStore;
+
+ EXPECT_EQ(CreateSortKey(account_form, IgnoreStore(true)),
+ CreateSortKey(profile_form, IgnoreStore(true)));
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager.cc b/chromium/components/password_manager/core/browser/password_manager.cc
index 4f0463a01a3..176a422e3b2 100644
--- a/chromium/components/password_manager/core/browser/password_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_manager.cc
@@ -26,7 +26,9 @@
#include "components/autofill/core/common/save_password_progress_logger.h"
#include "components/autofill/core/common/signatures.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
+#include "components/password_manager/core/browser/credential_cache.h"
#include "components/password_manager/core/browser/field_info_manager.h"
+#include "components/password_manager/core/browser/origin_credential_store.h"
#include "components/password_manager/core/browser/password_autofill_manager.h"
#include "components/password_manager/core/browser/password_form_manager.h"
#include "components/password_manager/core/browser/password_generation_frame_helper.h"
@@ -48,7 +50,9 @@
#endif
using autofill::ACCOUNT_CREATION_PASSWORD;
+using autofill::FieldRendererId;
using autofill::FormData;
+using autofill::FormRendererId;
using autofill::FormStructure;
using autofill::NEW_PASSWORD;
using autofill::NOT_USERNAME;
@@ -58,6 +62,8 @@ using autofill::UNKNOWN_TYPE;
using autofill::USERNAME;
using autofill::mojom::PasswordFormFieldPredictionType;
using base::NumberToString;
+using BlacklistedStatus =
+ password_manager::OriginCredentialStore::BlacklistedStatus;
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
using password_manager::metrics_util::GaiaPasswordHashChange;
#endif // SYNC_PASSWORD_REUSE_DETECTION_ENABLED
@@ -223,6 +229,11 @@ void PasswordManager::RegisterProfilePrefs(
registry->RegisterDictionaryPref(prefs::kAccountStoragePerAccountSettings);
+ registry->RegisterTimePref(prefs::kProfileStoreDateLastUsedForFilling,
+ base::Time());
+ registry->RegisterTimePref(prefs::kAccountStoreDateLastUsedForFilling,
+ base::Time());
+
#if defined(OS_MACOSX)
registry->RegisterIntegerPref(prefs::kKeychainMigrationStatus,
4 /* MIGRATED_DELETED */);
@@ -293,7 +304,7 @@ void PasswordManager::OnPasswordNoLongerGenerated(PasswordManagerDriver* driver,
void PasswordManager::SetGenerationElementAndReasonForForm(
password_manager::PasswordManagerDriver* driver,
const FormData& form_data,
- const base::string16& generation_element,
+ FieldRendererId generation_element,
bool is_manually_triggered) {
DCHECK(client_->IsSavingAndFillingEnabled(form_data.url));
@@ -304,11 +315,34 @@ void PasswordManager::SetGenerationElementAndReasonForForm(
}
}
+void PasswordManager::MarkWasUnblacklistedInFormManagers(
+ CredentialCache* credential_cache) {
+ if (owned_submitted_form_manager_) {
+ const OriginCredentialStore& credential_store =
+ credential_cache->GetCredentialStore(
+ url::Origin::Create(owned_submitted_form_manager_->GetURL()));
+ if (credential_store.GetBlacklistedStatus() ==
+ BlacklistedStatus::kWasBlacklisted) {
+ owned_submitted_form_manager_->MarkWasUnblacklisted();
+ }
+ }
+
+ for (const auto& form_manager : form_managers_) {
+ const OriginCredentialStore& credential_store =
+ credential_cache->GetCredentialStore(
+ url::Origin::Create(form_manager->GetURL()));
+ if (credential_store.GetBlacklistedStatus() ==
+ BlacklistedStatus::kWasBlacklisted) {
+ form_manager->MarkWasUnblacklisted();
+ }
+ }
+}
+
void PasswordManager::DidNavigateMainFrame(bool form_may_be_submitted) {
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+ logger = std::make_unique<BrowserSavePasswordProgressLogger>(
+ client_->GetLogManager());
logger->LogBoolean(Logger::STRING_DID_NAVIGATE_MAIN_FRAME,
form_may_be_submitted);
}
@@ -483,7 +517,7 @@ void PasswordManager::OnPasswordFormsParsed(
driver ? driver->GetPasswordGenerationHelper() : nullptr;
if (password_generation_manager) {
password_generation_manager->PrefetchSpec(
- client_->GetLastCommittedEntryURL().GetOrigin());
+ client_->GetLastCommittedOrigin().GetURL());
}
}
@@ -492,8 +526,8 @@ void PasswordManager::CreatePendingLoginManagers(
const std::vector<FormData>& forms_data) {
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+ logger = std::make_unique<BrowserSavePasswordProgressLogger>(
+ client_->GetLogManager());
logger->LogMessage(Logger::STRING_CREATE_LOGIN_MANAGERS_METHOD);
}
@@ -574,8 +608,8 @@ PasswordFormManager* PasswordManager::ProvisionallySaveForm(
bool is_manual_fallback) {
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+ logger = std::make_unique<BrowserSavePasswordProgressLogger>(
+ client_->GetLogManager());
logger->LogMessage(Logger::STRING_PROVISIONALLY_SAVE_FORM_METHOD);
}
if (!client_->IsSavingAndFillingEnabled(submitted_form.url)) {
@@ -588,11 +622,11 @@ PasswordFormManager* PasswordManager::ProvisionallySaveForm(
if (store_password_called_)
return nullptr;
- const GURL& origin = submitted_form.url;
- if (ShouldBlockPasswordForSameOriginButDifferentScheme(origin)) {
+ const GURL& submitted_url = submitted_form.url;
+ if (ShouldBlockPasswordForSameOriginButDifferentScheme(submitted_url)) {
RecordProvisionalSaveFailure(
- PasswordManagerMetricsRecorder::SAVING_ON_HTTP_AFTER_HTTPS, origin,
- logger.get());
+ PasswordManagerMetricsRecorder::SAVING_ON_HTTP_AFTER_HTTPS,
+ submitted_url, logger.get());
return nullptr;
}
@@ -634,10 +668,9 @@ PasswordFormManager* PasswordManager::ProvisionallySaveForm(
manager->set_not_submitted();
}
- // Cache the user-visible URL (i.e., the one seen in the omnibox). Once the
- // post-submit navigation concludes, we compare the landing URL against the
- // cached and report the difference through UMA.
- main_frame_url_ = client_->GetMainFrameURL();
+ // Cache the committed URL. Once the post-submit navigation concludes, we
+ // compare the landing URL against the cached and report the difference.
+ submitted_form_url_ = submitted_url;
ReportSubmittedFormFrameMetric(driver, *matched_manager->GetSubmittedForm());
@@ -667,7 +700,7 @@ void PasswordManager::PresaveGeneratedPassword(
PasswordManagerDriver* driver,
const FormData& form,
const base::string16& generated_password,
- const base::string16& generation_element) {
+ FieldRendererId generation_element) {
PasswordFormManager* form_manager = GetMatchedManager(driver, form);
UMA_HISTOGRAM_BOOLEAN("PasswordManager.GeneratedFormHasNoFormManager",
!form_manager);
@@ -681,12 +714,11 @@ void PasswordManager::PresaveGeneratedPassword(
void PasswordManager::UpdateStateOnUserInput(
PasswordManagerDriver* driver,
- const base::string16& form_identifier,
- const base::string16& field_identifier,
+ FormRendererId form_id,
+ FieldRendererId field_id,
const base::string16& field_value) {
for (std::unique_ptr<PasswordFormManager>& manager : form_managers_) {
- if (manager->UpdateStateOnUserInput(form_identifier, field_identifier,
- field_value)) {
+ if (manager->UpdateStateOnUserInput(form_id, field_id, field_value)) {
ProvisionallySaveForm(manager->observed_form(), driver, true);
if (manager->is_submitted() && !manager->HasGeneratedPassword()) {
ShowManualFallbackForSavingImpl(manager.get(),
@@ -704,13 +736,34 @@ void PasswordManager::OnPasswordNoLongerGenerated(
for (std::unique_ptr<PasswordFormManager>& manager : form_managers_)
manager->PasswordNoLongerGenerated();
}
+
+void PasswordManager::OnPasswordFormRemoved(PasswordManagerDriver* driver,
+ FormRendererId form_id) {
+ for (auto& manager : form_managers_) {
+ if (driver && !manager->GetDriver())
+ manager->SetDriver(driver->AsWeakPtr());
+ if (manager->DoesManageAccordingToRendererId(form_id, driver)) {
+ if (manager->is_submitted())
+ OnLoginSuccessful();
+ return;
+ }
+ }
+}
+
+void PasswordManager::OnIframeDetach(const std::string& frame_id) {
+ PasswordFormManager* submitted_manager = GetSubmittedManager();
+ if (submitted_manager &&
+ submitted_manager->observed_form().frame_id == frame_id) {
+ OnLoginSuccessful();
+ }
+}
#endif
bool PasswordManager::IsAutomaticSavePromptAvailable() {
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+ logger = std::make_unique<BrowserSavePasswordProgressLogger>(
+ client_->GetLogManager());
logger->LogMessage(Logger::STRING_CAN_PROVISIONAL_MANAGER_SAVE_METHOD);
}
@@ -729,7 +782,7 @@ bool PasswordManager::IsAutomaticSavePromptAvailable() {
// We just give up.
RecordProvisionalSaveFailure(
PasswordManagerMetricsRecorder::MATCHING_NOT_COMPLETE,
- submitted_manager->GetOrigin(), logger.get());
+ submitted_manager->GetURL(), logger.get());
return false;
}
@@ -737,10 +790,10 @@ bool PasswordManager::IsAutomaticSavePromptAvailable() {
}
bool PasswordManager::ShouldBlockPasswordForSameOriginButDifferentScheme(
- const GURL& origin) const {
- const GURL& old_origin = main_frame_url_.GetOrigin();
- return old_origin.host_piece() == origin.host_piece() &&
- old_origin.SchemeIsCryptographic() && !origin.SchemeIsCryptographic();
+ const GURL& url) const {
+ return submitted_form_url_.host_piece() == url.host_piece() &&
+ submitted_form_url_.SchemeIsCryptographic() &&
+ !url.SchemeIsCryptographic();
}
void PasswordManager::OnPasswordFormsRendered(
@@ -750,8 +803,8 @@ void PasswordManager::OnPasswordFormsRendered(
CreatePendingLoginManagers(driver, visible_forms_data);
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+ logger = std::make_unique<BrowserSavePasswordProgressLogger>(
+ client_->GetLogManager());
logger->LogMessage(Logger::STRING_ON_PASSWORD_FORMS_RENDERED_METHOD);
}
@@ -833,16 +886,14 @@ void PasswordManager::OnPasswordFormsRendered(
void PasswordManager::OnLoginSuccessful() {
if (autofill_assistant_mode_ == AutofillAssistantMode::kRunning) {
- // Autofillassistan performs one login. Only one prompt should
- // be suppressed.
- SetAutofillAssistantMode(AutofillAssistantMode::kNotRunning);
+ // Suppress prompts while Autofill Assistant is running.
return;
}
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+ logger = std::make_unique<BrowserSavePasswordProgressLogger>(
+ client_->GetLogManager());
logger->LogMessage(Logger::STRING_ON_ASK_USER_OR_SAVE_PASSWORD);
}
@@ -874,7 +925,7 @@ void PasswordManager::OnLoginSuccessful() {
*submitted_manager->GetSubmittedForm())) {
RecordProvisionalSaveFailure(
PasswordManagerMetricsRecorder::SYNC_CREDENTIAL,
- submitted_manager->GetOrigin(), logger.get());
+ submitted_manager->GetURL(), logger.get());
owned_submitted_form_manager_.reset();
return;
}
@@ -883,7 +934,7 @@ void PasswordManager::OnLoginSuccessful() {
UMA_HISTOGRAM_BOOLEAN(
"PasswordManager.SuccessfulLoginHappened",
- submitted_manager->GetSubmittedForm()->origin.SchemeIsCryptographic());
+ submitted_manager->GetSubmittedForm()->url.SchemeIsCryptographic());
// If the form is eligible only for saving fallback, it shouldn't go here.
DCHECK(!submitted_manager->GetPendingCredentials().only_for_fallback);
@@ -991,8 +1042,8 @@ void PasswordManager::ProcessAutofillPredictions(
const std::vector<FormStructure*>& forms) {
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+ logger = std::make_unique<BrowserSavePasswordProgressLogger>(
+ client_->GetLogManager());
}
for (const FormStructure* form : forms) {
@@ -1071,7 +1122,7 @@ void PasswordManager::RecordProvisionalSaveFailure(
BrowserSavePasswordProgressLogger* logger) {
if (client_ && client_->GetMetricsRecorder()) {
client_->GetMetricsRecorder()->RecordProvisionalSaveFailure(
- failure, main_frame_url_, form_origin, logger);
+ failure, submitted_form_url_, form_origin, logger);
}
}
@@ -1101,14 +1152,12 @@ void PasswordManager::ReportSubmittedFormFrameMetric(
metrics_util::SubmittedFormFrame frame;
if (driver->IsMainFrame()) {
frame = metrics_util::SubmittedFormFrame::MAIN_FRAME;
- } else if (form.origin == main_frame_url_) {
+ } else if (form.url == client()->GetLastCommittedURL()) {
frame =
metrics_util::SubmittedFormFrame::IFRAME_WITH_SAME_URL_AS_MAIN_FRAME;
} else {
- GURL::Replacements rep;
- rep.SetPathStr("");
std::string main_frame_signon_realm =
- main_frame_url_.ReplaceComponents(rep).spec();
+ GetSignonRealm(client()->GetLastCommittedURL());
frame = (main_frame_signon_realm == form.signon_realm)
? metrics_util::SubmittedFormFrame::
IFRAME_WITH_DIFFERENT_URL_SAME_SIGNON_REALM_AS_MAIN_FRAME
@@ -1178,6 +1227,10 @@ void PasswordManager::SetAutofillAssistantMode(AutofillAssistantMode mode) {
}
}
+AutofillAssistantMode PasswordManager::GetAutofillAssistantMode() const {
+ return autofill_assistant_mode_;
+}
+
void PasswordManager::ResetAutofillAssistantMode() {
// The timeout is 0 only in the dedicated test. Otherwise, the call can happen
// only due to a bug.
diff --git a/chromium/components/password_manager/core/browser/password_manager.h b/chromium/components/password_manager/core/browser/password_manager.h
index ef4ddc0f4d0..7087751b236 100644
--- a/chromium/components/password_manager/core/browser/password_manager.h
+++ b/chromium/components/password_manager/core/browser/password_manager.h
@@ -20,6 +20,7 @@
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/autofill/core/common/renderer_id.h"
#include "components/autofill/core/common/signatures.h"
+#include "components/password_manager/core/browser/credential_cache.h"
#include "components/password_manager/core/browser/form_parsing/password_field_prediction.h"
#include "components/password_manager/core/browser/form_submission_observer.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_check_factory.h"
@@ -105,9 +106,14 @@ class PasswordManager : public FormSubmissionObserver {
void SetGenerationElementAndReasonForForm(
PasswordManagerDriver* driver,
const autofill::FormData& form_data,
- const base::string16& generation_element,
+ autofill::FieldRendererId generation_element,
bool is_manually_triggered);
+ // Called upon navigation to persist the state from |CredentialCache|
+ // used to decide when to record
+ // |PasswordManager.ResultOfSavingFlowAfterUnblacklistin|.
+ void MarkWasUnblacklistedInFormManagers(CredentialCache* credential_cache);
+
// FormSubmissionObserver:
void DidNavigateMainFrame(bool form_may_be_submitted) override;
@@ -208,8 +214,13 @@ class PasswordManager : public FormSubmissionObserver {
// Notifies that Credential Management API function store() is called.
void NotifyStorePasswordCalled();
+ // Sets the autofill-assistant mode. Certain prompts will be disabled while
+ // autofill-assistant is running. See |AutofillAssistantMode|.
void SetAutofillAssistantMode(AutofillAssistantMode mode);
+ // Returns the currently set autofill-assistant mode.
+ AutofillAssistantMode GetAutofillAssistantMode() const;
+
#if defined(OS_IOS)
// TODO(https://crbug.com/866444): Use these methods instead olds ones when
// the old parser is gone.
@@ -221,20 +232,26 @@ class PasswordManager : public FormSubmissionObserver {
void PresaveGeneratedPassword(PasswordManagerDriver* driver,
const autofill::FormData& form,
const base::string16& generated_password,
- const base::string16& generation_element);
+ autofill::FieldRendererId generation_element);
// Updates the state if the PasswordFormManager which corresponds to the form
// with |form_identifier|. In case if there is a presaved credential it
// updates the presaved credential.
void UpdateStateOnUserInput(PasswordManagerDriver* driver,
- const base::string16& form_identifier,
- const base::string16& field_identifier,
+ autofill::FormRendererId form_id,
+ autofill::FieldRendererId field_id,
const base::string16& field_value);
// Stops treating a password as generated. |driver| corresponds to the
// form parent frame.
void OnPasswordNoLongerGenerated(PasswordManagerDriver* driver);
+ void OnPasswordFormRemoved(PasswordManagerDriver* driver,
+ autofill::FormRendererId form_id);
+
+ // Checks if there is a submitted PasswordFormManager for a form from the
+ // detached frame.
+ void OnIframeDetach(const std::string& frame_id);
#endif
private:
@@ -378,8 +395,8 @@ class PasswordManager : public FormSubmissionObserver {
// Server predictions for the forms on the page.
std::map<autofill::FormSignature, FormPredictions> predictions_;
- // The user-visible URL from the last time a password was provisionally saved.
- GURL main_frame_url_;
+ // The URL of the last submitted form.
+ GURL submitted_form_url_;
// True if Credential Management API function store() was called. In this case
// PasswordManager does not need to show a save/update prompt since
diff --git a/chromium/components/password_manager/core/browser/password_manager_client.cc b/chromium/components/password_manager/core/browser/password_manager_client.cc
index df7ebde0bcd..ac7fd054e2c 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_client.cc
@@ -25,7 +25,7 @@ bool PasswordManagerClient::IsFillingFallbackEnabled(const GURL& url) const {
return true;
}
-void PasswordManagerClient::PostHSTSQueryForHost(const GURL& origin,
+void PasswordManagerClient::PostHSTSQueryForHost(const url::Origin& origin,
HSTSCallback callback) const {
std::move(callback).Run(HSTSResult::kError);
}
@@ -39,13 +39,13 @@ BiometricAuthenticator* PasswordManagerClient::GetBiometricAuthenticator() {
void PasswordManagerClient::GeneratePassword() {}
void PasswordManagerClient::UpdateCredentialCache(
- const GURL& origin,
+ const url::Origin& origin,
const std::vector<const autofill::PasswordForm*>& best_matches,
bool is_blacklisted) {}
void PasswordManagerClient::PasswordWasAutofilled(
const std::vector<const autofill::PasswordForm*>& best_matches,
- const GURL& origin,
+ const url::Origin& origin,
const std::vector<const autofill::PasswordForm*>* federated_matches) {}
void PasswordManagerClient::AutofillHttpAuth(
@@ -58,6 +58,7 @@ void PasswordManagerClient::NotifyUserCredentialsWereLeaked(
const base::string16& username) {}
void PasswordManagerClient::TriggerReauthForPrimaryAccount(
+ signin_metrics::ReauthAccessPoint access_point,
base::OnceCallback<void(ReauthSucceeded)> reauth_callback) {
std::move(reauth_callback).Run(ReauthSucceeded(false));
}
@@ -115,11 +116,7 @@ PasswordManagerClient::GetAutofillDownloadManager() {
return nullptr;
}
-const GURL& PasswordManagerClient::GetMainFrameURL() const {
- return GURL::EmptyGURL();
-}
-
-bool PasswordManagerClient::IsMainFrameSecure() const {
+bool PasswordManagerClient::IsCommittedMainFrameSecure() const {
return false;
}
@@ -148,4 +145,8 @@ bool PasswordManagerClient::IsUnderAdvancedProtection() const {
return false;
}
+AutofillAssistantMode PasswordManagerClient::GetAutofillAssistantMode() const {
+ return GetPasswordManager()->GetAutofillAssistantMode();
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_client.h b/chromium/components/password_manager/core/browser/password_manager_client.h
index b1589f91539..7892425a1d4 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/password_manager_client.h
@@ -21,6 +21,7 @@
#include "components/password_manager/core/browser/http_auth_manager.h"
#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
#include "components/password_manager/core/browser/manage_passwords_referrer.h"
+#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_reuse_detector.h"
#include "components/password_manager/core/browser/password_store.h"
@@ -49,6 +50,11 @@ class IdentityManager;
namespace signin_metrics {
enum class AccessPoint;
+enum class ReauthAccessPoint;
+} // namespace signin_metrics
+
+namespace url {
+class Origin;
}
class GURL;
@@ -65,7 +71,6 @@ class FieldInfoManager;
class PasswordFeatureManager;
class BiometricAuthenticator;
class PasswordFormManagerForUI;
-class PasswordManager;
class PasswordManagerDriver;
class PasswordManagerMetricsRecorder;
class HttpAuthManager;
@@ -114,7 +119,7 @@ class PasswordManagerClient {
// Checks asynchronously whether HTTP Strict Transport Security (HSTS) is
// active for the host of the given origin. Notifies |callback| with the
// result on the calling thread.
- virtual void PostHSTSQueryForHost(const GURL& origin,
+ virtual void PostHSTSQueryForHost(const url::Origin& origin,
HSTSCallback callback) const;
// Informs the embedder of a password form that can be saved or updated in
@@ -171,7 +176,7 @@ class PasswordManagerClient {
// |callback| should be invoked with the chosen form.
virtual bool PromptUserToChooseCredentials(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
- const GURL& origin,
+ const url::Origin& origin,
const CredentialsCallback& callback) = 0;
// Instructs the client to show the Touch To Fill UI.
@@ -191,7 +196,7 @@ class PasswordManagerClient {
// auto signed in to.
virtual void NotifyUserAutoSignin(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
- const GURL& origin) = 0;
+ const url::Origin& origin) = 0;
// Inform the embedder that automatic signin would have happened if the user
// had been through the first-run experience to ensure their opt-in. |form|
@@ -211,7 +216,7 @@ class PasswordManagerClient {
// Update the CredentialCache used to display fetched credentials in the UI.
// Currently only implemented on Android.
virtual void UpdateCredentialCache(
- const GURL& origin,
+ const url::Origin& origin,
const std::vector<const autofill::PasswordForm*>& best_matches,
bool is_blacklisted);
@@ -229,7 +234,7 @@ class PasswordManagerClient {
// implementation is a noop.
virtual void PasswordWasAutofilled(
const std::vector<const autofill::PasswordForm*>& best_matches,
- const GURL& origin,
+ const url::Origin& origin,
const std::vector<const autofill::PasswordForm*>* federated_matches);
// Sends username/password from |preferred_match| for filling in the http auth
@@ -242,9 +247,12 @@ class PasswordManagerClient {
const GURL& origin,
const base::string16& username);
- // Requests a reauth for the primary account and triggers the
- // |reauth_callback| with ReauthSucceeded(true) if reauthentication succeeded.
+ // Requests a reauth for the primary account with |access_point| representing
+ // where the reauth was triggered.
+ // Triggers the |reauth_callback| with ReauthSucceeded(true) if
+ // reauthentication succeeded.
virtual void TriggerReauthForPrimaryAccount(
+ signin_metrics::ReauthAccessPoint access_point,
base::OnceCallback<void(ReauthSucceeded)> reauth_callback);
// Redirects the user to a sign-in in a new tab. |access_point| is used for
@@ -298,13 +306,14 @@ class PasswordManagerClient {
// Returns the AutofillDownloadManager for votes uploading.
virtual autofill::AutofillDownloadManager* GetAutofillDownloadManager();
- // Returns the main frame URL.
- virtual const GURL& GetMainFrameURL() const;
-
// Returns true if the main frame URL has a secure origin.
- virtual bool IsMainFrameSecure() const;
+ virtual bool IsCommittedMainFrameSecure() const;
- virtual const GURL& GetLastCommittedEntryURL() const = 0;
+ // Returns the committed main frame URL.
+ virtual const GURL& GetLastCommittedURL() const = 0;
+
+ // Returns last committed origin of the main frame.
+ virtual url::Origin GetLastCommittedOrigin() const = 0;
// Use this to filter credentials before handling them in password manager.
virtual const CredentialsFilter* GetStoreResultFilter() const = 0;
@@ -402,6 +411,9 @@ class PasswordManagerClient {
// Returns a FieldInfoManager associated with the current profile.
virtual FieldInfoManager* GetFieldInfoManager() const = 0;
+ // Returns the currently set autofill-assistant mode.
+ virtual AutofillAssistantMode GetAutofillAssistantMode() const;
+
private:
DISALLOW_COPY_AND_ASSIGN(PasswordManagerClient);
};
diff --git a/chromium/components/password_manager/core/browser/password_manager_client_helper.cc b/chromium/components/password_manager/core/browser/password_manager_client_helper.cc
index 4fc18c3c45a..c6ff2da28ae 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client_helper.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_client_helper.cc
@@ -5,6 +5,7 @@
#include "components/password_manager/core/browser/password_manager_client_helper.h"
#include "components/password_manager/core/browser/password_bubble_experiment.h"
+#include "components/password_manager/core/browser/password_feature_manager.h"
#include "components/password_manager/core/browser/password_form_manager_for_ui.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/common/password_manager_features.h"
@@ -19,7 +20,7 @@ PasswordManagerClientHelper::PasswordManagerClientHelper(
DCHECK(delegate_);
}
-PasswordManagerClientHelper::~PasswordManagerClientHelper() {}
+PasswordManagerClientHelper::~PasswordManagerClientHelper() = default;
void PasswordManagerClientHelper::NotifyUserCouldBeAutoSignedIn(
std::unique_ptr<autofill::PasswordForm> form) {
@@ -33,16 +34,14 @@ void PasswordManagerClientHelper::NotifySuccessfulLoginWithExistingPassword(
if (!possible_auto_sign_in_ ||
possible_auto_sign_in_->username_value != form.username_value ||
possible_auto_sign_in_->password_value != form.password_value ||
- possible_auto_sign_in_->origin != form.origin ||
+ possible_auto_sign_in_->url != form.url ||
!ShouldPromptToEnableAutoSignIn()) {
possible_auto_sign_in_.reset();
}
// Check if it is necessary to prompt user to enable auto sign-in.
if (possible_auto_sign_in_) {
delegate_->PromptUserToEnableAutosignin();
- } else if (base::FeatureList::IsEnabled(
- password_manager::features::kEnablePasswordsAccountStorage) &&
- submitted_manager->IsMovableToAccountStore()) {
+ } else if (ShouldPromptToMovePasswordToAccount(*submitted_manager)) {
delegate_->PromptUserToMovePasswordToAccount(std::move(submitted_manager));
}
}
@@ -84,4 +83,14 @@ bool PasswordManagerClientHelper::ShouldPromptToEnableAutoSignIn() const {
!delegate_->IsIncognito();
}
+bool PasswordManagerClientHelper::ShouldPromptToMovePasswordToAccount(
+ const PasswordFormManagerForUI& submitted_manager) const {
+ return delegate_->GetPasswordFeatureManager()
+ ->ShouldShowAccountStorageBubbleUi() &&
+ delegate_->GetPasswordFeatureManager()->GetDefaultPasswordStore() ==
+ autofill::PasswordForm::Store::kAccountStore &&
+ submitted_manager.IsMovableToAccountStore() &&
+ !delegate_->IsIncognito();
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_client_helper.h b/chromium/components/password_manager/core/browser/password_manager_client_helper.h
index 387288c4f85..ff588801b97 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client_helper.h
+++ b/chromium/components/password_manager/core/browser/password_manager_client_helper.h
@@ -49,6 +49,12 @@ class PasswordManagerClientHelper {
// is the case for first run experience, and only for non-incognito mode.
bool ShouldPromptToEnableAutoSignIn() const;
+ // Returns whether the user should be prompted to move the submitted password
+ // to the account-scoped store. This is the case if the password is movable,
+ // the corresponding feature flag is enabled, and only for non-incognito mode.
+ bool ShouldPromptToMovePasswordToAccount(
+ const PasswordFormManagerForUI& submitted_manager) const;
+
PasswordManagerClient* delegate_;
// Set during 'NotifyUserCouldBeAutoSignedIn' in order to store the
diff --git a/chromium/components/password_manager/core/browser/password_manager_client_helper_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_client_helper_unittest.cc
index a4269bb1fbd..affef187b88 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client_helper_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_client_helper_unittest.cc
@@ -54,7 +54,7 @@ PasswordForm CreateForm(std::string username,
PasswordForm form;
form.username_value = base::ASCIIToUTF16(username);
form.password_value = base::ASCIIToUTF16(password);
- form.origin = origin;
+ form.url = origin;
form.signon_realm = origin.spec();
return form;
}
@@ -104,10 +104,13 @@ TEST_F(PasswordManagerClientHelperTest, PromptAutosigninAfterSuccessfulLogin) {
CreateFormManager(&form, /*is_movable=*/true));
}
-TEST_F(PasswordManagerClientHelperTest, PromptAutosigninDisabledInIncognito) {
+TEST_F(PasswordManagerClientHelperTest,
+ PromptAutosigninAndMoveDisabledInIncognito) {
EXPECT_CALL(*client(), IsIncognito)
.Times(AnyNumber())
.WillRepeatedly(Return(true));
+ // In Incognito, both the auto-signin and the "Move password to account?"
+ // bubbles should be disabled.
EXPECT_CALL(*client(), PromptUserToEnableAutosignin).Times(0);
EXPECT_CALL(*client(), PromptUserToMovePasswordToAccount).Times(0);
@@ -118,14 +121,33 @@ TEST_F(PasswordManagerClientHelperTest, PromptAutosigninDisabledInIncognito) {
CreateFormManager(&form, /*is_movable=*/true));
}
-TEST_F(PasswordManagerClientHelperTest, PromptMoveForMovableForm) {
- base::test::ScopedFeatureList account_storage_feature;
- account_storage_feature.InitAndEnableFeature(
- password_manager::features::kEnablePasswordsAccountStorage);
+TEST_F(PasswordManagerClientHelperTest, PromptMoveForMovableFormInAccountMode) {
+ EXPECT_CALL(*client()->GetPasswordFeatureManager(),
+ ShouldShowAccountStorageBubbleUi)
+ .WillOnce(Return(true));
+ EXPECT_CALL(*client()->GetPasswordFeatureManager(), GetDefaultPasswordStore)
+ .WillOnce(Return(autofill::PasswordForm::Store::kAccountStore));
EXPECT_CALL(*client(), PromptUserToMovePasswordToAccount);
EXPECT_CALL(*client(), PromptUserToEnableAutosignin).Times(0);
- // Indicate successful login without matching form.
+ // Indicate successful login.
+ const PasswordForm form =
+ CreateForm(kTestUsername, kTestPassword, GURL(kTestOrigin));
+ helper()->NotifySuccessfulLoginWithExistingPassword(
+ CreateFormManager(&form, /*is_movable=*/true));
+}
+
+TEST_F(PasswordManagerClientHelperTest,
+ NoPromptToMoveForMovableFormInProfileMode) {
+ EXPECT_CALL(*client()->GetPasswordFeatureManager(),
+ ShouldShowAccountStorageBubbleUi)
+ .WillOnce(Return(true));
+ EXPECT_CALL(*client()->GetPasswordFeatureManager(), GetDefaultPasswordStore)
+ .WillOnce(Return(autofill::PasswordForm::Store::kProfileStore));
+ EXPECT_CALL(*client(), PromptUserToMovePasswordToAccount).Times(0);
+ EXPECT_CALL(*client(), PromptUserToEnableAutosignin).Times(0);
+
+ // Indicate successful login.
const PasswordForm form =
CreateForm(kTestUsername, kTestPassword, GURL(kTestOrigin));
helper()->NotifySuccessfulLoginWithExistingPassword(
diff --git a/chromium/components/password_manager/core/browser/password_manager_driver.h b/chromium/components/password_manager/core/browser/password_manager_driver.h
index 48cdd98f121..1250f1be3f3 100644
--- a/chromium/components/password_manager/core/browser/password_manager_driver.h
+++ b/chromium/components/password_manager/core/browser/password_manager_driver.h
@@ -48,8 +48,13 @@ class PasswordManagerDriver
// Informs the driver that there are no saved credentials in the password
// store for the current page.
+ // |should_show_popup_without_passwords| instructs the driver that the popup
+ // should be shown even without password suggestions. This is set to true if
+ // the popup will include another item that the driver doesn't know about
+ // (e.g. a promo to unlock passwords from the user's Google Account).
// TODO(https://crbug.com/621355): Remove and observe FormFetcher instead.
- virtual void InformNoSavedCredentials() {}
+ virtual void InformNoSavedCredentials(
+ bool should_show_popup_without_passwords) {}
// Notifies the driver that a password can be generated on the fields
// identified by |form|.
diff --git a/chromium/components/password_manager/core/browser/password_manager_features_util.cc b/chromium/components/password_manager/core/browser/password_manager_features_util.cc
index 7bd4931784d..a287f60d5a8 100644
--- a/chromium/components/password_manager/core/browser/password_manager_features_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_features_util.cc
@@ -4,6 +4,9 @@
#include "components/password_manager/core/browser/password_manager_features_util.h"
+#include <algorithm>
+
+#include "base/containers/flat_set.h"
#include "base/metrics/histogram_functions.h"
#include "base/values.h"
#include "components/autofill/core/common/gaia_id_hash.h"
@@ -71,6 +74,20 @@ PasswordForm::Store PasswordStoreFromInt(int value) {
const char kAccountStorageOptedInKey[] = "opted_in";
const char kAccountStorageDefaultStoreKey[] = "default_store";
+// Returns the total number of accounts for which an opt-in to the account
+// storage exists. Used for metrics.
+int GetNumberOfOptedInAccounts(const PrefService* pref_service) {
+ const base::DictionaryValue* global_pref =
+ pref_service->GetDictionary(prefs::kAccountStoragePerAccountSettings);
+ int count = 0;
+ for (const std::pair<std::string, std::unique_ptr<base::Value>>& entry :
+ *global_pref) {
+ if (entry.second->FindBoolKey(kAccountStorageOptedInKey).value_or(false))
+ ++count;
+ }
+ return count;
+}
+
// Helper class for reading account storage settings for a given account.
class AccountStorageSettingsReader {
public:
@@ -221,6 +238,11 @@ void OptInToAccountStorage(PrefService* pref_service,
ScopedAccountStorageSettingsUpdate(pref_service,
GaiaIdHash::FromGaiaId(gaia_id))
.SetOptedIn();
+
+ // Record the total number of (now) opted-in accounts.
+ base::UmaHistogramExactLinear(
+ "PasswordManager.AccountStorage.NumOptedInAccountsAfterOptIn",
+ GetNumberOfOptedInAccounts(pref_service), 10);
}
void OptOutOfAccountStorageAndClearSettings(
@@ -241,13 +263,25 @@ void OptOutOfAccountStorageAndClearSettings(
// opt-out UI was triggered.
return;
}
+
+ OptOutOfAccountStorageAndClearSettingsForAccount(pref_service, gaia_id);
+}
+
+void OptOutOfAccountStorageAndClearSettingsForAccount(
+ PrefService* pref_service,
+ const std::string& gaia_id) {
ScopedAccountStorageSettingsUpdate(pref_service,
GaiaIdHash::FromGaiaId(gaia_id))
.ClearAllSettings();
+
+ // Record the total number of (still) opted-in accounts.
+ base::UmaHistogramExactLinear(
+ "PasswordManager.AccountStorage.NumOptedInAccountsAfterOptOut",
+ GetNumberOfOptedInAccounts(pref_service), 10);
}
-bool ShouldShowPasswordStorePicker(const PrefService* pref_service,
- const syncer::SyncService* sync_service) {
+bool ShouldShowAccountStorageBubbleUi(const PrefService* pref_service,
+ const syncer::SyncService* sync_service) {
return !sync_service->IsSyncFeatureEnabled() &&
(IsOptedInForAccountStorage(pref_service, sync_service) ||
IsUserEligibleForAccountStorage(sync_service));
@@ -291,13 +325,48 @@ void SetDefaultPasswordStore(PrefService* pref_service,
// but is ultimately harmless - just do nothing here.
return;
}
+
ScopedAccountStorageSettingsUpdate(pref_service,
GaiaIdHash::FromGaiaId(gaia_id))
.SetDefaultStore(default_store);
+
+ base::UmaHistogramEnumeration("PasswordManager.DefaultPasswordStoreSet",
+ default_store);
+}
+
+void KeepAccountStorageSettingsOnlyForUsers(
+ PrefService* pref_service,
+ const std::vector<std::string>& gaia_ids) {
+ DCHECK(pref_service);
+
+ // Build a set of hashes of all the Gaia IDs.
+ std::vector<std::string> hashes_to_keep_list;
+ for (const std::string& gaia_id : gaia_ids)
+ hashes_to_keep_list.push_back(GaiaIdHash::FromGaiaId(gaia_id).ToBase64());
+ base::flat_set<std::string> hashes_to_keep(std::move(hashes_to_keep_list));
+
+ // Now remove any settings for account that are *not* in the set of hashes.
+ // DictionaryValue doesn't allow removing elements while iterating, so first
+ // collect all the keys to remove, then actually remove them in a second pass.
+ DictionaryPrefUpdate update(pref_service,
+ prefs::kAccountStoragePerAccountSettings);
+ std::vector<std::string> keys_to_remove;
+ for (auto kv : update->DictItems()) {
+ if (!hashes_to_keep.contains(kv.first))
+ keys_to_remove.push_back(kv.first);
+ }
+ for (const std::string& key_to_remove : keys_to_remove)
+ update->RemoveKey(key_to_remove);
}
void ClearAccountStorageSettingsForAllUsers(PrefService* pref_service) {
DCHECK(pref_service);
+
+ // Record the total number of opted-in accounts before clearing them.
+ base::UmaHistogramExactLinear(
+ "PasswordManager.AccountStorage.ClearedOptInForAllAccounts",
+ GetNumberOfOptedInAccounts(pref_service), 10);
+
pref_service->ClearPref(prefs::kAccountStoragePerAccountSettings);
}
diff --git a/chromium/components/password_manager/core/browser/password_manager_features_util.h b/chromium/components/password_manager/core/browser/password_manager_features_util.h
index a524b4c391a..4f46739870c 100644
--- a/chromium/components/password_manager/core/browser/password_manager_features_util.h
+++ b/chromium/components/password_manager/core/browser/password_manager_features_util.h
@@ -61,16 +61,21 @@ void OptOutOfAccountStorageAndClearSettings(
PrefService* pref_service,
const syncer::SyncService* sync_service);
-// Whether it makes sense to ask the user about the store when saving a
-// password (i.e. profile or account store). This is true if the user has
-// opted in already, or hasn't opted in but all other requirements are met (i.e.
-// there is a signed-in user, Sync-the-feature is not enabled, etc).
-// |pref_service| must not be null.
-// |sync_service| may be null (commonly the case in incognito mode), in which
-// case this will simply return false.
-// See PasswordFeatureManager::ShouldShowPasswordStorePicker.
-bool ShouldShowPasswordStorePicker(const PrefService* pref_service,
- const syncer::SyncService* sync_service);
+// Like OptOutOfAccountStorageAndClearSettings(), but applies to a specific
+// given |gaia_id| rather than to the current signed-in user.
+void OptOutOfAccountStorageAndClearSettingsForAccount(
+ PrefService* pref_service,
+ const std::string& gaia_id);
+
+// Whether it makes sense to ask the user to move a password to their account or
+// about the store when saving a password (i.e. profile or account store). This
+// is true if the user has opted in already, or hasn't opted in but all other
+// requirements are met (i.e. there is a signed-in user, Sync-the-feature is not
+// enabled, etc). |pref_service| must not be null. |sync_service| may be null
+// (commonly the case in incognito mode), in which case this will simply return
+// false. See PasswordFeatureManager::ShouldShowPasswordStorePicker.
+bool ShouldShowAccountStorageBubbleUi(const PrefService* pref_service,
+ const syncer::SyncService* sync_service);
// Sets the default storage location for signed-in but non-syncing users. This
// store is used for saving new credentials and adding blacking listing entries.
@@ -91,6 +96,14 @@ autofill::PasswordForm::Store GetDefaultPasswordStore(
const PrefService* pref_service,
const syncer::SyncService* sync_service);
+// Clears all account-storage-related settings for all users *except* the ones
+// in the passed-in |gaia_ids|. Most notably, this includes the opt-in, but also
+// all other related settings like the default password store.
+// |pref_service| must not be null.
+void KeepAccountStorageSettingsOnlyForUsers(
+ PrefService* pref_service,
+ const std::vector<std::string>& gaia_ids);
+
// Clears all account-storage-related settings for all users. Most notably, this
// includes the opt-in, but also all other related settings like the default
// password store. Meant to be called when account cookies were cleared.
diff --git a/chromium/components/password_manager/core/browser/password_manager_features_util_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_features_util_unittest.cc
index f1a5f9c7c2b..261f11ace51 100644
--- a/chromium/components/password_manager/core/browser/password_manager_features_util_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_features_util_unittest.cc
@@ -167,7 +167,7 @@ TEST(PasswordFeatureManagerUtil, AccountStoragePerAccountSettings) {
// Initially the user is not signed in, so everything is off/local.
EXPECT_FALSE(IsOptedInForAccountStorage(&pref_service, &sync_service));
EXPECT_FALSE(ShouldShowAccountStorageOptIn(&pref_service, &sync_service));
- EXPECT_FALSE(ShouldShowPasswordStorePicker(&pref_service, &sync_service));
+ EXPECT_FALSE(ShouldShowAccountStorageBubbleUi(&pref_service, &sync_service));
EXPECT_EQ(GetDefaultPasswordStore(&pref_service, &sync_service),
autofill::PasswordForm::Store::kProfileStore);
@@ -220,6 +220,55 @@ TEST(PasswordFeatureManagerUtil, AccountStoragePerAccountSettings) {
autofill::PasswordForm::Store::kProfileStore);
}
+TEST(PasswordFeatureManagerUtil, AccountStorageKeepSettingsOnlyForUsers) {
+ base::test::ScopedFeatureList features;
+ features.InitAndEnableFeature(features::kEnablePasswordsAccountStorage);
+
+ TestingPrefServiceSimple pref_service;
+ pref_service.registry()->RegisterDictionaryPref(
+ prefs::kAccountStoragePerAccountSettings);
+
+ CoreAccountInfo first_account;
+ first_account.email = "first@account.com";
+ first_account.gaia = "first";
+ first_account.account_id = CoreAccountId::FromGaiaId(first_account.gaia);
+
+ CoreAccountInfo second_account;
+ second_account.email = "second@account.com";
+ second_account.gaia = "second";
+ second_account.account_id = CoreAccountId::FromGaiaId(second_account.gaia);
+
+ syncer::TestSyncService sync_service;
+ sync_service.SetDisableReasons({});
+ sync_service.SetIsAuthenticatedAccountPrimary(false);
+ sync_service.SetTransportState(syncer::SyncService::TransportState::ACTIVE);
+
+ // Let SyncService run in transport mode with |first_account| and opt in.
+ sync_service.SetAuthenticatedAccountInfo(first_account);
+ OptInToAccountStorage(&pref_service, &sync_service);
+ ASSERT_TRUE(IsOptedInForAccountStorage(&pref_service, &sync_service));
+
+ // Switch to |second_account| and again opt in.
+ sync_service.SetAuthenticatedAccountInfo(second_account);
+ OptInToAccountStorage(&pref_service, &sync_service);
+ ASSERT_TRUE(IsOptedInForAccountStorage(&pref_service, &sync_service));
+
+ // Sign out. The opt-in still exists, but doesn't apply anymore.
+ sync_service.SetAuthenticatedAccountInfo(CoreAccountInfo());
+ ASSERT_FALSE(IsOptedInForAccountStorage(&pref_service, &sync_service));
+
+ // Keep the opt-in only for |first_account| (and some unknown other user).
+ KeepAccountStorageSettingsOnlyForUsers(&pref_service,
+ {first_account.gaia, "other_gaia_id"});
+
+ // The first account should still be opted in, but not the second.
+ sync_service.SetAuthenticatedAccountInfo(first_account);
+ EXPECT_TRUE(IsOptedInForAccountStorage(&pref_service, &sync_service));
+
+ sync_service.SetAuthenticatedAccountInfo(second_account);
+ EXPECT_FALSE(IsOptedInForAccountStorage(&pref_service, &sync_service));
+}
+
TEST(PasswordFeatureManagerUtil, SyncSuppressesAccountStorageOptIn) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(features::kEnablePasswordsAccountStorage);
@@ -245,7 +294,7 @@ TEST(PasswordFeatureManagerUtil, SyncSuppressesAccountStorageOptIn) {
// In this state, the user could opt in to the account storage.
ASSERT_FALSE(IsOptedInForAccountStorage(&pref_service, &sync_service));
ASSERT_TRUE(ShouldShowAccountStorageOptIn(&pref_service, &sync_service));
- ASSERT_TRUE(ShouldShowPasswordStorePicker(&pref_service, &sync_service));
+ ASSERT_TRUE(ShouldShowAccountStorageBubbleUi(&pref_service, &sync_service));
// Now the user enables Sync-the-feature.
sync_service.SetIsAuthenticatedAccountPrimary(true);
@@ -255,7 +304,7 @@ TEST(PasswordFeatureManagerUtil, SyncSuppressesAccountStorageOptIn) {
// Now the account-storage opt-in should *not* be available anymore.
EXPECT_FALSE(IsOptedInForAccountStorage(&pref_service, &sync_service));
EXPECT_FALSE(ShouldShowAccountStorageOptIn(&pref_service, &sync_service));
- EXPECT_FALSE(ShouldShowPasswordStorePicker(&pref_service, &sync_service));
+ EXPECT_FALSE(ShouldShowAccountStorageBubbleUi(&pref_service, &sync_service));
}
TEST(PasswordFeatureManagerUtil, SyncDisablesAccountStorage) {
@@ -283,7 +332,7 @@ TEST(PasswordFeatureManagerUtil, SyncDisablesAccountStorage) {
// and saving will default to the account store.
ASSERT_FALSE(IsOptedInForAccountStorage(&pref_service, &sync_service));
ASSERT_TRUE(ShouldShowAccountStorageOptIn(&pref_service, &sync_service));
- ASSERT_TRUE(ShouldShowPasswordStorePicker(&pref_service, &sync_service));
+ ASSERT_TRUE(ShouldShowAccountStorageBubbleUi(&pref_service, &sync_service));
ASSERT_EQ(GetDefaultPasswordStore(&pref_service, &sync_service),
autofill::PasswordForm::Store::kAccountStore);
@@ -291,7 +340,7 @@ TEST(PasswordFeatureManagerUtil, SyncDisablesAccountStorage) {
OptInToAccountStorage(&pref_service, &sync_service);
ASSERT_TRUE(IsOptedInForAccountStorage(&pref_service, &sync_service));
ASSERT_FALSE(ShouldShowAccountStorageOptIn(&pref_service, &sync_service));
- ASSERT_TRUE(ShouldShowPasswordStorePicker(&pref_service, &sync_service));
+ ASSERT_TRUE(ShouldShowAccountStorageBubbleUi(&pref_service, &sync_service));
ASSERT_EQ(GetDefaultPasswordStore(&pref_service, &sync_service),
autofill::PasswordForm::Store::kAccountStore);
@@ -303,7 +352,7 @@ TEST(PasswordFeatureManagerUtil, SyncDisablesAccountStorage) {
ASSERT_TRUE(sync_service.IsSyncFeatureEnabled());
EXPECT_TRUE(IsOptedInForAccountStorage(&pref_service, &sync_service));
EXPECT_FALSE(ShouldShowAccountStorageOptIn(&pref_service, &sync_service));
- EXPECT_FALSE(ShouldShowPasswordStorePicker(&pref_service, &sync_service));
+ EXPECT_FALSE(ShouldShowAccountStorageBubbleUi(&pref_service, &sync_service));
EXPECT_EQ(GetDefaultPasswordStore(&pref_service, &sync_service),
autofill::PasswordForm::Store::kProfileStore);
}
@@ -347,6 +396,76 @@ TEST(PasswordFeatureManagerUtil, OptOutClearsStorePreference) {
histogram_tester.ExpectUniqueSample(
"PasswordManager.AccountStorage.SignedInAccountFoundDuringOptOut", true,
1);
+ // The change to the profile store above should have been recorded. Clearing
+ // the pref does not get recorded in this histogram!
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.DefaultPasswordStoreSet",
+ autofill::PasswordForm::Store::kProfileStore, 1);
+}
+
+TEST(PasswordFeatureManagerUtil, OptInOutHistograms) {
+ base::test::ScopedFeatureList features;
+ features.InitAndEnableFeature(features::kEnablePasswordsAccountStorage);
+ base::HistogramTester histogram_tester;
+
+ TestingPrefServiceSimple pref_service;
+ pref_service.registry()->RegisterDictionaryPref(
+ prefs::kAccountStoragePerAccountSettings);
+
+ syncer::TestSyncService sync_service;
+ sync_service.SetDisableReasons({});
+ sync_service.SetTransportState(syncer::SyncService::TransportState::ACTIVE);
+ sync_service.SetIsAuthenticatedAccountPrimary(false);
+
+ CoreAccountInfo first_account;
+ first_account.email = "first@account.com";
+ first_account.gaia = "first";
+ first_account.account_id = CoreAccountId::FromGaiaId(first_account.gaia);
+
+ CoreAccountInfo second_account;
+ second_account.email = "second@account.com";
+ second_account.gaia = "second";
+ second_account.account_id = CoreAccountId::FromGaiaId(second_account.gaia);
+
+ // Opt in with the first account.
+ sync_service.SetAuthenticatedAccountInfo(first_account);
+ OptInToAccountStorage(&pref_service, &sync_service);
+ // There is now 1 opt-in.
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.AccountStorage.NumOptedInAccountsAfterOptIn", 1);
+ histogram_tester.ExpectBucketCount(
+ "PasswordManager.AccountStorage.NumOptedInAccountsAfterOptIn", 1, 1);
+
+ // Opt in with the second account.
+ sync_service.SetAuthenticatedAccountInfo(second_account);
+ OptInToAccountStorage(&pref_service, &sync_service);
+ // There are now 2 opt-ins.
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.AccountStorage.NumOptedInAccountsAfterOptIn", 2);
+ histogram_tester.ExpectBucketCount(
+ "PasswordManager.AccountStorage.NumOptedInAccountsAfterOptIn", 2, 1);
+
+ // Out out of the second account again.
+ OptOutOfAccountStorageAndClearSettings(&pref_service, &sync_service);
+ // The OptedIn histogram is unchanged.
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.AccountStorage.NumOptedInAccountsAfterOptIn", 2);
+ // There is now an OptedOut sample; there is 1 opt-in left.
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.AccountStorage.NumOptedInAccountsAfterOptOut", 1);
+ histogram_tester.ExpectBucketCount(
+ "PasswordManager.AccountStorage.NumOptedInAccountsAfterOptOut", 1, 1);
+
+ // Clear all remaining opt-ins (which is just one).
+ ClearAccountStorageSettingsForAllUsers(&pref_service);
+ // The OptedIn/OptedOut histograms are unchanged.
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.AccountStorage.NumOptedInAccountsAfterOptIn", 2);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.AccountStorage.NumOptedInAccountsAfterOptOut", 1);
+ // There was 1 remaining opt-in that was cleared.
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStorage.ClearedOptInForAllAccounts", 1, 1);
}
} // namespace features_util
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc
index 8ebf89d0f90..c8f492e88dc 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc
@@ -20,11 +20,9 @@ namespace password_manager {
PasswordManagerMetricsRecorder::PasswordManagerMetricsRecorder(
ukm::SourceId source_id,
- const GURL& main_frame_url,
std::unique_ptr<NavigationMetricRecorderDelegate>
navigation_metric_recorder)
- : main_frame_url_(main_frame_url),
- ukm_entry_builder_(
+ : ukm_entry_builder_(
std::make_unique<ukm::builders::PageWithPassword>(source_id)),
navigation_metric_recorder_(std::move(navigation_metric_recorder)) {}
@@ -45,16 +43,14 @@ PasswordManagerMetricsRecorder& PasswordManagerMetricsRecorder::operator=(
void PasswordManagerMetricsRecorder::RecordUserModifiedPasswordField() {
if (!user_modified_password_field_ && navigation_metric_recorder_) {
- navigation_metric_recorder_->OnUserModifiedPasswordFieldFirstTime(
- main_frame_url_);
+ navigation_metric_recorder_->OnUserModifiedPasswordFieldFirstTime();
}
user_modified_password_field_ = true;
}
void PasswordManagerMetricsRecorder::RecordUserFocusedPasswordField() {
if (!user_focused_password_field_ && navigation_metric_recorder_) {
- navigation_metric_recorder_->OnUserFocusedPasswordFieldFirstTime(
- main_frame_url_);
+ navigation_metric_recorder_->OnUserFocusedPasswordFieldFirstTime();
}
user_focused_password_field_ = true;
}
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h
index c83090a5527..94c8e320068 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h
@@ -85,20 +85,16 @@ class PasswordManagerMetricsRecorder {
// about the current navigation.
class NavigationMetricRecorderDelegate {
public:
+ virtual ~NavigationMetricRecorderDelegate() = default;
// Called the first time the user focuses on a password field.
- virtual void OnUserFocusedPasswordFieldFirstTime(
- const GURL& main_frame_url) = 0;
+ virtual void OnUserFocusedPasswordFieldFirstTime() = 0;
// Called the first time the user types into a password field.
- virtual void OnUserModifiedPasswordFieldFirstTime(
- const GURL& main_frame_url) = 0;
-
- virtual ~NavigationMetricRecorderDelegate() = default;
+ virtual void OnUserModifiedPasswordFieldFirstTime() = 0;
};
// Records UKM metrics and reports them on destruction.
PasswordManagerMetricsRecorder(
ukm::SourceId source_id,
- const GURL& main_frame_url,
std::unique_ptr<NavigationMetricRecorderDelegate>
navigation_metric_recorder);
@@ -130,9 +126,6 @@ class PasswordManagerMetricsRecorder {
void RecordPageLevelUserAction(PageLevelUserAction action);
private:
- // URL for which UKMs are reported.
- GURL main_frame_url_;
-
// Records URL keyed metrics (UKMs) and submits them on its destruction.
std::unique_ptr<ukm::builders::PageWithPassword> ukm_entry_builder_;
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder_unittest.cc
index 09b7061dc2a..eaa179a8fd7 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder_unittest.cc
@@ -21,14 +21,12 @@ namespace password_manager {
namespace {
-constexpr char kTestUrl[] = "https://www.example.com/";
constexpr ukm::SourceId kTestSourceId = 0x1234;
using UkmEntry = ukm::builders::PageWithPassword;
-// Creates a PasswordManagerMetricsRecorder that reports metrics for kTestUrl.
PasswordManagerMetricsRecorder CreateMetricsRecorder() {
- return PasswordManagerMetricsRecorder(kTestSourceId, GURL(kTestUrl), nullptr);
+ return PasswordManagerMetricsRecorder(kTestSourceId, nullptr);
}
} // namespace
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc b/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc
index 25a29b853b3..7b1cef82685 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc
@@ -8,6 +8,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/strings/strcat.h"
#include "components/autofill/core/common/password_generation_util.h"
+#include "components/password_manager/core/common/password_manager_features.h"
using autofill::password_generation::PasswordGenerationType;
@@ -57,9 +58,27 @@ void LogGeneralUIDismissalReason(UIDismissalReason reason) {
NUM_UI_RESPONSES);
}
-void LogSaveUIDismissalReason(UIDismissalReason reason) {
+void LogSaveUIDismissalReason(
+ UIDismissalReason reason,
+ base::Optional<PasswordAccountStorageUserState> user_state) {
base::UmaHistogramEnumeration("PasswordManager.SaveUIDismissalReason", reason,
NUM_UI_RESPONSES);
+
+ if (user_state.has_value()) {
+ DCHECK(base::FeatureList::IsEnabled(
+ password_manager::features::kEnablePasswordsAccountStorage));
+ std::string suffix =
+ GetPasswordAccountStorageUserStateHistogramSuffix(user_state.value());
+ base::UmaHistogramEnumeration(
+ "PasswordManager.SaveUIDismissalReason." + suffix, reason,
+ NUM_UI_RESPONSES);
+ }
+}
+
+void LogSaveUIDismissalReasonAfterUnblacklisting(UIDismissalReason reason) {
+ base::UmaHistogramEnumeration(
+ "PasswordManager.SaveUIDismissalReasonAfterUnblacklisting", reason,
+ NUM_UI_RESPONSES);
}
void LogUpdateUIDismissalReason(UIDismissalReason reason) {
@@ -67,6 +86,21 @@ void LogUpdateUIDismissalReason(UIDismissalReason reason) {
reason, NUM_UI_RESPONSES);
}
+void LogMoveUIDismissalReason(UIDismissalReason reason,
+ PasswordAccountStorageUserState user_state) {
+ DCHECK(base::FeatureList::IsEnabled(
+ password_manager::features::kEnablePasswordsAccountStorage));
+
+ base::UmaHistogramEnumeration("PasswordManager.MoveUIDismissalReason", reason,
+ NUM_UI_RESPONSES);
+
+ std::string suffix =
+ GetPasswordAccountStorageUserStateHistogramSuffix(user_state);
+ base::UmaHistogramEnumeration(
+ "PasswordManager.MoveUIDismissalReason." + suffix, reason,
+ NUM_UI_RESPONSES);
+}
+
void LogLeakDialogTypeAndDismissalReason(LeakDialogType type,
LeakDialogDismissalReason reason) {
static constexpr char kHistogram[] =
@@ -221,6 +255,13 @@ void LogSubmittedFormFrame(SubmittedFormFrame frame) {
SubmittedFormFrame::SUBMITTED_FORM_FRAME_COUNT);
}
+void LogPasswordsCountFromAccountStoreAfterUnlock(
+ int account_store_passwords_count) {
+ base::UmaHistogramCounts100(
+ "PasswordManager.CredentialsCountFromAccountStoreAfterUnlock",
+ account_store_passwords_count);
+}
+
void LogPasswordSettingsReauthResult(ReauthResult result) {
base::UmaHistogramEnumeration(
"PasswordManager.ReauthToAccessPasswordInSettings", result);
@@ -232,11 +273,6 @@ void LogDeleteUndecryptableLoginsReturnValue(
"PasswordManager.DeleteUndecryptableLoginsReturnValue", result);
}
-void LogDeleteCorruptedPasswordsResult(DeleteCorruptedPasswordsResult result) {
- base::UmaHistogramEnumeration(
- "PasswordManager.DeleteCorruptedPasswordsResult", result);
-}
-
void LogNewlySavedPasswordIsGenerated(
bool value,
PasswordAccountStorageUsageLevel account_storage_usage_level) {
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_util.h b/chromium/components/password_manager/core/browser/password_manager_metrics_util.h
index 9ad5d5df6ea..dfee676caba 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -164,7 +164,9 @@ enum class CredentialManagerGetResult {
kAutoSignIn,
// No credentials are returned in incognito mode.
kNoneIncognito,
- kMaxValue = kNoneIncognito,
+ // No credentials are returned while autofill_assistant is running.
+ kNoneAutofillAssistant,
+ kMaxValue = kNoneAutofillAssistant,
};
enum PasswordReusePasswordFieldDetected {
@@ -355,6 +357,8 @@ enum class PasswordDropdownState {
};
// Type of the item the user selects in the password drop-down.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
enum class PasswordDropdownSelectedOption {
// User selected a credential to fill.
kPassword = 0,
@@ -362,7 +366,13 @@ enum class PasswordDropdownSelectedOption {
kShowAll = 1,
// User selected to generate a password.
kGenerate = 2,
- kMaxValue = kGenerate
+ // User unlocked the account-store to fill a password.
+ kUnlockAccountStorePasswords = 3,
+ // User unlocked the account-store to generate a password.
+ kUnlockAccountStoreGeneration = 4,
+ // Previoulsy opted-in user decided to log-in again to access their passwords.
+ kResigninToUnlockAccountStore = 5,
+ kMaxValue = kResigninToUnlockAccountStore
};
// Used in UMA histograms, please do NOT reorder.
@@ -398,6 +408,20 @@ enum class PasswordAccountStorageUserState {
// Syncing user.
kSyncUser,
};
+
+// Metrics: PasswordManager.MoveToAccountStoreTrigger.
+// This must be kept in sync with the enum in password_move_to_account_dialog.js
+// (in chrome/browser/resources/settings/autofill_page).
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class MoveToAccountStoreTrigger {
+ // The user successfully logged in with a password from the profile store.
+ kSuccessfulLoginWithProfileStorePassword = 0,
+ // The user explicitly asked to move a password listed in Settings.
+ kExplicitlyTriggeredInSettings = 1,
+ kMaxValue = kExplicitlyTriggeredInSettings,
+};
+
std::string GetPasswordAccountStorageUserStateHistogramSuffix(
PasswordAccountStorageUserState user_state);
@@ -421,12 +445,25 @@ std::string GetPasswordAccountStorageUsageLevelHistogramSuffix(
// bubbles.
void LogGeneralUIDismissalReason(UIDismissalReason reason);
-// Log the |reason| a user dismissed the save password bubble.
-void LogSaveUIDismissalReason(UIDismissalReason reason);
+// Log the |reason| a user dismissed the save password bubble. If
+// |user_state| is set, the |reason| is also logged to a separate
+// user-state-specific histogram. |user_state| must be non-null iff the feature
+// kEnablePasswordsAccountStorage is enabled.
+void LogSaveUIDismissalReason(
+ UIDismissalReason reason,
+ base::Optional<PasswordAccountStorageUserState> user_state);
+
+// Log the |reason| a user dismissed the save password prompt after previously
+// having unblacklisted the origin while on the page.
+void LogSaveUIDismissalReasonAfterUnblacklisting(UIDismissalReason reason);
// Log the |reason| a user dismissed the update password bubble.
void LogUpdateUIDismissalReason(UIDismissalReason reason);
+// Log the |reason| a user dismissed the move password bubble.
+void LogMoveUIDismissalReason(UIDismissalReason reason,
+ PasswordAccountStorageUserState user_state);
+
// Log the |type| of a leak dialog shown to the user and the |reason| why it was
// dismissed.
void LogLeakDialogTypeAndDismissalReason(LeakDialogType type,
@@ -500,6 +537,9 @@ void LogPasswordAcceptedSaveUpdateSubmissionIndicatorEvent(
// Log a frame of a submitted password form.
void LogSubmittedFormFrame(SubmittedFormFrame frame);
+// Logs how many account-stored passwords are available right after unlock.
+void LogPasswordsCountFromAccountStoreAfterUnlock(int account_store_passwords);
+
// Logs the result of a re-auth challenge in the password settings.
void LogPasswordSettingsReauthResult(ReauthResult result);
@@ -507,10 +547,6 @@ void LogPasswordSettingsReauthResult(ReauthResult result);
void LogDeleteUndecryptableLoginsReturnValue(
DeleteCorruptedPasswordsResult result);
-// Log a result of removing passwords that couldn't be decrypted with the
-// present encryption key on MacOS.
-void LogDeleteCorruptedPasswordsResult(DeleteCorruptedPasswordsResult result);
-
// Log whether a saved password was generated.
void LogNewlySavedPasswordIsGenerated(
bool value,
diff --git a/chromium/components/password_manager/core/browser/password_manager_onboarding_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_onboarding_unittest.cc
index d6ae68ec499..533bd0d8ac5 100644
--- a/chromium/components/password_manager/core/browser/password_manager_onboarding_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_onboarding_unittest.cc
@@ -11,6 +11,7 @@
#include "base/bind_helpers.h"
#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
@@ -36,13 +37,9 @@ namespace password_manager {
class PasswordManagerOnboardingTest : public testing::Test {
public:
- PasswordManagerOnboardingTest() = default;
-
void SetUp() override {
- store_ = new TestPasswordStore;
store_->Init(nullptr);
- prefs_.reset(new TestingPrefServiceSimple());
prefs_->registry()->RegisterIntegerPref(
prefs::kPasswordManagerOnboardingState,
static_cast<int>(OnboardingState::kDoNotShow));
@@ -63,7 +60,7 @@ class PasswordManagerOnboardingTest : public testing::Test {
PasswordForm MakeSimpleForm(int id) {
PasswordForm form;
- form.origin = GURL("https://example.org/");
+ form.url = GURL("https://example.org/");
form.signon_realm = "https://example.org/";
form.username_value = ASCIIToUTF16("username") + base::NumberToString16(id);
form.password_value = ASCIIToUTF16("p4ssword") + base::NumberToString16(id);
@@ -73,7 +70,7 @@ class PasswordManagerOnboardingTest : public testing::Test {
PasswordForm MakeSimpleBlacklistedForm(int id) {
PasswordForm form;
std::string link = "https://example" + base::NumberToString(id) + ".org/";
- form.origin = GURL(link);
+ form.url = GURL(link);
form.signon_realm = link;
form.blacklisted_by_user = true;
return form;
@@ -81,8 +78,10 @@ class PasswordManagerOnboardingTest : public testing::Test {
protected:
base::test::TaskEnvironment task_environment_;
- scoped_refptr<TestPasswordStore> store_;
- std::unique_ptr<TestingPrefServiceSimple> prefs_;
+ scoped_refptr<TestPasswordStore> store_ =
+ base::MakeRefCounted<TestPasswordStore>();
+ std::unique_ptr<TestingPrefServiceSimple> prefs_ =
+ std::make_unique<TestingPrefServiceSimple>();
};
TEST_F(PasswordManagerOnboardingTest, CredentialsCountUnderThreshold) {
diff --git a/chromium/components/password_manager/core/browser/password_manager_test_utils.cc b/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
index 46f95aa975e..961da21aec2 100644
--- a/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
@@ -28,7 +28,7 @@ std::unique_ptr<PasswordForm> PasswordFormFromData(
if (form_data.signon_realm)
form->signon_realm = std::string(form_data.signon_realm);
if (form_data.origin)
- form->origin = GURL(form_data.origin);
+ form->url = GURL(form_data.origin);
if (form_data.action)
form->action = GURL(form_data.action);
if (form_data.submit_element)
@@ -72,7 +72,7 @@ std::unique_ptr<autofill::PasswordForm> CreateEntry(
auto form = std::make_unique<autofill::PasswordForm>();
form->username_value = base::ASCIIToUTF16(username);
form->password_value = base::ASCIIToUTF16(password);
- form->origin = origin_url;
+ form->url = origin_url;
form->is_public_suffix_match = is_psl_match;
form->is_affiliation_based_match = is_affiliation_based_match;
return form;
@@ -119,14 +119,16 @@ bool ContainsEqualPasswordFormsUnordered(
return !had_mismatched_actual_form && remaining_expectations.empty();
}
-MockPasswordStoreObserver::MockPasswordStoreObserver() {}
+MockPasswordStoreObserver::MockPasswordStoreObserver() = default;
-MockPasswordStoreObserver::~MockPasswordStoreObserver() {}
+MockPasswordStoreObserver::~MockPasswordStoreObserver() = default;
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
-MockPasswordReuseDetectorConsumer::MockPasswordReuseDetectorConsumer() {}
+MockPasswordReuseDetectorConsumer::MockPasswordReuseDetectorConsumer() =
+ default;
-MockPasswordReuseDetectorConsumer::~MockPasswordReuseDetectorConsumer() {}
+MockPasswordReuseDetectorConsumer::~MockPasswordReuseDetectorConsumer() =
+ default;
PasswordHashDataMatcher::PasswordHashDataMatcher(
base::Optional<PasswordHashData> expected)
diff --git a/chromium/components/password_manager/core/browser/password_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
index e7624b3cab6..a6932409908 100644
--- a/chromium/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
@@ -137,32 +137,52 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
ON_CALL(*this, IsNewTabPage()).WillByDefault(Return(false));
}
- MOCK_CONST_METHOD1(IsSavingAndFillingEnabled, bool(const GURL&));
- MOCK_CONST_METHOD0(GetMainFrameCertStatus, net::CertStatus());
- MOCK_METHOD2(AutofillHttpAuth,
- void(const autofill::PasswordForm&,
- const PasswordFormManagerForUI*));
- MOCK_CONST_METHOD0(GetProfilePasswordStore, PasswordStore*());
+ MOCK_METHOD(bool,
+ IsSavingAndFillingEnabled,
+ (const GURL&),
+ (const, override));
+ MOCK_METHOD(net::CertStatus, GetMainFrameCertStatus, (), (const, override));
+ MOCK_METHOD(void,
+ AutofillHttpAuth,
+ (const autofill::PasswordForm&, const PasswordFormManagerForUI*),
+ (override));
+ MOCK_METHOD(PasswordStore*, GetProfilePasswordStore, (), (const, override));
+ MOCK_METHOD(PasswordStore*, GetAccountPasswordStore, (), (const, override));
// The code inside EXPECT_CALL for PromptUserToSaveOrUpdatePasswordPtr and
// ShowManualFallbackForSavingPtr owns the PasswordFormManager* argument.
- MOCK_METHOD1(PromptUserToSaveOrUpdatePasswordPtr,
- void(PasswordFormManagerForUI*));
- MOCK_METHOD1(ShowOnboarding, bool(std::unique_ptr<PasswordFormManagerForUI>));
- MOCK_METHOD3(ShowManualFallbackForSavingPtr,
- void(PasswordFormManagerForUI*, bool, bool));
- MOCK_METHOD0(HideManualFallbackForSaving, void());
- MOCK_METHOD1(NotifySuccessfulLoginWithExistingPassword,
- void(std::unique_ptr<PasswordFormManagerForUI>));
- MOCK_METHOD0(AutomaticPasswordSaveIndicator, void());
- MOCK_CONST_METHOD0(GetPrefs, PrefService*());
- MOCK_CONST_METHOD0(GetMainFrameURL, const GURL&());
- MOCK_CONST_METHOD0(IsMainFrameSecure, bool());
- MOCK_METHOD0(GetDriver, PasswordManagerDriver*());
- MOCK_CONST_METHOD0(GetStoreResultFilter, const MockStoreResultFilter*());
- MOCK_METHOD0(GetMetricsRecorder, PasswordManagerMetricsRecorder*());
- MOCK_CONST_METHOD0(IsNewTabPage, bool());
- MOCK_CONST_METHOD0(GetPasswordSyncState, SyncState());
- MOCK_CONST_METHOD0(GetFieldInfoManager, FieldInfoManager*());
+ MOCK_METHOD(void,
+ PromptUserToSaveOrUpdatePasswordPtr,
+ (PasswordFormManagerForUI*));
+ MOCK_METHOD(bool,
+ ShowOnboarding,
+ (std::unique_ptr<PasswordFormManagerForUI>),
+ (override));
+ MOCK_METHOD(void,
+ ShowManualFallbackForSavingPtr,
+ (PasswordFormManagerForUI*, bool, bool));
+ MOCK_METHOD(void, HideManualFallbackForSaving, (), (override));
+ MOCK_METHOD(void,
+ NotifySuccessfulLoginWithExistingPassword,
+ (std::unique_ptr<PasswordFormManagerForUI>),
+ (override));
+ MOCK_METHOD(void,
+ AutomaticPasswordSave,
+ (std::unique_ptr<PasswordFormManagerForUI>),
+ (override));
+ MOCK_METHOD(PrefService*, GetPrefs, (), (const, override));
+ MOCK_METHOD(const GURL&, GetLastCommittedURL, (), (const, override));
+ MOCK_METHOD(bool, IsCommittedMainFrameSecure, (), (const, override));
+ MOCK_METHOD(const MockStoreResultFilter*,
+ GetStoreResultFilter,
+ (),
+ (const, override));
+ MOCK_METHOD(PasswordManagerMetricsRecorder*,
+ GetMetricsRecorder,
+ (),
+ (override));
+ MOCK_METHOD(bool, IsNewTabPage, (), (const, override));
+ MOCK_METHOD(SyncState, GetPasswordSyncState, (), (const, override));
+ MOCK_METHOD(FieldInfoManager*, GetFieldInfoManager, (), (const, override));
// Workaround for std::unique_ptr<> lacking a copy constructor.
bool PromptUserToSaveOrUpdatePassword(
@@ -179,10 +199,6 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
ShowManualFallbackForSavingPtr(manager.release(), has_generated_password,
is_update);
}
- void AutomaticPasswordSave(
- std::unique_ptr<PasswordFormManagerForUI> manager) override {
- AutomaticPasswordSaveIndicator();
- }
void FilterAllResultsForSaving() {
EXPECT_CALL(filter_, ShouldSave(_)).WillRepeatedly(Return(false));
@@ -212,14 +228,15 @@ class MockPasswordManagerDriver : public StubPasswordManagerDriver {
};
// Invokes the password store consumer with a single copy of |form|.
-ACTION_P(InvokeConsumer, form) {
+ACTION_P2(InvokeConsumer, store, form) {
std::vector<std::unique_ptr<PasswordForm>> result;
result.push_back(std::make_unique<PasswordForm>(form));
- arg0->OnGetPasswordStoreResults(std::move(result));
+ arg0->OnGetPasswordStoreResultsFrom(store, std::move(result));
}
-ACTION(InvokeEmptyConsumerWithForms) {
- arg0->OnGetPasswordStoreResults(std::vector<std::unique_ptr<PasswordForm>>());
+ACTION_P(InvokeEmptyConsumerWithForms, store) {
+ arg0->OnGetPasswordStoreResultsFrom(
+ store, std::vector<std::unique_ptr<PasswordForm>>());
}
ACTION_P(SaveToScopedPtr, scoped) {
@@ -307,26 +324,51 @@ class MockFieldInfoManager : public FieldInfoManager {
} // namespace
-class PasswordManagerTest : public testing::Test {
+// The test parameter controls the feature "EnablePasswordsAccountStorage".
+class PasswordManagerTest : public testing::TestWithParam<bool> {
public:
- PasswordManagerTest()
- : test_url_("https://www.example.com"),
- task_runner_(new TestMockTimeTaskRunner) {}
+ PasswordManagerTest() : task_runner_(new TestMockTimeTaskRunner) {
+ bool enable_passwords_account_storage = GetParam();
+ if (enable_passwords_account_storage) {
+ feature_list_.InitAndEnableFeature(
+ features::kEnablePasswordsAccountStorage);
+ } else {
+ feature_list_.InitAndDisableFeature(
+ features::kEnablePasswordsAccountStorage);
+ }
+ }
~PasswordManagerTest() override = default;
protected:
void SetUp() override {
store_ = new MockPasswordStore;
- ASSERT_TRUE(store_->Init(nullptr));
+ ASSERT_TRUE(store_->Init(/*prefs=*/nullptr));
ON_CALL(client_, GetProfilePasswordStore())
.WillByDefault(Return(store_.get()));
EXPECT_CALL(*store_, GetSiteStatsImpl(_)).Times(AnyNumber());
- ON_CALL(client_, GetDriver()).WillByDefault(Return(&driver_));
- manager_.reset(new PasswordManager(&client_));
- password_autofill_manager_.reset(
- new PasswordAutofillManager(client_.GetDriver(), nullptr, &client_));
+ if (base::FeatureList::IsEnabled(
+ features::kEnablePasswordsAccountStorage)) {
+ account_store_ = new MockPasswordStore;
+ ASSERT_TRUE(account_store_->Init(/*prefs=*/nullptr));
+
+ ON_CALL(client_, GetAccountPasswordStore())
+ .WillByDefault(Return(account_store_.get()));
+
+ // Most tests don't really need the account store, but it'll still get
+ // queried by MultiStoreFormFetcher, so it needs to return something to
+ // its consumers. Let the account store return empty results by default,
+ // so that not every test has to set this up individually. Individual
+ // tests that do cover the account store can still override this.
+ ON_CALL(*account_store_, GetLogins(_, _))
+ .WillByDefault(
+ WithArg<1>(InvokeEmptyConsumerWithForms(account_store_.get())));
+ }
+
+ manager_ = std::make_unique<PasswordManager>(&client_);
+ password_autofill_manager_ =
+ std::make_unique<PasswordAutofillManager>(&driver_, nullptr, &client_);
EXPECT_CALL(driver_, GetPasswordManager())
.WillRepeatedly(Return(manager_.get()));
@@ -336,15 +378,15 @@ class PasswordManagerTest : public testing::Test {
EXPECT_CALL(*store_, IsAbleToSavePasswords()).WillRepeatedly(Return(true));
- ON_CALL(client_, GetMainFrameURL()).WillByDefault(ReturnRef(test_url_));
- ON_CALL(client_, IsMainFrameSecure()).WillByDefault(Return(true));
+ ON_CALL(client_, GetLastCommittedURL()).WillByDefault(ReturnRef(test_url_));
+ ON_CALL(client_, IsCommittedMainFrameSecure()).WillByDefault(Return(true));
ON_CALL(client_, GetMetricsRecorder()).WillByDefault(Return(nullptr));
ON_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillByDefault(WithArg<0>(DeletePtr()));
ON_CALL(client_, ShowManualFallbackForSavingPtr(_, _, _))
.WillByDefault(WithArg<0>(DeletePtr()));
- prefs_.reset(new TestingPrefServiceSimple());
+ prefs_ = std::make_unique<TestingPrefServiceSimple>();
prefs_->registry()->RegisterIntegerPref(
prefs::kPasswordManagerOnboardingState,
static_cast<int>(OnboardingState::kDoNotShow));
@@ -356,6 +398,10 @@ class PasswordManagerTest : public testing::Test {
true);
prefs_->registry()->RegisterBooleanPref(::prefs::kSafeBrowsingEnhanced,
true);
+ prefs_->registry()->RegisterTimePref(
+ prefs::kProfileStoreDateLastUsedForFilling, base::Time());
+ prefs_->registry()->RegisterTimePref(
+ prefs::kAccountStoreDateLastUsedForFilling, base::Time());
ON_CALL(client_, GetPrefs()).WillByDefault(Return(prefs_.get()));
// When waiting for predictions is on, it makes tests more complicated.
@@ -366,13 +412,17 @@ class PasswordManagerTest : public testing::Test {
}
void TearDown() override {
+ if (account_store_) {
+ account_store_->ShutdownOnUIThread();
+ account_store_ = nullptr;
+ }
store_->ShutdownOnUIThread();
store_ = nullptr;
}
PasswordForm MakeSavedForm() {
PasswordForm form;
- form.origin = GURL("http://www.google.com/a/LoginAuth");
+ form.url = GURL("http://www.google.com/a/LoginAuth");
form.action = GURL("http://www.google.com/a/Login");
form.username_element = ASCIIToUTF16("Email");
form.password_element = ASCIIToUTF16("Passwd");
@@ -380,6 +430,7 @@ class PasswordManagerTest : public testing::Test {
form.password_value = ASCIIToUTF16("p4ssword");
form.submit_element = ASCIIToUTF16("signIn");
form.signon_realm = "http://www.google.com/";
+ form.in_store = PasswordForm::Store::kProfileStore;
return form;
}
@@ -420,8 +471,8 @@ class PasswordManagerTest : public testing::Test {
PasswordForm MakeSimpleGAIAForm() {
PasswordForm form = MakeSimpleForm();
form.form_data.url = GURL("https://accounts.google.com");
- form.origin = GURL("https://accounts.google.com");
- form.signon_realm = form.origin.spec();
+ form.url = GURL("https://accounts.google.com");
+ form.signon_realm = form.url.spec();
return form;
}
@@ -458,45 +509,18 @@ class PasswordManagerTest : public testing::Test {
PasswordForm MakeAndroidCredential() {
PasswordForm android_form;
- android_form.origin = GURL("android://hash@google.com");
+ android_form.url = GURL("android://hash@google.com");
android_form.signon_realm = "android://hash@google.com";
android_form.username_value = ASCIIToUTF16("google");
android_form.password_value = ASCIIToUTF16("password");
android_form.is_affiliation_based_match = true;
+ android_form.in_store = PasswordForm::Store::kProfileStore;
return android_form;
}
- // Reproduction of the form present on twitter's login page.
- PasswordForm MakeTwitterLoginForm() {
- PasswordForm form;
- form.origin = GURL("https://twitter.com/");
- form.action = GURL("https://twitter.com/sessions");
- form.username_element = ASCIIToUTF16("Email");
- form.password_element = ASCIIToUTF16("Passwd");
- form.username_value = ASCIIToUTF16("twitter");
- form.password_value = ASCIIToUTF16("password");
- form.submit_element = ASCIIToUTF16("signIn");
- form.signon_realm = "https://twitter.com/";
- return form;
- }
-
- // Reproduction of the form present on twitter's failed login page.
- PasswordForm MakeTwitterFailedLoginForm() {
- PasswordForm form;
- form.origin = GURL("https://twitter.com/login/error?redirect_after_login");
- form.action = GURL("https://twitter.com/sessions");
- form.username_element = ASCIIToUTF16("EmailField");
- form.password_element = ASCIIToUTF16("PasswdField");
- form.username_value = ASCIIToUTF16("twitter");
- form.password_value = ASCIIToUTF16("password");
- form.submit_element = ASCIIToUTF16("signIn");
- form.signon_realm = "https://twitter.com/";
- return form;
- }
-
PasswordForm MakeSimpleFormWithOnlyUsernameField() {
PasswordForm form;
- form.origin = GURL("http://www.google.com/a/LoginAuth");
+ form.url = GURL("http://www.google.com/a/LoginAuth");
form.username_element = ASCIIToUTF16("Email");
form.submit_element = ASCIIToUTF16("signIn");
form.signon_realm = "http://www.google.com/";
@@ -526,13 +550,13 @@ class PasswordManagerTest : public testing::Test {
PasswordForm MakeSimpleCreditCardForm() {
PasswordForm form;
- form.origin = GURL("https://accounts.google.com");
- form.signon_realm = form.origin.spec();
+ form.url = GURL("https://accounts.google.com");
+ form.signon_realm = form.url.spec();
form.username_element = ASCIIToUTF16("cc-number");
form.password_element = ASCIIToUTF16("cvc");
form.username_value = ASCIIToUTF16("1234567");
form.password_value = ASCIIToUTF16("123");
- form.form_data.url = form.origin;
+ form.form_data.url = form.url;
FormFieldData field;
field.name = form.username_element;
@@ -562,19 +586,22 @@ class PasswordManagerTest : public testing::Test {
manager()->OnPasswordFormSubmitted(&driver_, form_data);
}
- const GURL test_url_;
+ base::test::ScopedFeatureList feature_list_;
+
+ const GURL test_url_{"https://www.example.com"};
base::test::SingleThreadTaskEnvironment task_environment_;
scoped_refptr<MockPasswordStore> store_;
+ scoped_refptr<MockPasswordStore> account_store_;
testing::NiceMock<MockPasswordManagerClient> client_;
MockPasswordManagerDriver driver_;
+ std::unique_ptr<TestingPrefServiceSimple> prefs_;
std::unique_ptr<PasswordAutofillManager> password_autofill_manager_;
std::unique_ptr<PasswordManager> manager_;
scoped_refptr<TestMockTimeTaskRunner> task_runner_;
- std::unique_ptr<TestingPrefServiceSimple> prefs_;
};
MATCHER_P(FormMatches, form, "") {
- return form.signon_realm == arg.signon_realm && form.origin == arg.origin &&
+ return form.signon_realm == arg.signon_realm && form.url == arg.url &&
form.action == arg.action &&
form.username_element == arg.username_element &&
form.username_value == arg.username_value &&
@@ -583,7 +610,7 @@ MATCHER_P(FormMatches, form, "") {
form.new_password_element == arg.new_password_element;
}
-TEST_F(PasswordManagerTest, FormSubmitWithOnlyNewPasswordField) {
+TEST_P(PasswordManagerTest, FormSubmitWithOnlyNewPasswordField) {
// Test that when a form only contains a "new password" field, the form gets
// saved and in password store, the new password value is saved as a current
// password value.
@@ -591,11 +618,11 @@ TEST_F(PasswordManagerTest, FormSubmitWithOnlyNewPasswordField) {
PasswordForm form(MakeFormWithOnlyNewPasswordField());
observed.push_back(form.form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
OnPasswordFormSubmitted(form.form_data);
@@ -622,13 +649,13 @@ TEST_F(PasswordManagerTest, FormSubmitWithOnlyNewPasswordField) {
EXPECT_THAT(saved_form, FormMatches(expected_form));
}
-TEST_F(PasswordManagerTest, GeneratedPasswordFormSubmitEmptyStore) {
+TEST_P(PasswordManagerTest, GeneratedPasswordFormSubmitEmptyStore) {
// Test that generated passwords are stored without asking the user.
std::vector<FormData> observed;
FormData form_data(MakeFormDataWithOnlyNewPasswordField());
observed.push_back(form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -648,7 +675,7 @@ TEST_F(PasswordManagerTest, GeneratedPasswordFormSubmitEmptyStore) {
PasswordForm form_to_save;
EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, _))
.WillOnce(SaveArg<0>(&form_to_save));
- EXPECT_CALL(client_, AutomaticPasswordSaveIndicator());
+ EXPECT_CALL(client_, AutomaticPasswordSave);
// Now the password manager waits for the navigation to complete.
observed.clear();
@@ -661,7 +688,7 @@ TEST_F(PasswordManagerTest, GeneratedPasswordFormSubmitEmptyStore) {
}
#if defined(OS_IOS)
-TEST_F(PasswordManagerTest, EditingGeneratedPasswordOnIOS) {
+TEST_P(PasswordManagerTest, EditingGeneratedPasswordOnIOS) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
@@ -669,12 +696,12 @@ TEST_F(PasswordManagerTest, EditingGeneratedPasswordOnIOS) {
base::string16 username = form_data.fields[0].value;
base::string16 generated_password =
form_data.fields[1].value + ASCIIToUTF16("1");
- const base::string16 username_element = form_data.fields[0].name;
- const base::string16 generation_element = form_data.fields[1].name;
+ FieldRendererId username_element = form_data.fields[0].unique_renderer_id;
+ FieldRendererId generation_element = form_data.fields[1].unique_renderer_id;
// A form is found by PasswordManager.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, {form_data});
// The user is generating the password. The password has to be presaved.
@@ -695,7 +722,7 @@ TEST_F(PasswordManagerTest, EditingGeneratedPasswordOnIOS) {
FormHasUniqueKey(presaved_form)))
.WillOnce(SaveArg<0>(&presaved_form));
- manager()->UpdateStateOnUserInput(&driver_, form_data.name,
+ manager()->UpdateStateOnUserInput(&driver_, form_data.unique_renderer_id,
generation_element, generated_password);
Mock::VerifyAndClearExpectations(store_.get());
@@ -707,11 +734,11 @@ TEST_F(PasswordManagerTest, EditingGeneratedPasswordOnIOS) {
FormUsernamePasswordAre(username, generated_password),
FormHasUniqueKey(presaved_form)));
- manager()->UpdateStateOnUserInput(&driver_, form_data.name, username_element,
- username);
+ manager()->UpdateStateOnUserInput(&driver_, form_data.unique_renderer_id,
+ username_element, username);
}
-TEST_F(PasswordManagerTest, SavingGeneratedPasswordOnIOS) {
+TEST_P(PasswordManagerTest, SavingGeneratedPasswordOnIOS) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
@@ -719,11 +746,11 @@ TEST_F(PasswordManagerTest, SavingGeneratedPasswordOnIOS) {
const base::string16 username = form_data.fields[0].value;
base::string16 generated_password =
form_data.fields[1].value + ASCIIToUTF16("1");
- const base::string16 generation_element = form_data.fields[1].name;
+ FieldRendererId generation_element = form_data.fields[1].unique_renderer_id;
// A form is found by PasswordManager.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, {form_data});
// The user is generating the password.
@@ -734,7 +761,7 @@ TEST_F(PasswordManagerTest, SavingGeneratedPasswordOnIOS) {
EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, _));
// Test when the user is changing the generated password.
- manager()->UpdateStateOnUserInput(&driver_, form_data.name,
+ manager()->UpdateStateOnUserInput(&driver_, form_data.unique_renderer_id,
generation_element, generated_password);
// The user is submitting the form.
@@ -748,23 +775,23 @@ TEST_F(PasswordManagerTest, SavingGeneratedPasswordOnIOS) {
UpdateLoginWithPrimaryKey(
FormUsernamePasswordAre(username, generated_password), _));
EXPECT_CALL(*store_, IsAbleToSavePasswords()).WillRepeatedly(Return(true));
- EXPECT_CALL(client_, AutomaticPasswordSaveIndicator());
+ EXPECT_CALL(client_, AutomaticPasswordSave);
// Now the password manager waits for the navigation to complete.
manager()->OnPasswordFormsRendered(&driver_, {}, true);
}
-TEST_F(PasswordManagerTest, PasswordNoLongerGeneratedOnIOS) {
+TEST_P(PasswordManagerTest, PasswordNoLongerGeneratedOnIOS) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
FormData form_data = MakeSimpleFormData();
const base::string16 generated_password = form_data.fields[1].value;
- const base::string16 generation_element = form_data.fields[1].name;
+ FieldRendererId generation_element = form_data.fields[1].unique_renderer_id;
// A form is found by PasswordManager.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, {form_data});
// The user is generating the password.
@@ -778,15 +805,15 @@ TEST_F(PasswordManagerTest, PasswordNoLongerGeneratedOnIOS) {
manager()->OnPasswordNoLongerGenerated(&driver_);
}
-TEST_F(PasswordManagerTest, ShowHideManualFallbackOnIOS) {
+TEST_P(PasswordManagerTest, ShowHideManualFallbackOnIOS) {
ON_CALL(client_, IsSavingAndFillingEnabled(_)).WillByDefault(Return(true));
FormData form_data = MakeSimpleFormData();
- const base::string16 password_element = form_data.fields[1].name;
+ FieldRendererId password_element = form_data.fields[1].unique_renderer_id;
// A form is found by PasswordManager.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, {form_data});
// Check that the saving manual fallback is shown the user typed in a password
@@ -795,8 +822,8 @@ TEST_F(PasswordManagerTest, ShowHideManualFallbackOnIOS) {
EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, false))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
base::string16 typed_password = ASCIIToUTF16("password");
- manager()->UpdateStateOnUserInput(&driver_, form_data.name, password_element,
- typed_password);
+ manager()->UpdateStateOnUserInput(&driver_, form_data.unique_renderer_id,
+ password_element, typed_password);
Mock::VerifyAndClearExpectations(&client_);
ASSERT_TRUE(form_manager_to_save);
@@ -806,12 +833,12 @@ TEST_F(PasswordManagerTest, ShowHideManualFallbackOnIOS) {
// Check that the saving manual is hidden when the user cleared the password
// field value.
EXPECT_CALL(client_, HideManualFallbackForSaving());
- manager()->UpdateStateOnUserInput(&driver_, form_data.name, password_element,
- base::string16());
+ manager()->UpdateStateOnUserInput(&driver_, form_data.unique_renderer_id,
+ password_element, base::string16());
}
#endif // defined(OS_IOS)
-TEST_F(PasswordManagerTest, FormSubmitNoGoodMatch) {
+TEST_P(PasswordManagerTest, FormSubmitNoGoodMatch) {
// When the password store already contains credentials for a given form, new
// credentials get still added, as long as they differ in username from the
// stored ones.
@@ -824,10 +851,10 @@ TEST_F(PasswordManagerTest, FormSubmitNoGoodMatch) {
// TODO(https://crbug.com/949519): replace WillRepeatedly with WillOnce when
// the old parser is gone.
EXPECT_CALL(*store_, GetLogins(PasswordStore::FormDigest(form), _))
- .WillOnce(WithArg<1>(InvokeConsumer(existing_different)));
+ .WillOnce(WithArg<1>(InvokeConsumer(store_.get(), existing_different)));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
OnPasswordFormSubmitted(form.form_data);
@@ -849,15 +876,15 @@ TEST_F(PasswordManagerTest, FormSubmitNoGoodMatch) {
}
// Tests that a credential wouldn't be saved if it is already in the store.
-TEST_F(PasswordManagerTest, DontSaveAlreadySavedCredential) {
+TEST_P(PasswordManagerTest, DontSaveAlreadySavedCredential) {
PasswordForm form(MakeSimpleForm());
std::vector<FormData> observed = {form.form_data};
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
// TODO(https://crbug.com/949519): replace WillRepeatedly with WillOnce when
// the old parser is gone.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2);
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -898,14 +925,14 @@ TEST_F(PasswordManagerTest, DontSaveAlreadySavedCredential) {
}
// Tests that on Chrome sign-in form credentials are not saved.
-TEST_F(PasswordManagerTest, DoNotSaveOnChromeSignInForm) {
+TEST_P(PasswordManagerTest, DoNotSaveOnChromeSignInForm) {
FormData form_data(MakeSimpleFormData());
form_data.is_gaia_with_skip_save_password_form = true;
std::vector<FormData> observed = {form_data};
EXPECT_CALL(client_, IsSavingAndFillingEnabled(form_data.url))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -927,15 +954,15 @@ TEST_F(PasswordManagerTest, DoNotSaveOnChromeSignInForm) {
// Tests that a UKM metric "Login Passed" is sent when the submitted credentials
// are already in the store and OnPasswordFormsParsed is called multiple times.
-TEST_F(PasswordManagerTest,
+TEST_P(PasswordManagerTest,
SubmissionMetricsIsPassedWhenDontSaveAlreadySavedCredential) {
std::vector<FormData> observed;
PasswordForm form(MakeSimpleForm());
observed.push_back(form.form_data);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(AnyNumber());
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -963,12 +990,12 @@ TEST_F(PasswordManagerTest,
user_action_tester.GetActionCount("PasswordManager_LoginPassed"));
}
-TEST_F(PasswordManagerTest, FormSeenThenLeftPage) {
+TEST_P(PasswordManagerTest, FormSeenThenLeftPage) {
std::vector<FormData> observed;
FormData form_data(MakeSimpleFormData());
observed.push_back(form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -980,18 +1007,18 @@ TEST_F(PasswordManagerTest, FormSeenThenLeftPage) {
manager()->OnPasswordFormsRendered(&driver_, observed, true);
}
-TEST_F(PasswordManagerTest, FormSubmit) {
+TEST_P(PasswordManagerTest, FormSubmit) {
// Test that a plain form submit results in offering to save passwords.
PasswordForm form(MakeSimpleForm());
std::vector<FormData> observed = {form.form_data};
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
EXPECT_FALSE(manager()->IsPasswordFieldDetectedOnPage());
manager()->OnPasswordFormsParsed(&driver_, observed);
EXPECT_TRUE(manager()->IsPasswordFieldDetectedOnPage());
manager()->OnPasswordFormsRendered(&driver_, observed, true);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
OnPasswordFormSubmitted(form.form_data);
@@ -1009,7 +1036,7 @@ TEST_F(PasswordManagerTest, FormSubmit) {
form_manager_to_save->Save();
}
-TEST_F(PasswordManagerTest, OnboardingSimple) {
+TEST_P(PasswordManagerTest, OnboardingSimple) {
// Test that a plain form submit results in showing the onboarding
// if the |kShouldShow| state is set.
ON_CALL(client_, GetPasswordSyncState())
@@ -1023,7 +1050,7 @@ TEST_F(PasswordManagerTest, OnboardingSimple) {
FormData form_data(MakeSimpleFormData());
std::vector<FormData> observed = {form_data};
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1040,7 +1067,7 @@ TEST_F(PasswordManagerTest, OnboardingSimple) {
manager()->OnPasswordFormsRendered(&driver_, observed, true);
}
-TEST_F(PasswordManagerTest, OnboardingPasswordSyncDisabled) {
+TEST_P(PasswordManagerTest, OnboardingPasswordSyncDisabled) {
// Tests that the onboarding is not shown when password sync is disabled.
ON_CALL(client_, GetPasswordSyncState()).WillByDefault(Return(NOT_SYNCING));
base::test::ScopedFeatureList feature_list;
@@ -1052,7 +1079,7 @@ TEST_F(PasswordManagerTest, OnboardingPasswordSyncDisabled) {
FormData form_data(MakeSimpleFormData());
std::vector<FormData> observed = {form_data};
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1071,7 +1098,7 @@ TEST_F(PasswordManagerTest, OnboardingPasswordSyncDisabled) {
manager()->OnPasswordFormsRendered(&driver_, observed, true);
}
-TEST_F(PasswordManagerTest, OnboardingPasswordUpdate) {
+TEST_P(PasswordManagerTest, OnboardingPasswordUpdate) {
// Tests that the onboarding is not shown on password update.
ON_CALL(client_, GetPasswordSyncState())
.WillByDefault(Return(SYNCING_NORMAL_ENCRYPTION));
@@ -1088,7 +1115,8 @@ TEST_F(PasswordManagerTest, OnboardingPasswordUpdate) {
// TODO(https://crbug.com/949519): replace WillRepeatedly with WillOnce when
// the old parser is gone.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(MakeSavedForm())));
+ .WillRepeatedly(
+ WithArg<1>(InvokeConsumer(store_.get(), MakeSavedForm())));
manager()->OnPasswordFormsParsed(&driver_, observed_forms);
manager()->OnPasswordFormsRendered(&driver_, observed_forms, true);
@@ -1110,10 +1138,10 @@ TEST_F(PasswordManagerTest, OnboardingPasswordUpdate) {
manager()->OnPasswordFormsRendered(&driver_, observed_forms, true);
}
-TEST_F(PasswordManagerTest, IsPasswordFieldDetectedOnPage) {
+TEST_P(PasswordManagerTest, IsPasswordFieldDetectedOnPage) {
FormData form_data(MakeSimpleFormData());
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
EXPECT_FALSE(manager()->IsPasswordFieldDetectedOnPage());
manager()->OnPasswordFormsParsed(&driver_, {form_data});
EXPECT_TRUE(manager()->IsPasswordFieldDetectedOnPage());
@@ -1121,14 +1149,14 @@ TEST_F(PasswordManagerTest, IsPasswordFieldDetectedOnPage) {
EXPECT_FALSE(manager()->IsPasswordFieldDetectedOnPage());
}
-TEST_F(PasswordManagerTest, FormSubmitWhenPasswordsCannotBeSaved) {
+TEST_P(PasswordManagerTest, FormSubmitWhenPasswordsCannotBeSaved) {
// Test that a plain form submit doesn't result in offering to save passwords.
EXPECT_CALL(*store_, IsAbleToSavePasswords()).WillOnce(Return(false));
FormData form_data(MakeSimpleFormData());
std::vector<FormData> observed = {form_data};
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
EXPECT_FALSE(manager()->IsPasswordFieldDetectedOnPage());
manager()->OnPasswordFormsParsed(&driver_, observed);
EXPECT_TRUE(manager()->IsPasswordFieldDetectedOnPage());
@@ -1147,16 +1175,16 @@ TEST_F(PasswordManagerTest, FormSubmitWhenPasswordsCannotBeSaved) {
}
// This test verifies a fix for http://crbug.com/236673
-TEST_F(PasswordManagerTest, FormSubmitWithFormOnPreviousPage) {
+TEST_P(PasswordManagerTest, FormSubmitWithFormOnPreviousPage) {
PasswordForm first_form(MakeSimpleForm());
- first_form.origin = GURL("http://www.nytimes.com/");
- first_form.form_data.url = first_form.origin;
+ first_form.url = GURL("http://www.nytimes.com/");
+ first_form.form_data.url = first_form.url;
first_form.action = GURL("https://myaccount.nytimes.com/auth/login");
first_form.form_data.action = first_form.action;
first_form.signon_realm = "http://www.nytimes.com/";
PasswordForm second_form(MakeSimpleForm());
- second_form.origin = GURL("https://myaccount.nytimes.com/auth/login");
- second_form.form_data.url = second_form.origin;
+ second_form.url = GURL("https://myaccount.nytimes.com/auth/login");
+ second_form.form_data.url = second_form.url;
second_form.action = GURL("https://myaccount.nytimes.com/auth/login");
second_form.form_data.action = second_form.action;
second_form.signon_realm = "https://myaccount.nytimes.com/";
@@ -1165,7 +1193,7 @@ TEST_F(PasswordManagerTest, FormSubmitWithFormOnPreviousPage) {
std::vector<FormData> observed;
observed.push_back(first_form.form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
observed.clear();
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1180,7 +1208,7 @@ TEST_F(PasswordManagerTest, FormSubmitWithFormOnPreviousPage) {
manager()->OnPasswordFormsRendered(&driver_, observed, true);
// Now submit this form
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(second_form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(second_form.url))
.WillRepeatedly(Return(true));
OnPasswordFormSubmitted(second_form.form_data);
@@ -1199,18 +1227,18 @@ TEST_F(PasswordManagerTest, FormSubmitWithFormOnPreviousPage) {
form_manager_to_save->Save();
}
-TEST_F(PasswordManagerTest, FormSubmitInvisibleLogin) {
+TEST_P(PasswordManagerTest, FormSubmitInvisibleLogin) {
// Tests fix of http://crbug.com/28911: if the login form reappears on the
// subsequent page, but is invisible, it shouldn't count as a failed login.
std::vector<FormData> observed;
PasswordForm form(MakeSimpleForm());
observed.push_back(form.form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
OnPasswordFormSubmitted(form.form_data);
@@ -1230,7 +1258,7 @@ TEST_F(PasswordManagerTest, FormSubmitInvisibleLogin) {
form_manager_to_save->Save();
}
-TEST_F(PasswordManagerTest, InitiallyInvisibleForm) {
+TEST_P(PasswordManagerTest, InitiallyInvisibleForm) {
// Make sure an invisible login form still gets autofilled.
PasswordForm form(MakeSimpleForm());
std::vector<FormData> observed;
@@ -1240,17 +1268,17 @@ TEST_F(PasswordManagerTest, InitiallyInvisibleForm) {
// the
// old parser is gone.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
manager()->OnPasswordFormsParsed(&driver_, observed);
observed.clear();
manager()->OnPasswordFormsRendered(&driver_, observed, true);
}
-TEST_F(PasswordManagerTest, FillPasswordsOnDisabledManager) {
+TEST_P(PasswordManagerTest, FillPasswordsOnDisabledManager) {
// Test fix for http://crbug.com/158296: Passwords must be filled even if the
// password manager is disabled.
PasswordForm form(MakeSimpleForm());
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(false));
std::vector<FormData> observed;
observed.push_back(form.form_data);
@@ -1258,18 +1286,18 @@ TEST_F(PasswordManagerTest, FillPasswordsOnDisabledManager) {
// TODO(https://crbug.com/949519): replace WillRepeatedly with WillOnce when
// the old parser is gone.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
manager()->OnPasswordFormsParsed(&driver_, observed);
}
-TEST_F(PasswordManagerTest, PasswordFormReappearance) {
+TEST_P(PasswordManagerTest, PasswordFormReappearance) {
// If the password form reappears after submit, PasswordManager should deduce
// that the login failed and not offer saving.
std::vector<FormData> observed;
FormData login_form_data(MakeSimpleFormData());
observed.push_back(login_form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1289,7 +1317,7 @@ TEST_F(PasswordManagerTest, PasswordFormReappearance) {
// A PasswordForm appears, and is visible in the layout:
// No expected calls to the PasswordStore...
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
- EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()).Times(0);
+ EXPECT_CALL(client_, AutomaticPasswordSave).Times(0);
EXPECT_CALL(*store_, AddLogin(_)).Times(0);
EXPECT_CALL(*store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
@@ -1297,13 +1325,13 @@ TEST_F(PasswordManagerTest, PasswordFormReappearance) {
manager()->OnPasswordFormsRendered(&driver_, observed, true);
}
-TEST_F(PasswordManagerTest, SyncCredentialsNotSaved) {
+TEST_P(PasswordManagerTest, SyncCredentialsNotSaved) {
// Simulate loading a simple form with no existing stored password.
std::vector<FormData> observed;
FormData form_data(MakeSimpleGAIAFormData());
observed.push_back(form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1333,11 +1361,11 @@ TEST_F(PasswordManagerTest, SyncCredentialsNotSaved) {
}
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
-TEST_F(PasswordManagerTest, HashSavedOnGaiaFormWithSkipSavePassword) {
+TEST_P(PasswordManagerTest, HashSavedOnGaiaFormWithSkipSavePassword) {
for (bool did_stop_loading : {false, true}) {
SCOPED_TRACE(testing::Message("did_stop_loading = ") << did_stop_loading);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
std::vector<FormData> observed;
FormData form_data(MakeSimpleGAIAFormData());
@@ -1376,10 +1404,10 @@ TEST_F(PasswordManagerTest, HashSavedOnGaiaFormWithSkipSavePassword) {
}
}
-TEST_F(PasswordManagerTest,
+TEST_P(PasswordManagerTest,
HashSavedOnGaiaFormWithSkipSavePasswordAndToNTPNavigation) {
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
FormData form_data(MakeSimpleGAIAFormData());
// Simulate that this is Gaia form that should be ignored for
@@ -1411,7 +1439,7 @@ TEST_F(PasswordManagerTest,
// On a successful login with an updated password,
// CredentialsFilter::ReportFormLoginSuccess and CredentialsFilter::ShouldSave
// should be called. The argument of ShouldSave should be the submitted form.
-TEST_F(PasswordManagerTest, ReportFormLoginSuccessAndShouldSaveCalled) {
+TEST_P(PasswordManagerTest, ReportFormLoginSuccessAndShouldSaveCalled) {
PasswordForm stored_form(MakeSimpleForm());
std::vector<FormData> observed;
@@ -1424,14 +1452,14 @@ TEST_F(PasswordManagerTest, ReportFormLoginSuccessAndShouldSaveCalled) {
observed.push_back(observed_form.form_data);
// Simulate that |form| is already in the store, making this an update.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(stored_form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), stored_form)));
EXPECT_CALL(driver_, FillPasswordForm(_));
manager()->OnPasswordFormsParsed(&driver_, observed);
EXPECT_CALL(driver_, FillPasswordForm(_));
manager()->OnPasswordFormsRendered(&driver_, observed, true);
// Submit form and finish navigation.
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(observed_form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(observed_form.url))
.WillRepeatedly(Return(true));
OnPasswordFormSubmitted(observed_form.form_data);
@@ -1452,10 +1480,10 @@ TEST_F(PasswordManagerTest, ReportFormLoginSuccessAndShouldSaveCalled) {
// When there is a sync password saved, and the user successfully uses the
// stored version of it, PasswordManager should not drop that password.
-TEST_F(PasswordManagerTest, SyncCredentialsNotDroppedIfUpToDate) {
+TEST_P(PasswordManagerTest, SyncCredentialsNotDroppedIfUpToDate) {
PasswordForm form(MakeSimpleGAIAForm());
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
client_.FilterAllResultsForSaving();
@@ -1466,7 +1494,7 @@ TEST_F(PasswordManagerTest, SyncCredentialsNotDroppedIfUpToDate) {
manager()->OnPasswordFormsRendered(&driver_, observed, true);
// Submit form and finish navigation.
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
@@ -1492,11 +1520,11 @@ TEST_F(PasswordManagerTest, SyncCredentialsNotDroppedIfUpToDate) {
// While sync credentials are not saved, they are still filled to avoid users
// thinking they lost access to their accounts.
-TEST_F(PasswordManagerTest, SyncCredentialsStillFilled) {
+TEST_P(PasswordManagerTest, SyncCredentialsStillFilled) {
PasswordForm form(MakeSimpleForm());
// Pretend that the password store contains credentials stored for |form|.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
client_.FilterAllResultsForSaving();
@@ -1509,7 +1537,7 @@ TEST_F(PasswordManagerTest, SyncCredentialsStillFilled) {
EXPECT_EQ(form.password_value, form_data.password_field.value);
}
-TEST_F(PasswordManagerTest,
+TEST_P(PasswordManagerTest,
ShouldBlockPasswordForSameOriginButDifferentSchemeTest) {
constexpr struct {
const char* old_origin;
@@ -1535,7 +1563,7 @@ TEST_F(PasswordManagerTest,
for (const auto& test_case : kTestData) {
SCOPED_TRACE(testing::Message("#test_case = ") << (&test_case - kTestData));
- manager()->main_frame_url_ = GURL(test_case.old_origin);
+ manager()->submitted_form_url_ = GURL(test_case.old_origin);
GURL origin = GURL(test_case.new_origin);
EXPECT_EQ(
test_case.result,
@@ -1545,11 +1573,11 @@ TEST_F(PasswordManagerTest,
// Tests whether two submissions to the same origin but different schemes
// result in only saving the first submission, which has a secure scheme.
-TEST_F(PasswordManagerTest, AttemptedSavePasswordSameOriginInsecureScheme) {
+TEST_P(PasswordManagerTest, AttemptedSavePasswordSameOriginInsecureScheme) {
PasswordForm secure_form(MakeSimpleForm());
- secure_form.origin = GURL("https://example.com/login");
+ secure_form.url = GURL("https://example.com/login");
secure_form.action = GURL("https://example.com/login");
- secure_form.form_data.url = secure_form.origin;
+ secure_form.form_data.url = secure_form.url;
secure_form.form_data.action = secure_form.action;
secure_form.signon_realm = "https://example.com/";
@@ -1565,21 +1593,18 @@ TEST_F(PasswordManagerTest, AttemptedSavePasswordSameOriginInsecureScheme) {
insecure_form.password_value = ASCIIToUTF16("C0mpr0m1s3d_P4ss");
FormFieldData& password_field = insecure_form.form_data.fields[1];
password_field.value = insecure_form.password_value;
- insecure_form.origin = GURL("http://example.com/home");
+ insecure_form.url = GURL("http://example.com/home");
insecure_form.action = GURL("http://example.com/home");
- insecure_form.form_data.url = insecure_form.origin;
+ insecure_form.form_data.url = insecure_form.url;
insecure_form.form_data.action = insecure_form.action;
insecure_form.signon_realm = "http://example.com/";
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(secure_form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(secure_form.url))
.WillRepeatedly(Return(true));
- EXPECT_CALL(client_, GetMainFrameURL())
- .WillRepeatedly(ReturnRef(secure_form.origin));
-
// Parse, render and submit the secure form.
std::vector<FormData> observed = {secure_form.form_data};
manager()->OnPasswordFormsParsed(&driver_, observed);
@@ -1592,12 +1617,9 @@ TEST_F(PasswordManagerTest, AttemptedSavePasswordSameOriginInsecureScheme) {
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
- EXPECT_CALL(client_, GetMainFrameURL())
- .WillRepeatedly(ReturnRef(insecure_form.origin));
-
// Parse, render and submit the insecure form.
observed = {insecure_form.form_data};
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(insecure_form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(insecure_form.url))
.WillRepeatedly(Return(true));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1625,7 +1647,7 @@ TEST_F(PasswordManagerTest, AttemptedSavePasswordSameOriginInsecureScheme) {
// password forms, that would be the reasonable choice), if the new password is
// empty, this is likely just a slightly misunderstood form, and Chrome should
// save the non-empty current password field.
-TEST_F(PasswordManagerTest, DoNotSaveWithEmptyNewPasswordAndNonemptyPassword) {
+TEST_P(PasswordManagerTest, DoNotSaveWithEmptyNewPasswordAndNonemptyPassword) {
std::vector<FormData> observed;
FormData form_data(MakeSimpleFormData());
ASSERT_FALSE(form_data.fields[1].value.empty());
@@ -1639,7 +1661,7 @@ TEST_F(PasswordManagerTest, DoNotSaveWithEmptyNewPasswordAndNonemptyPassword) {
observed.push_back(form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillOnce(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillOnce(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1660,7 +1682,7 @@ TEST_F(PasswordManagerTest, DoNotSaveWithEmptyNewPasswordAndNonemptyPassword) {
form_manager_to_save->GetPendingCredentials().password_value);
}
-TEST_F(PasswordManagerTest, FormSubmitWithOnlyPasswordField) {
+TEST_P(PasswordManagerTest, FormSubmitWithOnlyPasswordField) {
// Test to verify that on submitting the HTML password form without having
// username input filed shows password save promt and saves the password to
// store.
@@ -1673,11 +1695,11 @@ TEST_F(PasswordManagerTest, FormSubmitWithOnlyPasswordField) {
// TODO(https://crbug.com/949519): replace WillRepeatedly with WillOnce when
// the old parser is gone.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
OnPasswordFormSubmitted(form.form_data);
@@ -1709,7 +1731,7 @@ TEST_F(PasswordManagerTest, FormSubmitWithOnlyPasswordField) {
// rendered by different processes, two unrelated forms can end up with the same
// ID. The test checks that nevertheless each of them gets assigned its own
// PasswordFormManager and filled as expected.
-TEST_F(PasswordManagerTest, FillPasswordOnManyFrames_SameId) {
+TEST_P(PasswordManagerTest, FillPasswordOnManyFrames_SameId) {
// Setting task runner is required since PasswordFormManager uses
// PostDelayTask for making filling.
PasswordFormManager::set_wait_for_server_predictions_for_filling(true);
@@ -1749,7 +1771,7 @@ TEST_F(PasswordManagerTest, FillPasswordOnManyFrames_SameId) {
// Observe the form in the first frame.
EXPECT_CALL(*store_,
GetLogins(PasswordStore::FormDigest(first_form.form_data), _))
- .WillOnce(WithArg<1>(InvokeConsumer(first_form)));
+ .WillOnce(WithArg<1>(InvokeConsumer(store_.get(), first_form)));
EXPECT_CALL(driver_, FillPasswordForm(_));
manager()->OnPasswordFormsParsed(&driver_, {first_form.form_data});
@@ -1757,22 +1779,22 @@ TEST_F(PasswordManagerTest, FillPasswordOnManyFrames_SameId) {
MockPasswordManagerDriver driver_b;
EXPECT_CALL(*store_,
GetLogins(PasswordStore::FormDigest(second_form.form_data), _))
- .WillOnce(WithArg<1>(InvokeConsumer(second_form)));
+ .WillOnce(WithArg<1>(InvokeConsumer(store_.get(), second_form)));
EXPECT_CALL(driver_b, FillPasswordForm(_));
manager()->OnPasswordFormsParsed(&driver_b, {second_form.form_data});
task_runner_->FastForwardUntilNoTasksRemain();
}
-TEST_F(PasswordManagerTest, SameDocumentNavigation) {
+TEST_P(PasswordManagerTest, SameDocumentNavigation) {
// Test that observing a newly submitted form shows the save password bar on
// call in page navigation.
std::vector<FormData> observed;
PasswordForm form(MakeSimpleForm());
observed.push_back(form.form_data);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
@@ -1788,7 +1810,7 @@ TEST_F(PasswordManagerTest, SameDocumentNavigation) {
form_manager_to_save->Save();
}
-TEST_F(PasswordManagerTest, SameDocumentBlacklistedSite) {
+TEST_P(PasswordManagerTest, SameDocumentBlacklistedSite) {
// Test that observing a newly submitted form on blacklisted site does notify
// the embedder on call in page navigation.
std::vector<FormData> observed;
@@ -1801,8 +1823,9 @@ TEST_F(PasswordManagerTest, SameDocumentBlacklistedSite) {
// TODO(https://crbug.com/949519): replace WillRepeatedly with WillOnce when
// the old parser is gone.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(blacklisted_form)));
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ .WillRepeatedly(
+ WithArg<1>(InvokeConsumer(store_.get(), blacklisted_form)));
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1816,7 +1839,7 @@ TEST_F(PasswordManagerTest, SameDocumentBlacklistedSite) {
EXPECT_TRUE(form_manager_to_save->IsBlacklisted());
}
-TEST_F(PasswordManagerTest, FormSubmittedUnchangedNotifiesClient) {
+TEST_P(PasswordManagerTest, FormSubmittedUnchangedNotifiesClient) {
// This tests verifies that if the observed forms and provisionally saved
// forms are the same, then successful submission notifies the client.
std::vector<FormData> observed;
@@ -1826,11 +1849,11 @@ TEST_F(PasswordManagerTest, FormSubmittedUnchangedNotifiesClient) {
// TODO(https://crbug.com/949519): replace WillRepeatedly with WillOnce when
// the old parser is gone.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
OnPasswordFormSubmitted(form.form_data);
@@ -1853,7 +1876,7 @@ TEST_F(PasswordManagerTest, FormSubmittedUnchangedNotifiesClient) {
EXPECT_THAT(form, FormMatches(notified_form));
}
-TEST_F(PasswordManagerTest, SaveFormFetchedAfterSubmit) {
+TEST_P(PasswordManagerTest, SaveFormFetchedAfterSubmit) {
// Test that a password is offered for saving even if the response from the
// PasswordStore comes after submit.
std::vector<FormData> observed;
@@ -1867,7 +1890,7 @@ TEST_F(PasswordManagerTest, SaveFormFetchedAfterSubmit) {
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
OnPasswordFormSubmitted(form.form_data);
@@ -1875,8 +1898,8 @@ TEST_F(PasswordManagerTest, SaveFormFetchedAfterSubmit) {
// Emulate fetching password form from PasswordStore after submission but
// before post-navigation load.
ASSERT_TRUE(store_consumer);
- store_consumer->OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<PasswordForm>>());
+ store_consumer->OnGetPasswordStoreResultsFrom(
+ store_, std::vector<std::unique_ptr<PasswordForm>>());
std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
@@ -1893,12 +1916,12 @@ TEST_F(PasswordManagerTest, SaveFormFetchedAfterSubmit) {
form_manager_to_save->Save();
}
-TEST_F(PasswordManagerTest, PasswordGeneration_FailedSubmission) {
+TEST_P(PasswordManagerTest, PasswordGeneration_FailedSubmission) {
std::vector<FormData> observed;
FormData form_data(MakeFormDataWithOnlyNewPasswordField());
observed.push_back(form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1911,7 +1934,7 @@ TEST_F(PasswordManagerTest, PasswordGeneration_FailedSubmission) {
// Do not save generated password when the password form reappears.
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
EXPECT_CALL(*store_, AddLogin(_)).Times(0);
- EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()).Times(0);
+ EXPECT_CALL(client_, AutomaticPasswordSave).Times(0);
// Simulate submission failing, with the same form being visible after
// navigation.
@@ -1922,12 +1945,12 @@ TEST_F(PasswordManagerTest, PasswordGeneration_FailedSubmission) {
// If the user edits the generated password, but does not remove it completely,
// it should stay treated as a generated password.
-TEST_F(PasswordManagerTest, PasswordGenerationPasswordEdited_FailedSubmission) {
+TEST_P(PasswordManagerTest, PasswordGenerationPasswordEdited_FailedSubmission) {
std::vector<FormData> observed;
FormData form_data(MakeFormDataWithOnlyNewPasswordField());
observed.push_back(form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1945,7 +1968,7 @@ TEST_F(PasswordManagerTest, PasswordGenerationPasswordEdited_FailedSubmission) {
// Do not save generated password when the password form reappears.
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
EXPECT_CALL(*store_, AddLogin(_)).Times(0);
- EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()).Times(0);
+ EXPECT_CALL(client_, AutomaticPasswordSave).Times(0);
// Simulate submission failing, with the same form being visible after
// navigation.
@@ -1956,13 +1979,13 @@ TEST_F(PasswordManagerTest, PasswordGenerationPasswordEdited_FailedSubmission) {
// Generated password are saved even if it looks like the submit failed (the
// form reappeared). Verify that passwords which are no longer marked as
// generated will not be automatically saved.
-TEST_F(PasswordManagerTest,
+TEST_P(PasswordManagerTest,
PasswordGenerationNoLongerGeneratedPasswordNotForceSaved_FailedSubmit) {
std::vector<FormData> observed;
FormData form_data(MakeFormDataWithOnlyNewPasswordField());
observed.push_back(form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1981,7 +2004,7 @@ TEST_F(PasswordManagerTest,
// No infobar or prompt is shown if submission fails.
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
- EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()).Times(0);
+ EXPECT_CALL(client_, AutomaticPasswordSave).Times(0);
// Simulate submission failing, with the same form being visible after
// navigation.
@@ -1991,13 +2014,13 @@ TEST_F(PasswordManagerTest,
// Verify that passwords which are no longer generated trigger the confirmation
// dialog when submitted.
-TEST_F(PasswordManagerTest,
+TEST_P(PasswordManagerTest,
PasswordGenerationNoLongerGeneratedPasswordNotForceSaved) {
std::vector<FormData> observed;
FormData form_data(MakeFormDataWithOnlyNewPasswordField());
observed.push_back(form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -2018,7 +2041,7 @@ TEST_F(PasswordManagerTest,
std::unique_ptr<PasswordFormManagerForUI> form_to_save;
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save)));
- EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()).Times(0);
+ EXPECT_CALL(client_, AutomaticPasswordSave).Times(0);
// Simulate a successful submission.
observed.clear();
@@ -2026,12 +2049,12 @@ TEST_F(PasswordManagerTest,
manager()->OnPasswordFormsRendered(&driver_, observed, true);
}
-TEST_F(PasswordManagerTest, PasswordGenerationUsernameChanged) {
+TEST_P(PasswordManagerTest, PasswordGenerationUsernameChanged) {
std::vector<FormData> observed;
FormData form_data(MakeFormDataWithOnlyNewPasswordField());
observed.push_back(form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -2050,7 +2073,7 @@ TEST_F(PasswordManagerTest, PasswordGenerationUsernameChanged) {
PasswordForm form_to_save;
EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, _))
.WillOnce(SaveArg<0>(&form_to_save));
- EXPECT_CALL(client_, AutomaticPasswordSaveIndicator());
+ EXPECT_CALL(client_, AutomaticPasswordSave);
observed.clear();
manager()->OnPasswordFormsParsed(&driver_, observed);
@@ -2059,14 +2082,14 @@ TEST_F(PasswordManagerTest, PasswordGenerationUsernameChanged) {
EXPECT_EQ(form_data.fields[1].value, form_to_save.password_value);
}
-TEST_F(PasswordManagerTest, PasswordGenerationPresavePassword) {
+TEST_P(PasswordManagerTest, PasswordGenerationPresavePassword) {
std::vector<FormData> observed;
PasswordForm form(MakeFormWithOnlyNewPasswordField());
observed.push_back(form.form_data);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -2099,13 +2122,13 @@ TEST_F(PasswordManagerTest, PasswordGenerationPresavePassword) {
manager()->OnPasswordNoLongerGenerated(&driver_, updated_form.form_data);
}
-TEST_F(PasswordManagerTest, PasswordGenerationPresavePassword_NoFormManager) {
+TEST_P(PasswordManagerTest, PasswordGenerationPresavePassword_NoFormManager) {
// Checks that GeneratedFormHasNoFormManager metric is sent if there is no
// corresponding PasswordFormManager for the given form. It should be uncommon
// case.
std::vector<FormData> observed;
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -2122,7 +2145,7 @@ TEST_F(PasswordManagerTest, PasswordGenerationPresavePassword_NoFormManager) {
"PasswordManager.GeneratedFormHasNoFormManager", true, 1);
}
-TEST_F(PasswordManagerTest, PasswordGenerationPresavePasswordAndLogin) {
+TEST_P(PasswordManagerTest, PasswordGenerationPresavePasswordAndLogin) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
const bool kFalseTrue[] = {false, true};
@@ -2133,13 +2156,14 @@ TEST_F(PasswordManagerTest, PasswordGenerationPresavePasswordAndLogin) {
std::vector<FormData> observed = {form.form_data};
if (found_matched_logins_in_store) {
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2);
} else {
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(
+ WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
}
- EXPECT_CALL(client_, AutomaticPasswordSaveIndicator())
+ EXPECT_CALL(client_, AutomaticPasswordSave)
.Times(found_matched_logins_in_store ? 0 : 1);
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -2184,16 +2208,17 @@ TEST_F(PasswordManagerTest, PasswordGenerationPresavePasswordAndLogin) {
}
}
-TEST_F(PasswordManagerTest, SetGenerationElementAndReasonForForm) {
+TEST_P(PasswordManagerTest, SetGenerationElementAndReasonForForm) {
PasswordForm form(MakeSimpleForm());
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins(PasswordStore::FormDigest(form), _));
manager()->OnPasswordFormsParsed(&driver_, {form.form_data});
- manager()->SetGenerationElementAndReasonForForm(&driver_, form.form_data,
- ASCIIToUTF16("psw"), false);
+ manager()->SetGenerationElementAndReasonForForm(
+ &driver_, form.form_data, form.form_data.fields[1].unique_renderer_id,
+ false);
EXPECT_CALL(*store_, AddLogin(_));
manager()->OnPresaveGeneratedPassword(&driver_, form.form_data,
form.password_value);
@@ -2204,12 +2229,12 @@ TEST_F(PasswordManagerTest, SetGenerationElementAndReasonForForm) {
EXPECT_TRUE(form_manager->HasGeneratedPassword());
}
-TEST_F(PasswordManagerTest, UpdateFormManagers) {
+TEST_P(PasswordManagerTest, UpdateFormManagers) {
// Seeing a form should result in creating PasswordFormManager and
// PasswordFormManager and querying PasswordStore. Calling
// UpdateFormManagers should result in querying the store again.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, {PasswordForm().form_data});
@@ -2217,7 +2242,7 @@ TEST_F(PasswordManagerTest, UpdateFormManagers) {
manager()->UpdateFormManagers();
}
-TEST_F(PasswordManagerTest, AutofillingOfAffiliatedCredentials) {
+TEST_P(PasswordManagerTest, AutofillingOfAffiliatedCredentials) {
PasswordForm android_form(MakeAndroidCredential());
PasswordForm observed_form(MakeSimpleForm());
std::vector<FormData> observed_forms;
@@ -2228,7 +2253,7 @@ TEST_F(PasswordManagerTest, AutofillingOfAffiliatedCredentials) {
// TODO(https://crbug.com/949519): replace WillRepeatedly with WillOnce when
// the old parser is gone.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(android_form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), android_form)));
manager()->OnPasswordFormsParsed(&driver_, observed_forms);
observed_forms.clear();
manager()->OnPasswordFormsRendered(&driver_, observed_forms, true);
@@ -2238,7 +2263,7 @@ TEST_F(PasswordManagerTest, AutofillingOfAffiliatedCredentials) {
EXPECT_FALSE(form_data.wait_for_username);
EXPECT_EQ(android_form.signon_realm, form_data.preferred_realm);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(observed_form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(observed_form.url))
.WillRepeatedly(Return(true));
PasswordForm filled_form(observed_form);
@@ -2270,7 +2295,7 @@ TEST_F(PasswordManagerTest, AutofillingOfAffiliatedCredentials) {
// If the manager fills a credential originally saved from an affiliated Android
// application, and the user overwrites the password, they should be prompted if
// they want to update. If so, the Android credential itself should be updated.
-TEST_F(PasswordManagerTest, UpdatePasswordOfAffiliatedCredential) {
+TEST_P(PasswordManagerTest, UpdatePasswordOfAffiliatedCredential) {
PasswordForm android_form(MakeAndroidCredential());
PasswordForm observed_form(MakeSimpleForm());
std::vector<FormData> observed_forms = {observed_form.form_data};
@@ -2279,11 +2304,11 @@ TEST_F(PasswordManagerTest, UpdatePasswordOfAffiliatedCredential) {
// TODO(https://crbug.com/949519): replace WillRepeatedly with WillOnce when
// the old parser is gone.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(android_form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), android_form)));
manager()->OnPasswordFormsParsed(&driver_, observed_forms);
manager()->OnPasswordFormsRendered(&driver_, observed_forms, true);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(observed_form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(observed_form.url))
.WillRepeatedly(Return(true));
PasswordForm filled_form(observed_form);
@@ -2314,7 +2339,7 @@ TEST_F(PasswordManagerTest, UpdatePasswordOfAffiliatedCredential) {
EXPECT_THAT(saved_form, FormMatches(expected_form));
}
-TEST_F(PasswordManagerTest, ClearedFieldsSuccessCriteria) {
+TEST_P(PasswordManagerTest, ClearedFieldsSuccessCriteria) {
// Test that a submission is considered to be successful on a change password
// form without username when fields valued are cleared.
PasswordForm form(MakeFormWithOnlyNewPasswordField());
@@ -2325,10 +2350,10 @@ TEST_F(PasswordManagerTest, ClearedFieldsSuccessCriteria) {
// Emulate page load.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
OnPasswordFormSubmitted(form.form_data);
@@ -2349,7 +2374,7 @@ TEST_F(PasswordManagerTest, ClearedFieldsSuccessCriteria) {
// Check that no sync password hash is saved when no username is available,
// because we it's not clear whether the submitted credentials are sync
// credentials.
-TEST_F(PasswordManagerTest, NotSavingSyncPasswordHash_NoUsername) {
+TEST_P(PasswordManagerTest, NotSavingSyncPasswordHash_NoUsername) {
// Simulate loading a simple form with no existing stored password.
std::vector<FormData> observed;
FormData form_data(MakeSimpleGAIAFormData());
@@ -2357,7 +2382,7 @@ TEST_F(PasswordManagerTest, NotSavingSyncPasswordHash_NoUsername) {
form_data.fields[0].value.clear();
observed.push_back(form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsRendered(&driver_, observed, true);
EXPECT_CALL(client_, IsSavingAndFillingEnabled(form_data.url))
@@ -2375,12 +2400,12 @@ TEST_F(PasswordManagerTest, NotSavingSyncPasswordHash_NoUsername) {
// Check that no sync password hash is saved when the submitted credentials are
// not qualified as sync credentials.
-TEST_F(PasswordManagerTest, NotSavingSyncPasswordHash_NotSyncCredentials) {
+TEST_P(PasswordManagerTest, NotSavingSyncPasswordHash_NotSyncCredentials) {
// Simulate loading a simple form with no existing stored password.
FormData form_data(MakeSimpleGAIAFormData());
std::vector<FormData> observed = {form_data};
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsRendered(&driver_, observed, true);
EXPECT_CALL(client_, IsSavingAndFillingEnabled(form_data.url))
@@ -2400,7 +2425,7 @@ TEST_F(PasswordManagerTest, NotSavingSyncPasswordHash_NotSyncCredentials) {
}
#endif
-TEST_F(PasswordManagerTest, ManualFallbackForSaving) {
+TEST_P(PasswordManagerTest, ManualFallbackForSaving) {
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
std::vector<FormData> observed;
@@ -2408,12 +2433,12 @@ TEST_F(PasswordManagerTest, ManualFallbackForSaving) {
observed.push_back(form.form_data);
PasswordForm stored_form = form;
stored_form.password_value = ASCIIToUTF16("old_password");
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
// TODO(https://crbug.com/949519): replace WillRepeatedly with WillOnce when
// the old parser is gone.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(stored_form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), stored_form)));
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2);
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -2456,7 +2481,7 @@ TEST_F(PasswordManagerTest, ManualFallbackForSaving) {
// Tests that the manual fallback for saving isn't shown if there is no response
// from the password storage. When crbug.com/741537 is fixed, change this test.
-TEST_F(PasswordManagerTest, ManualFallbackForSaving_SlowBackend) {
+TEST_P(PasswordManagerTest, ManualFallbackForSaving_SlowBackend) {
std::vector<FormData> observed;
FormData form_data(MakeSimpleFormData());
observed.push_back(form_data);
@@ -2476,24 +2501,24 @@ TEST_F(PasswordManagerTest, ManualFallbackForSaving_SlowBackend) {
// The storage responded. The fallback can be shown.
ASSERT_TRUE(store_consumer);
- store_consumer->OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<PasswordForm>>());
+ store_consumer->OnGetPasswordStoreResultsFrom(
+ store_, std::vector<std::unique_ptr<PasswordForm>>());
std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, false))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
manager()->ShowManualFallbackForSaving(&driver_, form_data);
}
-TEST_F(PasswordManagerTest, ManualFallbackForSaving_GeneratedPassword) {
+TEST_P(PasswordManagerTest, ManualFallbackForSaving_GeneratedPassword) {
std::vector<FormData> observed;
PasswordForm form(MakeSimpleForm());
observed.push_back(form.form_data);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
// TODO(https://crbug.com/949519): replace WillRepeatedly with WillOnce when
// the old parser is gone.
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -2527,10 +2552,10 @@ TEST_F(PasswordManagerTest, ManualFallbackForSaving_GeneratedPassword) {
}
// Sync password hash should be updated upon submission of change password page.
-TEST_F(PasswordManagerTest, SaveSyncPasswordHashOnChangePasswordPage) {
+TEST_P(PasswordManagerTest, SaveSyncPasswordHashOnChangePasswordPage) {
FormData form_data(MakeGAIAChangePasswordFormData());
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
std::vector<FormData> observed;
observed.push_back(form_data);
@@ -2563,10 +2588,10 @@ TEST_F(PasswordManagerTest, SaveSyncPasswordHashOnChangePasswordPage) {
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
// Non-Sync Gaia password hash should be saved upon submission of Gaia login
// page.
-TEST_F(PasswordManagerTest, SaveOtherGaiaPasswordHash) {
+TEST_P(PasswordManagerTest, SaveOtherGaiaPasswordHash) {
FormData form_data(MakeSimpleGAIAFormData());
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
std::vector<FormData> observed;
observed.push_back(form_data);
@@ -2593,10 +2618,10 @@ TEST_F(PasswordManagerTest, SaveOtherGaiaPasswordHash) {
// Non-Sync Gaia password hash should be saved upon submission of change
// password page.
-TEST_F(PasswordManagerTest, SaveOtherGaiaPasswordHashOnChangePasswordPage) {
+TEST_P(PasswordManagerTest, SaveOtherGaiaPasswordHashOnChangePasswordPage) {
FormData form_data(MakeGAIAChangePasswordFormData());
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
std::vector<FormData> observed;
observed.push_back(form_data);
@@ -2624,10 +2649,10 @@ TEST_F(PasswordManagerTest, SaveOtherGaiaPasswordHashOnChangePasswordPage) {
// Enterprise password hash should be saved upon submission of enterprise login
// page.
-TEST_F(PasswordManagerTest, SaveEnterprisePasswordHash) {
+TEST_P(PasswordManagerTest, SaveEnterprisePasswordHash) {
FormData form_data(MakeSimpleFormData());
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
std::vector<FormData> observed;
observed.push_back(form_data);
@@ -2653,12 +2678,12 @@ TEST_F(PasswordManagerTest, SaveEnterprisePasswordHash) {
#endif
// If there are no forms to parse, certificate errors should not be reported.
-TEST_F(PasswordManagerTest, CertErrorReported_NoForms) {
+TEST_P(PasswordManagerTest, CertErrorReported_NoForms) {
const std::vector<FormData> observed;
EXPECT_CALL(client_, GetMainFrameCertStatus())
.WillRepeatedly(Return(net::CERT_STATUS_AUTHORITY_INVALID));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
base::HistogramTester histogram_tester;
manager()->OnPasswordFormsParsed(&driver_, observed);
@@ -2666,7 +2691,7 @@ TEST_F(PasswordManagerTest, CertErrorReported_NoForms) {
"PasswordManager.CertificateErrorsWhileSeeingForms", 0);
}
-TEST_F(PasswordManagerTest, CertErrorReported) {
+TEST_P(PasswordManagerTest, CertErrorReported) {
constexpr struct {
net::CertStatus cert_status;
metrics_util::CertificateError expected_error;
@@ -2708,17 +2733,16 @@ TEST_F(PasswordManagerTest, CertErrorReported) {
}
}
-TEST_F(PasswordManagerTest, CreatingFormManagers) {
+TEST_P(PasswordManagerTest, CreatingFormManagers) {
FormData form_data(MakeSimpleFormData());
std::vector<FormData> observed;
observed.push_back(form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
// Check that the form manager is created.
EXPECT_EQ(1u, manager()->form_managers().size());
- EXPECT_TRUE(manager()->form_managers()[0]->DoesManage(form_data,
- client_.GetDriver()));
+ EXPECT_TRUE(manager()->form_managers()[0]->DoesManage(form_data, &driver_));
// Check that receiving the same form the second time does not lead to
// creating new form manager.
@@ -2729,7 +2753,7 @@ TEST_F(PasswordManagerTest, CreatingFormManagers) {
// Tests that processing normal HTML form submissions works properly with the
// new parsing. For details see scheme 1 in comments before
// |form_managers_| in password_manager.h.
-TEST_F(PasswordManagerTest, ProcessingNormalFormSubmission) {
+TEST_P(PasswordManagerTest, ProcessingNormalFormSubmission) {
for (bool successful_submission : {false, true}) {
SCOPED_TRACE(testing::Message("successful_submission = ")
<< successful_submission);
@@ -2739,7 +2763,7 @@ TEST_F(PasswordManagerTest, ProcessingNormalFormSubmission) {
FormData form_data(MakeSimpleFormData());
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
std::vector<FormData> observed;
observed.push_back(form_data);
@@ -2774,13 +2798,13 @@ TEST_F(PasswordManagerTest, ProcessingNormalFormSubmission) {
// Tests that processing form submissions without navigations works properly
// with the new parsing. For details see scheme 2 in comments before
// |form_managers_| in password_manager.h.
-TEST_F(PasswordManagerTest, ProcessingOtherSubmissionTypes) {
+TEST_P(PasswordManagerTest, ProcessingOtherSubmissionTypes) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
FormData form_data(MakeSimpleFormData());
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
std::vector<FormData> observed;
observed.push_back(form_data);
@@ -2800,14 +2824,14 @@ TEST_F(PasswordManagerTest, ProcessingOtherSubmissionTypes) {
EXPECT_TRUE(manager()->form_managers().empty());
}
-TEST_F(PasswordManagerTest, SubmittedGaiaFormWithoutVisiblePasswordField) {
+TEST_P(PasswordManagerTest, SubmittedGaiaFormWithoutVisiblePasswordField) {
// Tests that a submitted GAIA sign-in form which does not contain a visible
// password field is skipped.
std::vector<FormData> observed;
FormData form_data(MakeSimpleGAIAFormData());
observed.push_back(form_data);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -2823,7 +2847,7 @@ TEST_F(PasswordManagerTest, SubmittedGaiaFormWithoutVisiblePasswordField) {
form_data.submission_event);
}
-TEST_F(PasswordManagerTest, MetricForSchemeOfSuccessfulLogins) {
+TEST_P(PasswordManagerTest, MetricForSchemeOfSuccessfulLogins) {
for (bool origin_is_secure : {false, true}) {
SCOPED_TRACE(testing::Message("origin_is_secure = ") << origin_is_secure);
FormData form_data(MakeSimpleFormData());
@@ -2831,7 +2855,7 @@ TEST_F(PasswordManagerTest, MetricForSchemeOfSuccessfulLogins) {
GURL(origin_is_secure ? "https://example.com" : "http://example.com");
std::vector<FormData> observed = {form_data};
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -2852,7 +2876,7 @@ TEST_F(PasswordManagerTest, MetricForSchemeOfSuccessfulLogins) {
}
}
-TEST_F(PasswordManagerTest, ManualFallbackForSavingNewParser) {
+TEST_P(PasswordManagerTest, ManualFallbackForSavingNewParser) {
PasswordFormManager::set_wait_for_server_predictions_for_filling(false);
std::vector<FormData> observed;
@@ -2860,10 +2884,10 @@ TEST_F(PasswordManagerTest, ManualFallbackForSavingNewParser) {
observed.push_back(form.form_data);
PasswordForm stored_form = form;
stored_form.password_value = ASCIIToUTF16("old_password");
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(stored_form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), stored_form)));
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2);
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -2892,12 +2916,12 @@ TEST_F(PasswordManagerTest, ManualFallbackForSavingNewParser) {
manager()->HideManualFallbackForSaving();
}
-TEST_F(PasswordManagerTest, NoSavePromptWhenPasswordManagerDisabled) {
+TEST_P(PasswordManagerTest, NoSavePromptWhenPasswordManagerDisabled) {
FormData form_data(MakeSimpleFormData());
EXPECT_CALL(client_, IsSavingAndFillingEnabled(form_data.url))
.WillRepeatedly(Return(false));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, {form_data});
@@ -2910,12 +2934,12 @@ TEST_F(PasswordManagerTest, NoSavePromptWhenPasswordManagerDisabled) {
&driver_, submitted_form_data.submission_event);
}
-TEST_F(PasswordManagerTest, NoSavePromptForNotPasswordForm) {
+TEST_P(PasswordManagerTest, NoSavePromptForNotPasswordForm) {
FormData form_data(MakeSimpleFormData());
EXPECT_CALL(client_, IsSavingAndFillingEnabled(form_data.url))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
// Make the form to be credit card form.
form_data.fields[1].autocomplete_attribute = "cc-csc";
@@ -2932,7 +2956,7 @@ TEST_F(PasswordManagerTest, NoSavePromptForNotPasswordForm) {
// Check that when autofill predictions are received before a form is found then
// server predictions are not ignored and used for filling.
-TEST_F(PasswordManagerTest, AutofillPredictionBeforeFormParsed) {
+TEST_P(PasswordManagerTest, AutofillPredictionBeforeFormParsed) {
PasswordFormManager::set_wait_for_server_predictions_for_filling(true);
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
@@ -2950,7 +2974,7 @@ TEST_F(PasswordManagerTest, AutofillPredictionBeforeFormParsed) {
#endif
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
EXPECT_CALL(driver_, FillPasswordForm(_));
// Simulate that the form is incorrectly marked as sign-up, which means it can
@@ -2963,7 +2987,7 @@ TEST_F(PasswordManagerTest, AutofillPredictionBeforeFormParsed) {
// Check that when autofill predictions are received before a form is found then
// server predictions are not ignored and used for filling in case there are
// multiple forms on a page, including forms that have UsernameFirstFlow votes.
-TEST_F(PasswordManagerTest, AutofillPredictionBeforeMultipleFormsParsed) {
+TEST_P(PasswordManagerTest, AutofillPredictionBeforeMultipleFormsParsed) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kUsernameFirstFlow);
PasswordFormManager::set_wait_for_server_predictions_for_filling(true);
@@ -2974,7 +2998,7 @@ TEST_F(PasswordManagerTest, AutofillPredictionBeforeMultipleFormsParsed) {
PasswordForm form2(MakeSimpleForm());
EXPECT_CALL(*store_, GetLogins)
- .WillRepeatedly(WithArg<1>(InvokeConsumer(form2)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form2)));
FormStructure form_structure1(form1.form_data);
form_structure1.field(0)->set_server_type(autofill::SINGLE_USERNAME);
@@ -3008,15 +3032,15 @@ TEST_F(PasswordManagerTest, AutofillPredictionBeforeMultipleFormsParsed) {
// 2. Navigation happens.
// 3. The password disappeared after navigation.
// 4. A save prompt is shown.
-TEST_F(PasswordManagerTest, SavingAfterUserTypingAndNavigation) {
+TEST_P(PasswordManagerTest, SavingAfterUserTypingAndNavigation) {
for (bool form_may_be_submitted : {false, true}) {
SCOPED_TRACE(testing::Message()
<< "form_may_be_submitted = " << form_may_be_submitted);
PasswordForm form(MakeSimpleForm());
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, {form.form_data});
// The user is typing as a result the saving manual fallback is shown.
@@ -3048,17 +3072,17 @@ TEST_F(PasswordManagerTest, SavingAfterUserTypingAndNavigation) {
// Check that when a form is submitted and a PasswordFormManager not present,
// this ends up reported in ProvisionallySaveFailure UMA and UKM.
-TEST_F(PasswordManagerTest, ProvisionallySaveFailure) {
+TEST_P(PasswordManagerTest, ProvisionallySaveFailure) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(nullptr, {});
base::HistogramTester histogram_tester;
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
- auto metrics_recorder = std::make_unique<PasswordManagerMetricsRecorder>(
- 1234, GURL("http://example.com"), nullptr);
+ auto metrics_recorder =
+ std::make_unique<PasswordManagerMetricsRecorder>(1234, nullptr);
EXPECT_CALL(client_, GetMetricsRecorder())
.WillRepeatedly(Return(metrics_recorder.get()));
@@ -3105,7 +3129,7 @@ struct MissingFormManagerTestCase {
// Test that presence of form managers in various situations is appropriately
// reported through UKM.
-TEST_F(PasswordManagerTest, ReportMissingFormManager) {
+TEST_P(PasswordManagerTest, ReportMissingFormManager) {
const FormData form_data = MakeSimpleFormData();
FormData other_form_data = MakeSimpleFormData();
other_form_data.unique_renderer_id.value() += 1;
@@ -3180,7 +3204,7 @@ TEST_F(PasswordManagerTest, ReportMissingFormManager) {
};
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
for (const MissingFormManagerTestCase& test_case : kTestCases) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(test_case.saving ==
@@ -3191,8 +3215,8 @@ TEST_F(PasswordManagerTest, ReportMissingFormManager) {
manager()->OnPasswordFormsParsed(nullptr, test_case.parsed_forms_data);
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
- auto metrics_recorder = std::make_unique<PasswordManagerMetricsRecorder>(
- 1234, GURL("http://example.com"), nullptr);
+ auto metrics_recorder =
+ std::make_unique<PasswordManagerMetricsRecorder>(1234, nullptr);
EXPECT_CALL(client_, GetMetricsRecorder())
.WillRepeatedly(Return(metrics_recorder.get()));
@@ -3228,13 +3252,13 @@ TEST_F(PasswordManagerTest, ReportMissingFormManager) {
// Tests that despite there a form was not seen on a page load, new
// |PasswordFormManager| is created in process of saving.
-TEST_F(PasswordManagerTest, CreatePasswordFormManagerOnSaving) {
+TEST_P(PasswordManagerTest, CreatePasswordFormManagerOnSaving) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
PasswordForm form(MakeSimpleForm());
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, {form.form_data});
@@ -3263,13 +3287,13 @@ TEST_F(PasswordManagerTest, CreatePasswordFormManagerOnSaving) {
// Tests that no save prompt from form manager is shown when Credentials
// Management API function store is called.
-TEST_F(PasswordManagerTest, NoSavePromptAfterStoreCalled) {
+TEST_P(PasswordManagerTest, NoSavePromptAfterStoreCalled) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
FormData form_data(MakeSimpleFormData());
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, {form_data});
@@ -3285,7 +3309,7 @@ TEST_F(PasswordManagerTest, NoSavePromptAfterStoreCalled) {
// Check that on non-password form, saving and filling fallbacks are available
// but no automatic filling and saving are available.
-TEST_F(PasswordManagerTest, FillingAndSavingFallbacksOnNonPasswordForm) {
+TEST_P(PasswordManagerTest, FillingAndSavingFallbacksOnNonPasswordForm) {
PasswordFormManager::set_wait_for_server_predictions_for_filling(false);
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
@@ -3295,7 +3319,7 @@ TEST_F(PasswordManagerTest, FillingAndSavingFallbacksOnNonPasswordForm) {
credit_card_form.only_for_fallback = true;
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(saved_match)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), saved_match)));
PasswordFormFillData form_data;
EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&form_data));
@@ -3326,7 +3350,7 @@ TEST_F(PasswordManagerTest, FillingAndSavingFallbacksOnNonPasswordForm) {
#if !defined(OS_IOS)
// Check that on successful login the credentials are checked for leak.
-TEST_F(PasswordManagerTest, StartLeakDetection) {
+TEST_P(PasswordManagerTest, StartLeakDetection) {
auto mock_factory =
std::make_unique<testing::StrictMock<MockLeakDetectionCheckFactory>>();
MockLeakDetectionCheckFactory* weak_factory = mock_factory.get();
@@ -3335,7 +3359,7 @@ TEST_F(PasswordManagerTest, StartLeakDetection) {
const FormData form_data = MakeSimpleFormData();
std::vector<FormData> observed = {form_data};
EXPECT_CALL(*store_, GetLogins)
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -3359,7 +3383,7 @@ TEST_F(PasswordManagerTest, StartLeakDetection) {
#endif // !defined(OS_IOS)
// Check that a non-password form with SINGLE_USERNAME prediction is filled.
-TEST_F(PasswordManagerTest, FillSingleUsername) {
+TEST_P(PasswordManagerTest, FillSingleUsername) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kUsernameFirstFlow);
PasswordFormManager::set_wait_for_server_predictions_for_filling(true);
@@ -3367,9 +3391,9 @@ TEST_F(PasswordManagerTest, FillSingleUsername) {
.WillRepeatedly(Return(true));
PasswordForm saved_match(MakeSavedForm());
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(saved_match)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), saved_match)));
- // Create FormdData for a form with 1 text field.
+ // Create FormData for a form with 1 text field.
FormData form_data;
constexpr FormRendererId form_id(1001);
form_data.unique_renderer_id = form_id;
@@ -3400,7 +3424,7 @@ TEST_F(PasswordManagerTest, FillSingleUsername) {
// Checks that a password form with a clear-text account creation field results
// in marking the password field as eligible for password generation.
-TEST_F(PasswordManagerTest,
+TEST_P(PasswordManagerTest,
MarkServerPredictedClearTextPasswordFieldEligibleForGeneration) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
@@ -3411,7 +3435,7 @@ TEST_F(PasswordManagerTest,
.WillRepeatedly(Return(true));
PasswordForm saved_match(MakeSavedForm());
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(saved_match)));
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), saved_match)));
// Create FormdData for a form with 1 text field.
FormData form_data;
@@ -3445,16 +3469,16 @@ TEST_F(PasswordManagerTest,
}
// Checks that username is saved on username first flow.
-TEST_F(PasswordManagerTest, UsernameFirstFlow) {
+TEST_P(PasswordManagerTest, UsernameFirstFlow) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kUsernameFirstFlow);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
PasswordForm form(MakeSimpleFormWithOnlyPasswordField());
// Simulate the user typed a username in username form.
const base::string16 username = ASCIIToUTF16("username1");
- EXPECT_CALL(driver_, GetLastCommittedURL()).WillOnce(ReturnRef(form.origin));
+ EXPECT_CALL(driver_, GetLastCommittedURL()).WillOnce(ReturnRef(form.url));
manager()->OnUserModifiedNonPasswordField(&driver_, FieldRendererId(1001),
username /* value */);
@@ -3462,7 +3486,7 @@ TEST_F(PasswordManagerTest, UsernameFirstFlow) {
// to the page.
manager()->OnPasswordFormsParsed(&driver_, {form.form_data} /* observed */);
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
// Simulate that the user typed password and submitted the password form.
@@ -3497,11 +3521,12 @@ TEST_F(PasswordManagerTest, UsernameFirstFlow) {
#if !defined(OS_IOS)
// Checks that username is filled on username first flow based on server and
// local predictions.
-TEST_F(PasswordManagerTest, UsernameFirstFlowFillingServerAndLocalPredictions) {
+TEST_P(PasswordManagerTest, UsernameFirstFlowFillingServerAndLocalPredictions) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kUsernameFirstFlow);
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeConsumer(MakeSavedForm())));
+ .WillRepeatedly(
+ WithArg<1>(InvokeConsumer(store_.get(), MakeSavedForm())));
EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
constexpr FieldRendererId kFieldRendererId(1);
@@ -3545,10 +3570,10 @@ TEST_F(PasswordManagerTest, UsernameFirstFlowFillingServerAndLocalPredictions) {
}
#endif
-TEST_F(PasswordManagerTest, FormSubmittedOnMainFrame) {
+TEST_P(PasswordManagerTest, FormSubmittedOnMainFrame) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
FormData form_data(MakeSimpleFormData());
// Submit |form| on a main frame.
@@ -3569,10 +3594,10 @@ TEST_F(PasswordManagerTest, FormSubmittedOnMainFrame) {
true /* did stop loading */);
}
-TEST_F(PasswordManagerTest, FormSubmittedOnIFrame) {
+TEST_P(PasswordManagerTest, FormSubmittedOnIFrame) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
FormData form_data(MakeSimpleFormData());
// Submit |form| on an iframe.
@@ -3599,10 +3624,10 @@ TEST_F(PasswordManagerTest, FormSubmittedOnIFrame) {
true /* did stop loading */);
}
-TEST_F(PasswordManagerTest, FormSubmittedOnIFrameMainFrameLoaded) {
+TEST_P(PasswordManagerTest, FormSubmittedOnIFrameMainFrameLoaded) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
FormData form_data(MakeSimpleFormData());
// Simulate a form submission on an iframe.
@@ -3618,23 +3643,27 @@ TEST_F(PasswordManagerTest, FormSubmittedOnIFrameMainFrameLoaded) {
true /* did stop loading */);
}
-TEST_F(PasswordManagerTest, NoPromptAutofillAssistantManuallyCuratedScript) {
+TEST_P(PasswordManagerTest, NoPromptAutofillAssistantManuallyCuratedScript) {
manager()->SetAutofillAssistantMode(AutofillAssistantMode::kRunning);
- PasswordForm form(MakeSimpleForm());
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins)
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
- manager()->OnPasswordFormsParsed(&driver_, {form.form_data});
- manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
// Check that a save prompt is not shown.
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr).Times(0);
- manager()->DidNavigateMainFrame(true /* form_may_be_submitted */);
- manager()->OnPasswordFormsRendered(&driver_, {} /* observed */,
- true /* did stop loading */);
+ // Simulate multiple submissions.
+ for (size_t i = 0; i < 2; i++) {
+ PasswordForm form(MakeSimpleForm());
+ manager()->OnPasswordFormsParsed(&driver_, {form.form_data});
+ manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
+
+ manager()->DidNavigateMainFrame(true /* form_may_be_submitted */);
+ manager()->OnPasswordFormsRendered(&driver_, {} /* observed */,
+ true /* did stop loading */);
+ }
}
// Tests the following scenario:
@@ -3643,16 +3672,16 @@ TEST_F(PasswordManagerTest, NoPromptAutofillAssistantManuallyCuratedScript) {
// 2. The timeout for prompts disabling expires.
// 3. The timer re-enables the prompts.
// 4. A prompt is shown after a form submission.
-TEST_F(PasswordManagerTest, ResetAutofillAssistantModeAfterTimeout) {
+TEST_P(PasswordManagerTest, ResetAutofillAssistantModeAfterTimeout) {
manager()->SetDisablePromptsTimeoutToZero();
manager()->SetAutofillAssistantMode(AutofillAssistantMode::kRunning);
PasswordForm form(MakeSimpleForm());
- EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.origin))
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins)
- .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
manager()->OnPasswordFormsParsed(&driver_, {form.form_data});
manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
@@ -3667,4 +3696,6 @@ TEST_F(PasswordManagerTest, ResetAutofillAssistantModeAfterTimeout) {
true /* did stop loading */);
}
+INSTANTIATE_TEST_SUITE_P(, PasswordManagerTest, testing::Bool());
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_util.cc b/chromium/components/password_manager/core/browser/password_manager_util.cc
index 3885c44c51c..7f8ed4e5473 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_util.cc
@@ -34,6 +34,7 @@
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_service.h"
+#include "components/signin/public/base/signin_metrics.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_user_settings.h"
@@ -154,17 +155,20 @@ void UserTriggeredManualGenerationFromContextMenu(
}
// The client ensures the callback won't be run if it is destroyed, so
// base::Unretained is safe.
- password_manager_client->TriggerReauthForPrimaryAccount(base::BindOnce(
- [](password_manager::PasswordManagerClient* client,
- password_manager::PasswordManagerClient::ReauthSucceeded succeeded) {
- if (succeeded) {
- client->GeneratePassword();
- LogPasswordGenerationEvent(
- autofill::password_generation::
- PASSWORD_GENERATION_CONTEXT_MENU_PRESSED);
- }
- },
- base::Unretained(password_manager_client)));
+ password_manager_client->TriggerReauthForPrimaryAccount(
+ signin_metrics::ReauthAccessPoint::kGeneratePasswordContextMenu,
+ base::BindOnce(
+ [](password_manager::PasswordManagerClient* client,
+ password_manager::PasswordManagerClient::ReauthSucceeded
+ succeeded) {
+ if (succeeded) {
+ client->GeneratePassword();
+ LogPasswordGenerationEvent(
+ autofill::password_generation::
+ PASSWORD_GENERATION_CONTEXT_MENU_PRESSED);
+ }
+ },
+ base::Unretained(password_manager_client)));
}
// TODO(http://crbug.com/890318): Add unitests to check cleaners are correctly
@@ -204,7 +208,7 @@ base::StringPiece GetSignonRealmWithProtocolExcluded(const PasswordForm& form) {
// Find the web origin (with protocol excluded) in the signon_realm.
const size_t after_protocol =
- signon_realm_protocol_excluded.find(form.origin.host_piece());
+ signon_realm_protocol_excluded.find(form.url.host_piece());
DCHECK_NE(after_protocol, base::StringPiece::npos);
// Keep the string starting with position |after_protocol|.
@@ -323,16 +327,15 @@ autofill::PasswordForm MakeNormalizedBlacklistedForm(
result.signon_realm = std::move(digest.signon_realm);
// In case |digest| corresponds to an Android credential copy the origin as
// is, otherwise clear out the path by calling GetOrigin().
- if (password_manager::FacetURI::FromPotentiallyInvalidSpec(
- digest.origin.spec())
+ if (password_manager::FacetURI::FromPotentiallyInvalidSpec(digest.url.spec())
.IsValidAndroidFacetURI()) {
- result.origin = std::move(digest.origin);
+ result.url = std::move(digest.url);
} else {
// GetOrigin() will return an empty GURL if the origin is not valid or
// standard. DCHECK that this will not happen.
- DCHECK(digest.origin.is_valid());
- DCHECK(digest.origin.IsStandard());
- result.origin = digest.origin.GetOrigin();
+ DCHECK(digest.url.is_valid());
+ DCHECK(digest.url.IsStandard());
+ result.url = digest.url.GetOrigin();
}
return result;
}
diff --git a/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
index 764108c41ab..80af63b7227 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
@@ -20,6 +20,7 @@
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "components/password_manager/core/browser/test_password_store.h"
#include "components/password_manager/core/common/password_manager_features.h"
+#include "components/signin/public/base/signin_metrics.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -45,7 +46,8 @@ class MockPasswordManagerClient
MOCK_METHOD(void,
TriggerReauthForPrimaryAccount,
- (base::OnceCallback<void(
+ (signin_metrics::ReauthAccessPoint,
+ base::OnceCallback<void(
password_manager::PasswordManagerClient::ReauthSucceeded)>),
(override));
MOCK_METHOD(void, GeneratePassword, (), (override));
@@ -54,7 +56,7 @@ class MockPasswordManagerClient
autofill::PasswordForm GetTestAndroidCredential() {
autofill::PasswordForm form;
form.scheme = autofill::PasswordForm::Scheme::kHtml;
- form.origin = GURL(kTestAndroidRealm);
+ form.url = GURL(kTestAndroidRealm);
form.signon_realm = kTestAndroidRealm;
form.username_value = base::ASCIIToUTF16(kTestUsername);
form.password_value = base::ASCIIToUTF16(kTestPassword);
@@ -64,8 +66,8 @@ autofill::PasswordForm GetTestAndroidCredential() {
autofill::PasswordForm GetTestCredential() {
autofill::PasswordForm form;
form.scheme = autofill::PasswordForm::Scheme::kHtml;
- form.origin = GURL(kTestURL);
- form.signon_realm = form.origin.GetOrigin().spec();
+ form.url = GURL(kTestURL);
+ form.signon_realm = form.url.GetOrigin().spec();
form.username_value = base::ASCIIToUTF16(kTestUsername);
form.password_value = base::ASCIIToUTF16(kTestPassword);
return form;
@@ -74,7 +76,7 @@ autofill::PasswordForm GetTestCredential() {
autofill::PasswordForm GetTestProxyCredential() {
autofill::PasswordForm form;
form.scheme = autofill::PasswordForm::Scheme::kBasic;
- form.origin = GURL(kTestProxyOrigin);
+ form.url = GURL(kTestProxyOrigin);
form.signon_realm = kTestProxySignonRealm;
form.username_value = base::ASCIIToUTF16(kTestUsername);
form.password_value = base::ASCIIToUTF16(kTestPassword);
@@ -117,17 +119,17 @@ TEST(PasswordManagerUtil, TrimUsernameOnlyCredentials) {
TEST(PasswordManagerUtil, GetSignonRealmWithProtocolExcluded) {
autofill::PasswordForm http_form;
- http_form.origin = GURL("http://www.google.com/page-1/");
+ http_form.url = GURL("http://www.google.com/page-1/");
http_form.signon_realm = "http://www.google.com/";
EXPECT_EQ(GetSignonRealmWithProtocolExcluded(http_form), "www.google.com/");
autofill::PasswordForm https_form;
- https_form.origin = GURL("https://www.google.com/page-1/");
+ https_form.url = GURL("https://www.google.com/page-1/");
https_form.signon_realm = "https://www.google.com/";
EXPECT_EQ(GetSignonRealmWithProtocolExcluded(https_form), "www.google.com/");
autofill::PasswordForm federated_form;
- federated_form.origin = GURL("http://localhost:8000/");
+ federated_form.url = GURL("http://localhost:8000/");
federated_form.signon_realm =
"federation://localhost/accounts.federation.com";
EXPECT_EQ(GetSignonRealmWithProtocolExcluded(federated_form),
@@ -409,7 +411,7 @@ TEST(PasswordManagerUtil, MakeNormalizedBlacklistedForm_Android) {
EXPECT_TRUE(blacklisted_credential.blacklisted_by_user);
EXPECT_EQ(PasswordForm::Scheme::kHtml, blacklisted_credential.scheme);
EXPECT_EQ(kTestAndroidRealm, blacklisted_credential.signon_realm);
- EXPECT_EQ(GURL(kTestAndroidRealm), blacklisted_credential.origin);
+ EXPECT_EQ(GURL(kTestAndroidRealm), blacklisted_credential.url);
}
TEST(PasswordManagerUtil, MakeNormalizedBlacklistedForm_Html) {
@@ -419,7 +421,7 @@ TEST(PasswordManagerUtil, MakeNormalizedBlacklistedForm_Html) {
EXPECT_EQ(PasswordForm::Scheme::kHtml, blacklisted_credential.scheme);
EXPECT_EQ(GURL(kTestURL).GetOrigin().spec(),
blacklisted_credential.signon_realm);
- EXPECT_EQ(GURL(kTestURL).GetOrigin(), blacklisted_credential.origin);
+ EXPECT_EQ(GURL(kTestURL).GetOrigin(), blacklisted_credential.url);
}
TEST(PasswordManagerUtil, MakeNormalizedBlacklistedForm_Proxy) {
@@ -428,7 +430,7 @@ TEST(PasswordManagerUtil, MakeNormalizedBlacklistedForm_Proxy) {
EXPECT_TRUE(blacklisted_credential.blacklisted_by_user);
EXPECT_EQ(PasswordForm::Scheme::kBasic, blacklisted_credential.scheme);
EXPECT_EQ(kTestProxySignonRealm, blacklisted_credential.signon_realm);
- EXPECT_EQ(GURL(kTestProxyOrigin), blacklisted_credential.origin);
+ EXPECT_EQ(GURL(kTestProxyOrigin), blacklisted_credential.url);
}
TEST(PasswordManagerUtil, ManualGenerationShouldNotReauthIfNotNeeded) {
@@ -450,9 +452,13 @@ TEST(PasswordManagerUtil,
ShouldShowAccountStorageOptIn)
.WillByDefault(Return(true));
- EXPECT_CALL(mock_client, TriggerReauthForPrimaryAccount)
+ EXPECT_CALL(
+ mock_client,
+ TriggerReauthForPrimaryAccount(
+ signin_metrics::ReauthAccessPoint::kGeneratePasswordContextMenu, _))
.WillOnce(
- [](base::OnceCallback<void(
+ [](signin_metrics::ReauthAccessPoint,
+ base::OnceCallback<void(
password_manager::PasswordManagerClient::ReauthSucceeded)>
callback) {
std::move(callback).Run(
@@ -470,9 +476,13 @@ TEST(PasswordManagerUtil,
ShouldShowAccountStorageOptIn)
.WillByDefault(Return(true));
- EXPECT_CALL(mock_client, TriggerReauthForPrimaryAccount)
+ EXPECT_CALL(
+ mock_client,
+ TriggerReauthForPrimaryAccount(
+ signin_metrics::ReauthAccessPoint::kGeneratePasswordContextMenu, _))
.WillOnce(
- [](base::OnceCallback<void(
+ [](signin_metrics::ReauthAccessPoint,
+ base::OnceCallback<void(
password_manager::PasswordManagerClient::ReauthSucceeded)>
callback) {
std::move(callback).Run(
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc
index 3a83ff44a80..bb4dcd18ae9 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc
@@ -29,7 +29,7 @@ PasswordReuseDetectionManager::PasswordReuseDetectionManager(
DCHECK(client_);
}
-PasswordReuseDetectionManager::~PasswordReuseDetectionManager() {}
+PasswordReuseDetectionManager::~PasswordReuseDetectionManager() = default;
void PasswordReuseDetectionManager::DidNavigateMainFrame(
const GURL& main_frame_url) {
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detector_consumer.cc b/chromium/components/password_manager/core/browser/password_reuse_detector_consumer.cc
index 9f64c86fdb1..8e1b392fc9b 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detector_consumer.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detector_consumer.cc
@@ -6,8 +6,8 @@
namespace password_manager {
-PasswordReuseDetectorConsumer::PasswordReuseDetectorConsumer() {}
+PasswordReuseDetectorConsumer::PasswordReuseDetectorConsumer() = default;
-PasswordReuseDetectorConsumer::~PasswordReuseDetectorConsumer() {}
+PasswordReuseDetectorConsumer::~PasswordReuseDetectorConsumer() = default;
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_save_manager.h b/chromium/components/password_manager/core/browser/password_save_manager.h
index a0c7b8a876b..d6d7ad5cf81 100644
--- a/chromium/components/password_manager/core/browser/password_save_manager.h
+++ b/chromium/components/password_manager/core/browser/password_save_manager.h
@@ -16,6 +16,10 @@ class GaiaIdHash;
namespace password_manager {
+namespace metrics_util {
+enum class MoveToAccountStoreTrigger;
+}
+
class PasswordManagerClient;
class FormFetcher;
class VotesUploader;
@@ -81,7 +85,10 @@ class PasswordSaveManager {
// Moves the pending credentials together with any other PSL matched ones from
// the profile store to the account store.
- virtual void MoveCredentialsToAccountStore() = 0;
+ // |trigger| represents the user action that triggered the flow and is used
+ // for recording metrics.
+ virtual void MoveCredentialsToAccountStore(
+ metrics_util::MoveToAccountStoreTrigger trigger) = 0;
// Adds the |gaia_id_hash| to the |moving_blocked_for_list| of the
// PasswordForm returned by GetPendingCredentials() and stores it in the
diff --git a/chromium/components/password_manager/core/browser/password_save_manager_impl.cc b/chromium/components/password_manager/core/browser/password_save_manager_impl.cc
index 86f8527ec66..962b3237177 100644
--- a/chromium/components/password_manager/core/browser/password_save_manager_impl.cc
+++ b/chromium/components/password_manager/core/browser/password_save_manager_impl.cc
@@ -171,7 +171,8 @@ void PasswordSaveManagerImpl::CreatePendingCredentials(
submitted_form, generated_password, is_http_auth, is_credential_api_save,
similar_saved_form);
- SetVotesAndRecordMetricsForPendingCredentials(parsed_submitted_form);
+ if (votes_uploader_)
+ SetVotesAndRecordMetricsForPendingCredentials(parsed_submitted_form);
}
void PasswordSaveManagerImpl::SetVotesAndRecordMetricsForPendingCredentials(
@@ -314,7 +315,8 @@ void PasswordSaveManagerImpl::PasswordNoLongerGenerated() {
PasswordFormMetricsRecorder::GeneratedPasswordStatus::kPasswordDeleted);
}
-void PasswordSaveManagerImpl::MoveCredentialsToAccountStore() {
+void PasswordSaveManagerImpl::MoveCredentialsToAccountStore(
+ metrics_util::MoveToAccountStoreTrigger) {
// Moving credentials is only supported in MultiStorePasswordSaveManager.
NOTREACHED();
}
@@ -403,7 +405,7 @@ PasswordForm PasswordSaveManagerImpl::BuildPendingCredentials(
password_manager_util::UpdateMetadataForUsage(&pending_credentials);
// Update |pending_credentials| in order to be able correctly save it.
- pending_credentials.origin = parsed_submitted_form.origin;
+ pending_credentials.url = parsed_submitted_form.url;
pending_credentials.signon_realm = parsed_submitted_form.signon_realm;
pending_credentials.action = parsed_submitted_form.action;
break;
diff --git a/chromium/components/password_manager/core/browser/password_save_manager_impl.h b/chromium/components/password_manager/core/browser/password_save_manager_impl.h
index dc9018ad8b0..c5195f12663 100644
--- a/chromium/components/password_manager/core/browser/password_save_manager_impl.h
+++ b/chromium/components/password_manager/core/browser/password_save_manager_impl.h
@@ -33,6 +33,7 @@ class PasswordSaveManagerImpl : public PasswordSaveManager {
const base::string16& GetGeneratedPassword() const override;
FormSaver* GetFormSaver() const override;
+ // |metrics_recorder| and |votes_uploader| can both be nullptr.
void Init(PasswordManagerClient* client,
const FormFetcher* form_fetcher,
scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder,
@@ -71,7 +72,8 @@ class PasswordSaveManagerImpl : public PasswordSaveManager {
// Signals that the user cancels password generation.
void PasswordNoLongerGenerated() override;
- void MoveCredentialsToAccountStore() override;
+ void MoveCredentialsToAccountStore(
+ metrics_util::MoveToAccountStoreTrigger) override;
void BlockMovingToAccountStoreFor(
const autofill::GaiaIdHash& gaia_id_hash) override;
@@ -159,9 +161,10 @@ class PasswordSaveManagerImpl : public PasswordSaveManager {
// Handles the user flows related to the generation.
std::unique_ptr<PasswordGenerationManager> generation_manager_;
- // Takes care of recording metrics and events for |*this|.
+ // Takes care of recording metrics and events for |*this|. Can be nullptr.
scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder_;
+ // Can be nullptr.
VotesUploader* votes_uploader_;
};
diff --git a/chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc b/chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
index c8e29774877..45e4c5652dd 100644
--- a/chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
@@ -58,7 +58,7 @@ MATCHER_P(FormHasUniqueKey, key, "") {
void CheckPendingCredentials(const PasswordForm& expected,
const PasswordForm& actual) {
EXPECT_EQ(expected.signon_realm, actual.signon_realm);
- EXPECT_EQ(expected.origin, actual.origin);
+ EXPECT_EQ(expected.url, actual.url);
EXPECT_EQ(expected.action, actual.action);
EXPECT_EQ(expected.username_value, actual.username_value);
EXPECT_EQ(expected.password_value, actual.password_value);
@@ -116,55 +116,54 @@ void CheckPasswordGenerationUKM(const ukm::TestAutoSetUkmRecorder& recorder,
class MockFormSaver : public StubFormSaver {
public:
- MockFormSaver() = default;
-
- ~MockFormSaver() override = default;
-
// FormSaver:
- MOCK_METHOD1(PermanentlyBlacklist, PasswordForm(PasswordStore::FormDigest));
- MOCK_METHOD1(Unblacklist, void(const PasswordStore::FormDigest&));
- MOCK_METHOD3(Save,
- void(PasswordForm pending,
- const std::vector<const PasswordForm*>& matches,
- const base::string16& old_password));
- MOCK_METHOD3(Update,
- void(PasswordForm pending,
- const std::vector<const PasswordForm*>& matches,
- const base::string16& old_password));
- MOCK_METHOD4(UpdateReplace,
- void(PasswordForm pending,
- const std::vector<const PasswordForm*>& matches,
- const base::string16& old_password,
- const PasswordForm& old_unique_key));
- MOCK_METHOD1(Remove, void(const PasswordForm&));
+ MOCK_METHOD(PasswordForm,
+ PermanentlyBlacklist,
+ (PasswordStore::FormDigest),
+ (override));
+ MOCK_METHOD(void,
+ Unblacklist,
+ (const PasswordStore::FormDigest&),
+ (override));
+ MOCK_METHOD(void,
+ Save,
+ (PasswordForm pending,
+ const std::vector<const PasswordForm*>& matches,
+ const base::string16& old_password),
+ (override));
+ MOCK_METHOD(void,
+ Update,
+ (PasswordForm pending,
+ const std::vector<const PasswordForm*>& matches,
+ const base::string16& old_password),
+ (override));
+ MOCK_METHOD(void,
+ UpdateReplace,
+ (PasswordForm pending,
+ const std::vector<const PasswordForm*>& matches,
+ const base::string16& old_password,
+ const PasswordForm& old_unique_key),
+ (override));
+ MOCK_METHOD(void, Remove, (const PasswordForm&), (override));
std::unique_ptr<FormSaver> Clone() override {
return std::make_unique<MockFormSaver>();
}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockFormSaver);
};
class MockPasswordManagerClient : public StubPasswordManagerClient {
public:
- MockPasswordManagerClient() = default;
- ~MockPasswordManagerClient() override = default;
-
- MOCK_CONST_METHOD0(IsIncognito, bool());
-
- MOCK_METHOD0(GetAutofillDownloadManager,
- autofill::AutofillDownloadManager*());
-
- MOCK_METHOD0(UpdateFormManagers, void());
-
- MOCK_METHOD2(AutofillHttpAuth,
- void(const PasswordForm&, const PasswordFormManagerForUI*));
-
- MOCK_CONST_METHOD0(IsMainFrameSecure, bool());
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerClient);
+ MOCK_METHOD(bool, IsIncognito, (), (const, override));
+ MOCK_METHOD(autofill::AutofillDownloadManager*,
+ GetAutofillDownloadManager,
+ (),
+ (override));
+ MOCK_METHOD(void, UpdateFormManagers, (), (override));
+ MOCK_METHOD(void,
+ AutofillHttpAuth,
+ (const PasswordForm&, const PasswordFormManagerForUI*),
+ (override));
+ MOCK_METHOD(bool, IsCommittedMainFrameSecure, (), (const, override));
};
class MockAutofillDownloadManager : public autofill::AutofillDownloadManager {
@@ -172,19 +171,21 @@ class MockAutofillDownloadManager : public autofill::AutofillDownloadManager {
MockAutofillDownloadManager()
: AutofillDownloadManager(nullptr, &fake_observer) {}
- MOCK_METHOD6(StartUploadRequest,
- bool(const FormStructure&,
- bool,
- const autofill::ServerFieldTypeSet&,
- const std::string&,
- bool,
- PrefService*));
+ MOCK_METHOD(bool,
+ StartUploadRequest,
+ (const FormStructure&,
+ bool,
+ const autofill::ServerFieldTypeSet&,
+ const std::string&,
+ bool,
+ PrefService*),
+ (override));
private:
class StubObserver : public AutofillDownloadManager::Observer {
void OnLoadedServerPredictions(
std::string response,
- const std::vector<std::string>& form_signatures) override {}
+ const autofill::FormAndFieldSignatures& form_signatures) override {}
};
StubObserver fake_observer;
@@ -261,7 +262,7 @@ class PasswordSaveManagerImplTest : public testing::Test,
submitted_form_.fields[kUsernameFieldIndex].value = ASCIIToUTF16("user1");
submitted_form_.fields[kPasswordFieldIndex].value = ASCIIToUTF16("secret1");
- saved_match_.origin = origin;
+ saved_match_.url = origin;
saved_match_.action = action;
saved_match_.signon_realm = "https://accounts.google.com/";
saved_match_.username_value = ASCIIToUTF16("test@gmail.com");
@@ -273,7 +274,7 @@ class PasswordSaveManagerImplTest : public testing::Test,
saved_match_.in_store = PasswordForm::Store::kProfileStore;
psl_saved_match_ = saved_match_;
- psl_saved_match_.origin = psl_origin;
+ psl_saved_match_.url = psl_origin;
psl_saved_match_.action = psl_action;
psl_saved_match_.signon_realm = "https://myaccounts.google.com/";
psl_saved_match_.is_public_suffix_match = true;
@@ -296,7 +297,8 @@ class PasswordSaveManagerImplTest : public testing::Test,
fetcher_->Fetch();
metrics_recorder_ = base::MakeRefCounted<PasswordFormMetricsRecorder>(
- client_.IsMainFrameSecure(), client_.GetUkmSourceId());
+ client_.IsCommittedMainFrameSecure(), client_.GetUkmSourceId(),
+ /*pref_service=*/nullptr);
auto mock_form_saver = std::make_unique<NiceMock<MockFormSaver>>();
mock_form_saver_ = mock_form_saver.get();
@@ -449,7 +451,7 @@ TEST_P(PasswordSaveManagerImplTest, CreatePendingCredentialsAlreadySaved) {
TEST_P(PasswordSaveManagerImplTest, CreatePendingCredentialsPSLMatchSaved) {
PasswordForm expected = saved_match_;
- saved_match_.origin = GURL("https://m.accounts.google.com/auth");
+ saved_match_.url = GURL("https://m.accounts.google.com/auth");
saved_match_.signon_realm = "https://m.accounts.google.com/";
saved_match_.is_public_suffix_match = true;
@@ -599,7 +601,7 @@ TEST_P(PasswordSaveManagerImplTest, SaveNewCredentials) {
password_save_manager_impl()->Save(observed_form_, Parse(submitted_form));
std::string expected_signon_realm = submitted_form.url.GetOrigin().spec();
- EXPECT_EQ(submitted_form.url, saved_form.origin);
+ EXPECT_EQ(submitted_form.url, saved_form.url);
EXPECT_EQ(expected_signon_realm, saved_form.signon_realm);
EXPECT_EQ(new_username, saved_form.username_value);
EXPECT_EQ(new_password, saved_form.password_value);
@@ -649,7 +651,7 @@ TEST_P(PasswordSaveManagerImplTest, SavePSLToAlreadySaved) {
password_save_manager_impl()->Save(observed_form_, Parse(submitted_form));
- EXPECT_EQ(submitted_form.url, saved_form.origin);
+ EXPECT_EQ(submitted_form.url, saved_form.url);
EXPECT_EQ(GetSignonRealm(submitted_form.url), saved_form.signon_realm);
EXPECT_EQ(psl_saved_match_.username_value, saved_form.username_value);
EXPECT_EQ(psl_saved_match_.password_value, saved_form.password_value);
diff --git a/chromium/components/password_manager/core/browser/password_store.cc b/chromium/components/password_manager/core/browser/password_store.cc
index 0c6c3a8f3dd..93d9670c59d 100644
--- a/chromium/components/password_manager/core/browser/password_store.cc
+++ b/chromium/components/password_manager/core/browser/password_store.cc
@@ -14,6 +14,7 @@
#include "base/debug/dump_without_crashing.h"
#include "base/location.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
@@ -52,6 +53,8 @@ namespace password_manager {
namespace {
+const base::TimeDelta kSyncTaskTimeout = base::TimeDelta::FromSeconds(30);
+
// Utility function to simplify removing logins prior a given |cutoff| data.
// Runs |callback| with the result.
//
@@ -90,7 +93,7 @@ PasswordStore::CheckReuseRequest::CheckReuseRequest(
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("passwords", "CheckReuseRequest", this);
}
-PasswordStore::CheckReuseRequest::~CheckReuseRequest() {}
+PasswordStore::CheckReuseRequest::~CheckReuseRequest() = default;
void PasswordStore::CheckReuseRequest::OnReuseFound(
size_t password_length,
@@ -108,18 +111,16 @@ void PasswordStore::CheckReuseRequest::OnReuseFound(
PasswordStore::FormDigest::FormDigest(autofill::PasswordForm::Scheme new_scheme,
const std::string& new_signon_realm,
- const GURL& new_origin)
- : scheme(new_scheme), signon_realm(new_signon_realm), origin(new_origin) {}
+ const GURL& new_url)
+ : scheme(new_scheme), signon_realm(new_signon_realm), url(new_url) {}
PasswordStore::FormDigest::FormDigest(const PasswordForm& form)
- : scheme(form.scheme),
- signon_realm(form.signon_realm),
- origin(form.origin) {}
+ : scheme(form.scheme), signon_realm(form.signon_realm), url(form.url) {}
PasswordStore::FormDigest::FormDigest(const autofill::FormData& form)
: scheme(PasswordForm::Scheme::kHtml),
signon_realm(form.url.GetOrigin().spec()),
- origin(form.url) {}
+ url(form.url) {}
PasswordStore::FormDigest::FormDigest(const FormDigest& other) = default;
@@ -133,13 +134,11 @@ PasswordStore::FormDigest& PasswordStore::FormDigest::operator=(
bool PasswordStore::FormDigest::operator==(const FormDigest& other) const {
return scheme == other.scheme && signon_realm == other.signon_realm &&
- origin == other.origin;
+ url == other.url;
}
PasswordStore::PasswordStore()
- : observers_(new base::ObserverListThreadSafe<Observer>()),
- shutdown_called_(false),
- init_status_(InitStatus::kUnknown) {}
+ : observers_(new base::ObserverListThreadSafe<Observer>()) {}
bool PasswordStore::Init(PrefService* prefs,
base::RepeatingClosure sync_enabled_or_disabled_cb) {
@@ -196,11 +195,13 @@ void PasswordStore::RemoveLoginsByURLAndTime(
const base::RepeatingCallback<bool(const GURL&)>& url_filter,
base::Time delete_begin,
base::Time delete_end,
- base::OnceClosure completion) {
+ base::OnceClosure completion,
+ base::OnceCallback<void(bool)> sync_completion) {
DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
ScheduleTask(base::BindOnce(&PasswordStore::RemoveLoginsByURLAndTimeInternal,
this, url_filter, delete_begin, delete_end,
- std::move(completion)));
+ std::move(completion),
+ std::move(sync_completion)));
}
void PasswordStore::RemoveLoginsCreatedBetween(base::Time delete_begin,
@@ -667,7 +668,7 @@ PasswordStore::CreateBackgroundTaskRunner() const {
bool PasswordStore::InitOnBackgroundSequence() {
DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- sync_bridge_.reset(new PasswordSyncBridge(
+ sync_bridge_ = base::WrapUnique(new PasswordSyncBridge(
std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
syncer::PASSWORDS, base::DoNothing()),
/*password_store_sync=*/this, sync_enabled_or_disabled_cb_));
@@ -677,8 +678,8 @@ bool PasswordStore::InitOnBackgroundSequence() {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::BindOnce(&PasswordStoreConsumer::OnGetPasswordStoreResults,
- reuse_detector_->GetWeakPtr(),
+ base::BindOnce(&PasswordStoreConsumer::OnGetPasswordStoreResultsFrom,
+ reuse_detector_->GetWeakPtr(), base::WrapRefCounted(this),
GetAutofillableLoginsImpl()));
#endif
return true;
@@ -746,6 +747,25 @@ void PasswordStore::NotifyLoginsChanged(
}
}
+void PasswordStore::NotifyDeletionsHaveSynced(bool success) {
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+ // Either all deletions have been committed to the Sync server, or Sync is
+ // telling us that it won't commit them (because Sync was turned off
+ // permanently). In either case, run the corresponding callbacks now (on the
+ // main task runner).
+ DCHECK(!success || !GetMetadataStore()->HasUnsyncedDeletions());
+ if (!deletions_have_synced_callbacks_.empty()) {
+ base::UmaHistogramBoolean(
+ "PasswordManager.PasswordStoreDeletionsHaveSynced", success);
+ }
+ for (auto& callback : deletions_have_synced_callbacks_) {
+ main_task_runner_->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), success));
+ }
+ deletions_have_synced_timeout_.Cancel();
+ deletions_have_synced_callbacks_.clear();
+}
+
void PasswordStore::InvokeAndNotifyAboutCompromisedPasswordsChange(
base::OnceCallback<bool()> callback) {
DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
@@ -858,8 +878,8 @@ void PasswordStore::PostLoginsTaskAndReplyToConsumerWithResult(
LoginsTask task) {
consumer->cancelable_task_tracker()->PostTaskAndReplyWithResult(
background_task_runner_.get(), FROM_HERE, std::move(task),
- base::BindOnce(&PasswordStoreConsumer::OnGetPasswordStoreResults,
- consumer->GetWeakPtr()));
+ base::BindOnce(&PasswordStoreConsumer::OnGetPasswordStoreResultsFrom,
+ consumer->GetWeakPtr(), base::WrapRefCounted(this)));
}
void PasswordStore::PostLoginsTaskAndReplyToConsumerWithProcessedResult(
@@ -869,8 +889,8 @@ void PasswordStore::PostLoginsTaskAndReplyToConsumerWithProcessedResult(
LoginsResultProcessor processor) {
auto call_consumer = base::BindOnce(
CloseTraceAndCallBack, trace_name, consumer,
- base::BindOnce(&PasswordStoreConsumer::OnGetPasswordStoreResults,
- consumer->GetWeakPtr()));
+ base::BindOnce(&PasswordStoreConsumer::OnGetPasswordStoreResultsFrom,
+ consumer->GetWeakPtr(), base::WrapRefCounted(this)));
consumer->cancelable_task_tracker()->PostTaskAndReplyWithResult(
background_task_runner_.get(), FROM_HERE, std::move(task),
base::BindOnce(std::move(processor), std::move(call_consumer)));
@@ -955,7 +975,8 @@ void PasswordStore::RemoveLoginsByURLAndTimeInternal(
const base::RepeatingCallback<bool(const GURL&)>& url_filter,
base::Time delete_begin,
base::Time delete_end,
- base::OnceClosure completion) {
+ base::OnceClosure completion,
+ base::OnceCallback<void(bool)> sync_completion) {
DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
TRACE_EVENT0("passwords", "PasswordStore::RemoveLoginsByURLAndTimeInternal");
BeginTransaction();
@@ -967,8 +988,23 @@ void PasswordStore::RemoveLoginsByURLAndTimeInternal(
// sync codebase needs to update metadata atomically together with the login
// data.
CommitTransaction();
+
if (completion)
main_task_runner_->PostTask(FROM_HERE, std::move(completion));
+
+ if (sync_completion) {
+ deletions_have_synced_callbacks_.push_back(std::move(sync_completion));
+ // Start a timeout for sync, or restart it if it was already running.
+ deletions_have_synced_timeout_.Reset(base::BindRepeating(
+ &PasswordStore::NotifyDeletionsHaveSynced, this, /*success=*/false));
+ background_task_runner_->PostDelayedTask(
+ FROM_HERE, deletions_have_synced_timeout_.callback(), kSyncTaskTimeout);
+
+ // Do an immediate check for the case where there are already no unsynced
+ // deletions.
+ if (!GetMetadataStore()->HasUnsyncedDeletions())
+ NotifyDeletionsHaveSynced(/*success=*/true);
+ }
}
void PasswordStore::RemoveLoginsCreatedBetweenInternal(
@@ -1315,7 +1351,7 @@ std::ostream& operator<<(std::ostream& os,
const PasswordStore::FormDigest& digest) {
return os << "FormDigest(scheme: " << digest.scheme
<< ", signon_realm: " << digest.signon_realm
- << ", origin: " << digest.origin << ")";
+ << ", url: " << digest.url << ")";
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store.h b/chromium/components/password_manager/core/browser/password_store.h
index 34a0d57af92..44a20a0d47c 100644
--- a/chromium/components/password_manager/core/browser/password_store.h
+++ b/chromium/components/password_manager/core/browser/password_store.h
@@ -13,6 +13,7 @@
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/callback_list.h"
+#include "base/cancelable_callback.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
@@ -120,7 +121,7 @@ class PasswordStore : protected PasswordStoreSync,
struct FormDigest {
FormDigest(autofill::PasswordForm::Scheme scheme,
const std::string& signon_realm,
- const GURL& origin);
+ const GURL& url);
explicit FormDigest(const autofill::PasswordForm& form);
explicit FormDigest(const autofill::FormData& form);
FormDigest(const FormDigest& other);
@@ -131,7 +132,7 @@ class PasswordStore : protected PasswordStoreSync,
autofill::PasswordForm::Scheme scheme;
std::string signon_realm;
- GURL origin;
+ GURL url;
};
PasswordStore();
@@ -159,7 +160,7 @@ class PasswordStore : protected PasswordStoreSync,
virtual void AddLogin(const autofill::PasswordForm& form);
// Updates the matching PasswordForm in the secure password store (async).
- // If any of the primary key fields (signon_realm, origin, username_element,
+ // If any of the primary key fields (signon_realm, url, username_element,
// username_value, password_element) are updated, then the second version of
// the method must be used that takes |old_primary_key|, i.e., the old values
// for the primary key fields (the rest of the fields are ignored).
@@ -172,15 +173,20 @@ class PasswordStore : protected PasswordStoreSync,
virtual void RemoveLogin(const autofill::PasswordForm& form);
// Remove all logins whose origins match the given filter and that were
- // created
- // in the given date range. |completion| will be posted to the
- // |main_task_runner_| after deletions have been completed and notification
- // have been sent out.
+ // created in the given date range. |completion| will be posted to the
+ // |main_task_runner_| after deletions have been completed and notifications
+ // have been sent out. |sync_completion| will be posted to
+ // |main_task_runner_| once the deletions have also been propagated to the
+ // server (or, in rare cases, if the user permanently disables Sync or
+ // deletions haven't been propagated after 30 seconds). This is
+ // only relevant for Sync users and for account store users - for other users,
+ // |sync_completion| will be run immediately after |completion|.
void RemoveLoginsByURLAndTime(
const base::RepeatingCallback<bool(const GURL&)>& url_filter,
base::Time delete_begin,
base::Time delete_end,
- base::OnceClosure completion);
+ base::OnceClosure completion,
+ base::OnceCallback<void(bool)> sync_completion = base::NullCallback());
// Removes all logins created in the given date range. If |completion| is not
// null, it will be posted to the |main_task_runner_| after deletions have
@@ -252,6 +258,7 @@ class PasswordStore : protected PasswordStoreSync,
// Adds or replaces the statistics for the domain |stats.origin_domain|.
void AddSiteStats(const InteractionsStats& stats);
+ // TODO(crbug/1081389): replace GURL with Origin.
// Removes the statistics for |origin_domain|.
void RemoveSiteStats(const GURL& origin_domain);
@@ -572,6 +579,8 @@ class PasswordStore : protected PasswordStoreSync,
// been changed.
void NotifyLoginsChanged(const PasswordStoreChangeList& changes) override;
+ void NotifyDeletionsHaveSynced(bool success) override;
+
void NotifyUnsyncedCredentialsWillBeDeleted(
const std::vector<autofill::PasswordForm>& unsynced_credentials) override;
@@ -699,7 +708,8 @@ class PasswordStore : protected PasswordStoreSync,
const base::RepeatingCallback<bool(const GURL&)>& url_filter,
base::Time delete_begin,
base::Time delete_end,
- base::OnceClosure completion);
+ base::OnceClosure completion,
+ base::OnceCallback<void(bool)> sync_completion);
void RemoveLoginsCreatedBetweenInternal(base::Time delete_begin,
base::Time delete_end,
base::OnceClosure completion);
@@ -786,7 +796,7 @@ class PasswordStore : protected PasswordStoreSync,
const std::vector<std::string>& additional_android_realms);
// Retrieves the currently stored form, if any, with the same primary key as
- // |form|, that is, with the same signon_realm, origin, username_element,
+ // |form|, that is, with the same signon_realm, url, username_element,
// username_value and password_element attributes. To be called on the
// background sequence.
std::unique_ptr<autofill::PasswordForm> GetLoginImpl(
@@ -859,9 +869,16 @@ class PasswordStore : protected PasswordStoreSync,
std::unique_ptr<UnsyncedCredentialsDeletionNotifier> deletion_notifier_;
- bool shutdown_called_;
+ // A list of callbacks that should be run once all pending deletions have been
+ // sent to the Sync server. Note that the vector itself lives on the
+ // background thread, but the callbacks must be run on the main thread!
+ std::vector<base::OnceCallback<void(bool)>> deletions_have_synced_callbacks_;
+ // Timeout closure that runs if sync takes too long to propagate deletions.
+ base::CancelableClosure deletions_have_synced_timeout_;
+
+ bool shutdown_called_ = false;
- InitStatus init_status_;
+ InitStatus init_status_ = InitStatus::kUnknown;
DISALLOW_COPY_AND_ASSIGN(PasswordStore);
};
diff --git a/chromium/components/password_manager/core/browser/password_store_change.h b/chromium/components/password_manager/core/browser/password_store_change.h
index d65a55e136f..c24eb873792 100644
--- a/chromium/components/password_manager/core/browser/password_store_change.h
+++ b/chromium/components/password_manager/core/browser/password_store_change.h
@@ -47,7 +47,7 @@ class PasswordStoreChange {
bool operator==(const PasswordStoreChange& other) const {
return type() == other.type() &&
form().signon_realm == other.form().signon_realm &&
- form().origin == other.form().origin &&
+ form().url == other.form().url &&
form().action == other.form().action &&
form().submit_element == other.form().submit_element &&
form().username_element == other.form().username_element &&
diff --git a/chromium/components/password_manager/core/browser/password_store_consumer.cc b/chromium/components/password_manager/core/browser/password_store_consumer.cc
index e4e4d4b047a..e40cb07e15a 100644
--- a/chromium/components/password_manager/core/browser/password_store_consumer.cc
+++ b/chromium/components/password_manager/core/browser/password_store_consumer.cc
@@ -4,7 +4,9 @@
#include "components/password_manager/core/browser/password_store_consumer.h"
+#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/field_info_table.h"
+#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/statistics_table.h"
namespace password_manager {
@@ -13,6 +15,12 @@ PasswordStoreConsumer::PasswordStoreConsumer() = default;
PasswordStoreConsumer::~PasswordStoreConsumer() = default;
+void PasswordStoreConsumer::OnGetPasswordStoreResultsFrom(
+ scoped_refptr<PasswordStore> store,
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+ OnGetPasswordStoreResults(std::move(results));
+}
+
void PasswordStoreConsumer::OnGetSiteStatistics(
std::vector<InteractionsStats> stats) {}
diff --git a/chromium/components/password_manager/core/browser/password_store_consumer.h b/chromium/components/password_manager/core/browser/password_store_consumer.h
index 5e8e25df508..75c4c8d47f3 100644
--- a/chromium/components/password_manager/core/browser/password_store_consumer.h
+++ b/chromium/components/password_manager/core/browser/password_store_consumer.h
@@ -8,6 +8,8 @@
#include <memory>
#include <vector>
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/task/cancelable_task_tracker.h"
namespace autofill {
@@ -18,6 +20,7 @@ namespace password_manager {
struct FieldInfo;
struct InteractionsStats;
+class PasswordStore;
// Reads from the PasswordStore are done asynchronously on a separate
// thread. PasswordStoreConsumer provides the virtual callback method, which is
@@ -33,6 +36,15 @@ class PasswordStoreConsumer {
virtual void OnGetPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>> results) = 0;
+ // Like OnGetPasswordStoreResults(), but also receives the originating
+ // PasswordStore as a parameter. This is useful for consumers that query both
+ // the profile-scoped and the account-scoped store.
+ // The default implementation simply calls OnGetPasswordStoreResults(), so
+ // consumers that don't care about the store can just ignore this.
+ virtual void OnGetPasswordStoreResultsFrom(
+ scoped_refptr<PasswordStore> store,
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results);
+
// Called when the GetSiteStats() request is finished, with the associated
// site statistics.
virtual void OnGetSiteStatistics(std::vector<InteractionsStats> stats);
diff --git a/chromium/components/password_manager/core/browser/password_store_default.cc b/chromium/components/password_manager/core/browser/password_store_default.cc
index dc17fe82aef..bd797187541 100644
--- a/chromium/components/password_manager/core/browser/password_store_default.cc
+++ b/chromium/components/password_manager/core/browser/password_store_default.cc
@@ -22,8 +22,7 @@ PasswordStoreDefault::PasswordStoreDefault(
std::unique_ptr<LoginDatabase> login_db)
: login_db_(std::move(login_db)) {}
-PasswordStoreDefault::~PasswordStoreDefault() {
-}
+PasswordStoreDefault::~PasswordStoreDefault() = default;
void PasswordStoreDefault::ShutdownOnUIThread() {
PasswordStore::ShutdownOnUIThread();
@@ -41,6 +40,11 @@ bool PasswordStoreDefault::InitOnBackgroundSequence() {
success = false;
LOG(ERROR) << "Could not create/open login database.";
}
+ if (success) {
+ login_db_->SetDeletionsHaveSyncedCallback(
+ base::BindRepeating(&PasswordStoreDefault::NotifyDeletionsHaveSynced,
+ base::Unretained(this)));
+ }
return PasswordStore::InitOnBackgroundSequence() && success;
}
@@ -102,7 +106,7 @@ PasswordStoreChangeList PasswordStoreDefault::RemoveLoginsByURLAndTimeImpl(
for (const auto& pair : key_to_form_map) {
PasswordForm* form = pair.second.get();
PasswordStoreChangeList remove_changes;
- if (url_filter.Run(form->origin) &&
+ if (url_filter.Run(form->url) &&
login_db_->RemoveLogin(*form, &remove_changes)) {
std::move(remove_changes.begin(), remove_changes.end(),
std::back_inserter(changes));
@@ -132,8 +136,8 @@ PasswordStoreChangeList PasswordStoreDefault::DisableAutoSignInForOriginsImpl(
std::set<GURL> origins_to_update;
for (const auto& pair : key_to_form_map) {
- if (origin_filter.Run(pair.second->origin))
- origins_to_update.insert(pair.second->origin);
+ if (origin_filter.Run(pair.second->url))
+ origins_to_update.insert(pair.second->url);
}
std::set<GURL> origins_updated;
@@ -143,7 +147,7 @@ PasswordStoreChangeList PasswordStoreDefault::DisableAutoSignInForOriginsImpl(
}
for (const auto& pair : key_to_form_map) {
- if (origins_updated.count(pair.second->origin)) {
+ if (origins_updated.count(pair.second->url)) {
changes.emplace_back(PasswordStoreChange::UPDATE, *pair.second,
/*primary_key=*/pair.first);
}
diff --git a/chromium/components/password_manager/core/browser/password_store_default_unittest.cc b/chromium/components/password_manager/core/browser/password_store_default_unittest.cc
index 0be0cec5822..21d86f86a06 100644
--- a/chromium/components/password_manager/core/browser/password_store_default_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_default_unittest.cc
@@ -53,7 +53,6 @@ class MockPasswordStoreConsumer : public PasswordStoreConsumer {
class BadLoginDatabase : public LoginDatabase {
public:
BadLoginDatabase() : LoginDatabase(base::FilePath(), IsAccountStore(false)) {}
- ~BadLoginDatabase() override {}
// LoginDatabase:
bool Init() override { return false; }
@@ -173,8 +172,8 @@ TEST(PasswordStoreDefaultTest, NonASCIIData) {
// Build the expected forms vector and add the forms to the store.
std::vector<std::unique_ptr<PasswordForm>> expected_forms;
- for (unsigned int i = 0; i < base::size(form_data); ++i) {
- expected_forms.push_back(FillPasswordFormWithData(form_data[i]));
+ for (const auto& data : form_data) {
+ expected_forms.push_back(FillPasswordFormWithData(data));
store->AddLogin(*expected_forms.back());
}
@@ -256,7 +255,7 @@ TEST(PasswordStoreDefaultTest, OperationsOnABadDatabaseSilentlyFail) {
FillPasswordFormWithData(CreateTestPasswordFormData());
std::unique_ptr<PasswordForm> blacklisted_form(new PasswordForm(*form));
blacklisted_form->signon_realm = "http://foo.example.com";
- blacklisted_form->origin = GURL("http://foo.example.com/origin");
+ blacklisted_form->url = GURL("http://foo.example.com/origin");
blacklisted_form->action = GURL("http://foo.example.com/action");
blacklisted_form->blacklisted_by_user = true;
bad_store->AddLogin(*form);
diff --git a/chromium/components/password_manager/core/browser/password_store_signin_notifier.cc b/chromium/components/password_manager/core/browser/password_store_signin_notifier.cc
index bebd9ee425a..80300be5a34 100644
--- a/chromium/components/password_manager/core/browser/password_store_signin_notifier.cc
+++ b/chromium/components/password_manager/core/browser/password_store_signin_notifier.cc
@@ -9,9 +9,9 @@
namespace password_manager {
-PasswordStoreSigninNotifier::PasswordStoreSigninNotifier() {}
+PasswordStoreSigninNotifier::PasswordStoreSigninNotifier() = default;
-PasswordStoreSigninNotifier::~PasswordStoreSigninNotifier() {}
+PasswordStoreSigninNotifier::~PasswordStoreSigninNotifier() = default;
void PasswordStoreSigninNotifier::NotifySignedOut(const std::string& username,
bool primary_account) {
diff --git a/chromium/components/password_manager/core/browser/password_store_sync.h b/chromium/components/password_manager/core/browser/password_store_sync.h
index ac9361a7bd9..277bfa59908 100644
--- a/chromium/components/password_manager/core/browser/password_store_sync.h
+++ b/chromium/components/password_manager/core/browser/password_store_sync.h
@@ -102,6 +102,20 @@ class PasswordStoreSync {
// Deletes all the stored sync metadata for passwords.
virtual void DeleteAllSyncMetadata() = 0;
+
+ // Registers a callback that will be invoked whenever all pending (unsynced)
+ // deletions are gone. If they were committed to the server (or, rarely, the
+ // entity was undeleted), the |callback| will be run with "true". If the
+ // deletions are gone because Sync was permanently turned off, it'll be run
+ // with "false" instead.
+ // Note that there can be only one such callback; if one was already
+ // registered, it'll be overridden by the new |callback|.
+ virtual void SetDeletionsHaveSyncedCallback(
+ base::RepeatingCallback<void(bool)> callback) = 0;
+
+ // Returns whether there are any pending deletions that have not been sent
+ // to the Sync server yet.
+ virtual bool HasUnsyncedDeletions() = 0;
};
PasswordStoreSync();
@@ -149,6 +163,11 @@ class PasswordStoreSync {
// Notifies observers that password store data may have been changed.
virtual void NotifyLoginsChanged(const PasswordStoreChangeList& changes) = 0;
+ // Notifies any waiting callback that all pending deletions have been
+ // committed to the Sync server now, or that Sync definitely won't commit
+ // them (because Sync was turned off permanently).
+ virtual void NotifyDeletionsHaveSynced(bool success) = 0;
+
// Notifies the UI that some unsynced credentials will be deleted on sign-out
// in order to offer the user the option of saving them in the profile store.
// Should only be called for the account store.
diff --git a/chromium/components/password_manager/core/browser/password_store_unittest.cc b/chromium/components/password_manager/core/browser/password_store_unittest.cc
index 35bdcee8365..ea1d567caee 100644
--- a/chromium/components/password_manager/core/browser/password_store_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_unittest.cc
@@ -209,8 +209,8 @@ TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
// Build the forms vector and add the forms to the store.
std::vector<std::unique_ptr<PasswordForm>> all_forms;
- for (size_t i = 0; i < base::size(form_data); ++i) {
- all_forms.push_back(FillPasswordFormWithData(form_data[i]));
+ for (const auto& data : form_data) {
+ all_forms.push_back(FillPasswordFormWithData(data));
store->AddLogin(*all_forms.back());
}
@@ -296,7 +296,7 @@ TEST_F(PasswordStoreTest, UpdateLoginPrimaryKeyFields) {
EXPECT_CALL(mock_observer, OnLoginsChanged(testing::SizeIs(2u)));
PasswordForm old_primary_key;
old_primary_key.signon_realm = old_form->signon_realm;
- old_primary_key.origin = old_form->origin;
+ old_primary_key.url = old_form->url;
old_primary_key.username_element = old_form->username_element;
old_primary_key.username_value = old_form->username_value;
old_primary_key.password_element = old_form->password_element;
@@ -601,8 +601,8 @@ TEST_F(PasswordStoreTest, GetLoginsWithoutAffiliations) {
store->Init(nullptr);
std::vector<std::unique_ptr<PasswordForm>> all_credentials;
- for (size_t i = 0; i < base::size(kTestCredentials); ++i) {
- all_credentials.push_back(FillPasswordFormWithData(kTestCredentials[i]));
+ for (const auto& credential : kTestCredentials) {
+ all_credentials.push_back(FillPasswordFormWithData(credential));
store->AddLogin(*all_credentials.back());
}
@@ -869,8 +869,8 @@ TEST_F(PasswordStoreTest, UpdatePasswordsStoredForAffiliatedWebsites) {
// Set up the initial test data set.
std::vector<std::unique_ptr<PasswordForm>> all_credentials;
- for (size_t i = 0; i < base::size(kTestCredentials); ++i) {
- all_credentials.push_back(FillPasswordFormWithData(kTestCredentials[i]));
+ for (const auto& credential : kTestCredentials) {
+ all_credentials.push_back(FillPasswordFormWithData(credential));
all_credentials.back()->date_synced =
all_credentials.back()->date_created;
store->AddLogin(*all_credentials.back());
diff --git a/chromium/components/password_manager/core/browser/password_sync_util.cc b/chromium/components/password_manager/core/browser/password_sync_util.cc
index 3b9a791794d..6d903aeec68 100644
--- a/chromium/components/password_manager/core/browser/password_sync_util.cc
+++ b/chromium/components/password_manager/core/browser/password_sync_util.cc
@@ -89,8 +89,8 @@ bool IsGaiaCredentialPage(const std::string& signon_realm) {
bool ShouldSaveEnterprisePasswordHash(const autofill::PasswordForm& form,
const PrefService& prefs) {
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
- return safe_browsing::MatchesPasswordProtectionLoginURL(form.origin, prefs) ||
- safe_browsing::MatchesPasswordProtectionChangePasswordURL(form.origin,
+ return safe_browsing::MatchesPasswordProtectionLoginURL(form.url, prefs) ||
+ safe_browsing::MatchesPasswordProtectionChangePasswordURL(form.url,
prefs);
#else
return false;
diff --git a/chromium/components/password_manager/core/browser/password_ui_utils.cc b/chromium/components/password_manager/core/browser/password_ui_utils.cc
index 63d03583112..bda49377d3e 100644
--- a/chromium/components/password_manager/core/browser/password_ui_utils.cc
+++ b/chromium/components/password_manager/core/browser/password_ui_utils.cc
@@ -50,16 +50,16 @@ std::pair<std::string, GURL> GetShownOriginAndLinkUrl(
: password_form.app_display_name;
link_url = GURL(kPlayStoreAppPrefix + facet_uri.android_package_name());
} else {
- shown_origin = GetShownOrigin(password_form.origin);
- link_url = password_form.origin;
+ shown_origin = GetShownOrigin(url::Origin::Create(password_form.url));
+ link_url = password_form.url;
}
return {std::move(shown_origin), std::move(link_url)};
}
-std::string GetShownOrigin(const GURL& origin) {
+std::string GetShownOrigin(const url::Origin& origin) {
std::string original =
- base::UTF16ToUTF8(url_formatter::FormatUrlForSecurityDisplay(
+ base::UTF16ToUTF8(url_formatter::FormatOriginForSecurityDisplay(
origin, url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS));
base::StringPiece result = original;
for (base::StringPiece prefix : kRemovedPrefixes) {
diff --git a/chromium/components/password_manager/core/browser/password_ui_utils.h b/chromium/components/password_manager/core/browser/password_ui_utils.h
index 18a4fd7467a..9dd2808b379 100644
--- a/chromium/components/password_manager/core/browser/password_ui_utils.h
+++ b/chromium/components/password_manager/core/browser/password_ui_utils.h
@@ -12,7 +12,7 @@
#include "base/strings/string_piece.h"
-#include "url/gurl.h"
+#include "url/origin.h"
namespace autofill {
struct PasswordForm;
@@ -41,7 +41,7 @@ std::pair<std::string, GURL> GetShownOriginAndLinkUrl(
// Returns a string suitable for security display to the user (just like
// |FormatUrlForSecurityDisplay| with OMIT_HTTP_AND_HTTPS) based on origin of
// |password_form|) and without prefixes "m.", "mobile." or "www.".
-std::string GetShownOrigin(const GURL& origin);
+std::string GetShownOrigin(const url::Origin& origin);
// Updates the |form_manager| pending credentials with |username| and
// |password|.
diff --git a/chromium/components/password_manager/core/browser/password_ui_utils_unittest.cc b/chromium/components/password_manager/core/browser/password_ui_utils_unittest.cc
index 4ba9a9eb588..8dc03e1c128 100644
--- a/chromium/components/password_manager/core/browser/password_ui_utils_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_ui_utils_unittest.cc
@@ -33,9 +33,8 @@ TEST(GetShownOriginTest, RemovePrefixes) {
{"https://WWW.Example.DE", "example.de"}};
for (const auto& test_case : kTestCases) {
- autofill::PasswordForm password_form;
- password_form.origin = GURL(test_case.input);
- EXPECT_EQ(test_case.output, GetShownOrigin(password_form.origin))
+ EXPECT_EQ(test_case.output,
+ GetShownOrigin(url::Origin::Create(GURL(test_case.input))))
<< "for input " << test_case.input;
}
}
@@ -71,7 +70,7 @@ TEST(GetShownOriginAndLinkUrlTest, OriginFromAndroidForm_WithAppDisplayName) {
TEST(GetShownOriginAndLinkUrlTest, OriginFromNonAndroidForm) {
autofill::PasswordForm form;
form.signon_realm = "https://example.com/";
- form.origin = GURL("https://example.com/login?ref=1");
+ form.url = GURL("https://example.com/login?ref=1");
std::string shown_origin;
GURL link_url;
diff --git a/chromium/components/password_manager/core/browser/psl_matching_helper.cc b/chromium/components/password_manager/core/browser/psl_matching_helper.cc
index b7dca4c71f2..b945e2b3309 100644
--- a/chromium/components/password_manager/core/browser/psl_matching_helper.cc
+++ b/chromium/components/password_manager/core/browser/psl_matching_helper.cc
@@ -43,22 +43,21 @@ std::ostream& operator<<(std::ostream& out, MatchResult result) {
return out;
}
-bool IsFederatedRealm(const std::string& form_signon_realm,
- const GURL& origin) {
+bool IsFederatedRealm(const std::string& form_signon_realm, const GURL& url) {
// The format should be "federation://origin.host/federation.host;
- std::string federated_realm = "federation://" + origin.host() + "/";
+ std::string federated_realm = "federation://" + url.host() + "/";
return form_signon_realm.size() > federated_realm.size() &&
base::StartsWith(form_signon_realm, federated_realm,
base::CompareCase::INSENSITIVE_ASCII);
}
bool IsFederatedPSLMatch(const std::string& form_signon_realm,
- const GURL& form_origin,
- const GURL& origin) {
- if (!IsPublicSuffixDomainMatch(form_origin.spec(), origin.spec()))
+ const GURL& form_url,
+ const GURL& url) {
+ if (!IsPublicSuffixDomainMatch(form_url.spec(), url.spec()))
return false;
- return IsFederatedRealm(form_signon_realm, form_origin);
+ return IsFederatedRealm(form_signon_realm, form_url);
}
MatchResult GetMatchResult(const PasswordForm& form,
@@ -77,13 +76,13 @@ MatchResult GetMatchResult(const PasswordForm& form,
const bool allow_federated_match = !form.federation_origin.opaque();
if (allow_federated_match &&
- IsFederatedRealm(form.signon_realm, form_digest.origin) &&
- form.origin.GetOrigin() == form_digest.origin.GetOrigin()) {
+ IsFederatedRealm(form.signon_realm, form_digest.url) &&
+ form.url.GetOrigin() == form_digest.url.GetOrigin()) {
return MatchResult::FEDERATED_MATCH;
}
if (allow_federated_match &&
- IsFederatedPSLMatch(form.signon_realm, form.origin, form_digest.origin)) {
+ IsFederatedPSLMatch(form.signon_realm, form.url, form_digest.url)) {
return MatchResult::FEDERATED_PSL_MATCH;
}
diff --git a/chromium/components/password_manager/core/browser/psl_matching_helper_unittest.cc b/chromium/components/password_manager/core/browser/psl_matching_helper_unittest.cc
index 84a703f88c4..2a436193006 100644
--- a/chromium/components/password_manager/core/browser/psl_matching_helper_unittest.cc
+++ b/chromium/components/password_manager/core/browser/psl_matching_helper_unittest.cc
@@ -65,8 +65,8 @@ TEST(PSLMatchingUtilsTest, GetMatchResultNormalCredentials) {
for (const TestData& data : cases) {
autofill::PasswordForm form;
- form.origin = GURL(data.form_origin);
- form.signon_realm = form.origin.GetOrigin().spec();
+ form.url = GURL(data.form_origin);
+ form.signon_realm = form.url.GetOrigin().spec();
PasswordStore::FormDigest digest(
autofill::PasswordForm::Scheme::kHtml,
GURL(data.digest_origin).GetOrigin().spec(), GURL(data.digest_origin));
@@ -122,8 +122,8 @@ TEST(PSLMatchingUtilsTest, GetMatchResultPSL) {
for (const TestData& data : cases) {
autofill::PasswordForm form;
- form.origin = GURL(data.form_origin);
- form.signon_realm = form.origin.GetOrigin().spec();
+ form.url = GURL(data.form_origin);
+ form.signon_realm = form.url.GetOrigin().spec();
PasswordStore::FormDigest digest(
autofill::PasswordForm::Scheme::kHtml,
GURL(data.digest_origin).GetOrigin().spec(), GURL(data.digest_origin));
@@ -182,11 +182,11 @@ TEST(PSLMatchingUtilsTest, GetMatchResultFederated) {
for (const TestData& data : cases) {
autofill::PasswordForm form;
- form.origin = GURL(data.form_origin);
+ form.url = GURL(data.form_origin);
form.federation_origin =
url::Origin::Create(GURL(data.form_federation_origin));
- form.signon_realm = "federation://" + form.origin.host() + "/" +
- form.federation_origin.host();
+ form.signon_realm =
+ "federation://" + form.url.host() + "/" + form.federation_origin.host();
PasswordStore::FormDigest digest(
autofill::PasswordForm::Scheme::kHtml,
@@ -253,11 +253,11 @@ TEST(PSLMatchingUtilsTest, GetMatchResultFederatedPSL) {
for (const TestData& data : cases) {
autofill::PasswordForm form;
- form.origin = GURL(data.form_origin);
+ form.url = GURL(data.form_origin);
form.federation_origin =
url::Origin::Create(GURL(data.form_federation_origin));
- form.signon_realm = "federation://" + form.origin.host() + "/" +
- form.federation_origin.host();
+ form.signon_realm =
+ "federation://" + form.url.host() + "/" + form.federation_origin.host();
PasswordStore::FormDigest digest(
autofill::PasswordForm::Scheme::kHtml,
diff --git a/chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc b/chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc
index d35786dad4b..f29bd197e63 100644
--- a/chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc
+++ b/chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/test/mock_callback.h"
#include "sql/database.h"
diff --git a/chromium/components/password_manager/core/browser/statistics_table.cc b/chromium/components/password_manager/core/browser/statistics_table.cc
index 4975fcc199d..82439375f32 100644
--- a/chromium/components/password_manager/core/browser/statistics_table.cc
+++ b/chromium/components/password_manager/core/browser/statistics_table.cc
@@ -28,7 +28,7 @@ enum LoginTableColumns {
std::vector<InteractionsStats> StatementToInteractionsStats(sql::Statement* s) {
std::vector<InteractionsStats> results;
while (s->Step()) {
- results.push_back(InteractionsStats());
+ results.emplace_back();
results.back().origin_domain = GURL(s->ColumnString(COLUMN_ORIGIN_DOMAIN));
results.back().username_value = s->ColumnString16(COLUMN_USERNAME);
results.back().dismissal_count = s->ColumnInt(COLUMN_DISMISSALS);
diff --git a/chromium/components/password_manager/core/browser/statistics_table_unittest.cc b/chromium/components/password_manager/core/browser/statistics_table_unittest.cc
index 8fb520a0e9b..198332aba9d 100644
--- a/chromium/components/password_manager/core/browser/statistics_table_unittest.cc
+++ b/chromium/components/password_manager/core/browser/statistics_table_unittest.cc
@@ -4,6 +4,7 @@
#include "components/password_manager/core/browser/statistics_table.h"
#include <functional>
+#include <memory>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -45,8 +46,8 @@ class StatisticsTableTest : public testing::Test {
void ReloadDatabase() {
base::FilePath file = temp_dir_.GetPath().AppendASCII("TestDatabase");
- db_.reset(new StatisticsTable);
- connection_.reset(new sql::Database);
+ db_ = std::make_unique<StatisticsTable>();
+ connection_ = std::make_unique<sql::Database>();
connection_->set_exclusive_locking();
ASSERT_TRUE(connection_->Open(file));
db_->Init(connection_.get());
diff --git a/chromium/components/password_manager/core/browser/store_metrics_reporter.cc b/chromium/components/password_manager/core/browser/store_metrics_reporter.cc
index f38f31953f4..b8fe07c928a 100644
--- a/chromium/components/password_manager/core/browser/store_metrics_reporter.cc
+++ b/chromium/components/password_manager/core/browser/store_metrics_reporter.cc
@@ -5,6 +5,8 @@
#include "components/password_manager/core/browser/store_metrics_reporter.h"
#include "base/metrics/histogram_functions.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_store.h"
@@ -13,19 +15,169 @@
namespace password_manager {
+namespace {
+
+class Consumer : public PasswordStoreConsumer {
+ public:
+ explicit Consumer(PasswordStore* store,
+ base::OnceCallback<void(
+ std::vector<std::unique_ptr<autofill::PasswordForm>>)>
+ results_callback)
+ : results_callback_(std::move(results_callback)) {
+ store->GetAutofillableLogins(this);
+ }
+ ~Consumer() override = default;
+
+ void OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) override {
+ std::move(results_callback_).Run(std::move(results));
+ // Note: |this| might be destroyed now.
+ }
+
+ private:
+ base::OnceCallback<void(std::vector<std::unique_ptr<autofill::PasswordForm>>)>
+ results_callback_;
+};
+
+} // namespace
+
+class StoreMetricsReporter::MultiStoreMetricsReporter {
+ public:
+ MultiStoreMetricsReporter(PasswordStore* profile_store,
+ PasswordStore* account_store,
+ base::OnceClosure done_callback)
+ : done_callback_(std::move(done_callback)) {
+ DCHECK(profile_store);
+ DCHECK(account_store);
+ profile_store_consumer_ = std::make_unique<Consumer>(
+ profile_store,
+ base::BindOnce(&MultiStoreMetricsReporter::ReceiveResults,
+ base::Unretained(this), /*is_account_store=*/false));
+ account_store_consumer_ = std::make_unique<Consumer>(
+ account_store,
+ base::BindOnce(&MultiStoreMetricsReporter::ReceiveResults,
+ base::Unretained(this), /*is_account_store=*/true));
+ }
+
+ private:
+ void ReceiveResults(
+ bool is_account_store,
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+ if (is_account_store) {
+ for (const std::unique_ptr<autofill::PasswordForm>& form : results) {
+ account_store_results_.insert(std::make_pair(
+ std::make_pair(form->signon_realm, form->username_value),
+ form->password_value));
+ }
+ account_store_consumer_.reset();
+ } else {
+ for (const std::unique_ptr<autofill::PasswordForm>& form : results) {
+ profile_store_results_.insert(std::make_pair(
+ std::make_pair(form->signon_realm, form->username_value),
+ form->password_value));
+ }
+ profile_store_consumer_.reset();
+ }
+
+ if (!profile_store_consumer_ && !account_store_consumer_)
+ ReportMetrics();
+ }
+
+ void ReportMetrics() {
+ // Count the contents of the account store as compared to the profile store:
+ // - Additional: Credentials that are in the account store, but not in the
+ // profile store.
+ // - Missing: Credentials that are in the profile store, but not in the
+ // account store.
+ // - Identical: Credentials that are in both stores.
+ // - Conflicting: Credentials with the same signon realm and username, but
+ // different passwords in the two stores.
+ int additional = 0;
+ int missing = 0;
+ int identical = 0;
+ int conflicting = 0;
+
+ // Go over the data from both stores in parallel, always advancing in the
+ // one that is "behind". The entries are sorted by signon_realm and
+ // username (the exact ordering doesn't matter, just that it's consistent).
+ auto profile_it = profile_store_results_.begin();
+ auto account_it = account_store_results_.begin();
+ while (account_it != account_store_results_.end()) {
+ // First, go over any entries in the profile store that don't exist in the
+ // account store.
+ while (profile_it != profile_store_results_.end() &&
+ profile_it->first < account_it->first) {
+ ++missing;
+ ++profile_it;
+ }
+ // Now profile_it->first is >= account_it->first.
+ // Check if they match.
+ if (profile_it != profile_store_results_.end() &&
+ account_it->first == profile_it->first) {
+ // The signon_realm and username match, check the password value.
+ if (account_it->second == profile_it->second)
+ ++identical;
+ else
+ ++conflicting;
+
+ ++profile_it;
+ } else {
+ // The signon_realm and username don't match, so this is an account
+ // store entry that doesn't exist in the profile store.
+ ++additional;
+ }
+
+ ++account_it;
+ }
+ // We're done with the account store. Go over any remaining profile store
+ // entries.
+ while (profile_it != profile_store_results_.end()) {
+ ++missing;
+ ++profile_it;
+ }
+
+ base::UmaHistogramCounts100(
+ "PasswordManager.AccountStoreVsProfileStore.Additional", additional);
+ base::UmaHistogramCounts100(
+ "PasswordManager.AccountStoreVsProfileStore.Missing", missing);
+ base::UmaHistogramCounts100(
+ "PasswordManager.AccountStoreVsProfileStore.Identical", identical);
+ base::UmaHistogramCounts100(
+ "PasswordManager.AccountStoreVsProfileStore.Conflicting", conflicting);
+
+ std::move(done_callback_).Run();
+ // Note: |this| might be destroyed now.
+ }
+
+ base::OnceClosure done_callback_;
+
+ std::unique_ptr<Consumer> profile_store_consumer_;
+ std::unique_ptr<Consumer> account_store_consumer_;
+
+ // Maps from (signon_realm, username) to password.
+ std::map<std::pair<std::string, base::string16>, base::string16>
+ profile_store_results_;
+ std::map<std::pair<std::string, base::string16>, base::string16>
+ account_store_results_;
+};
+
StoreMetricsReporter::StoreMetricsReporter(
PasswordManagerClient* client,
const syncer::SyncService* sync_service,
const signin::IdentityManager* identity_manager,
PrefService* prefs) {
- // May be null in tests.
- if (PasswordStore* store = client->GetProfilePasswordStore()) {
- store->ReportMetrics(
- password_manager::sync_util::GetSyncUsernameIfSyncingPasswords(
- sync_service, identity_manager),
- client->GetPasswordSyncState() ==
- password_manager::SYNCING_WITH_CUSTOM_PASSPHRASE,
- client->IsUnderAdvancedProtection());
+ for (PasswordStore* store :
+ {client->GetProfilePasswordStore(), client->GetAccountPasswordStore()}) {
+ // May be null in tests. The account store is also null if the
+ // kEnablePasswordsAccountStorage feature is disabled.
+ if (store) {
+ store->ReportMetrics(
+ password_manager::sync_util::GetSyncUsernameIfSyncingPasswords(
+ sync_service, identity_manager),
+ client->GetPasswordSyncState() ==
+ password_manager::SYNCING_WITH_CUSTOM_PASSPHRASE,
+ client->IsUnderAdvancedProtection());
+ }
}
base::UmaHistogramBoolean(
"PasswordManager.Enabled",
@@ -34,6 +186,38 @@ StoreMetricsReporter::StoreMetricsReporter(
"PasswordManager.LeakDetection.Enabled",
prefs->GetBoolean(
password_manager::prefs::kPasswordLeakDetectionEnabled));
+
+ // If both stores exist, kick off the MultiStoreMetricsReporter.
+ PasswordStore* profile_store = client->GetProfilePasswordStore();
+ PasswordStore* account_store = client->GetAccountPasswordStore();
+ if (profile_store && account_store) {
+ // Delay the actual reporting by 30 seconds, to ensure it doesn't happen
+ // during the "hot phase" of Chrome startup. (This is what
+ // PasswordStore::ReportMetrics also does.)
+ // Grab refptrs to the stores, to ensure they're still alive when the
+ // delayed task runs.
+ scoped_refptr<PasswordStore> retained_profile_store = profile_store;
+ scoped_refptr<PasswordStore> retained_account_store = account_store;
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&StoreMetricsReporter::ReportMultiStoreMetrics,
+ weak_ptr_factory_.GetWeakPtr(), retained_profile_store,
+ retained_account_store),
+ base::TimeDelta::FromSeconds(30));
+ }
+}
+
+void StoreMetricsReporter::ReportMultiStoreMetrics(
+ scoped_refptr<PasswordStore> profile_store,
+ scoped_refptr<PasswordStore> account_store) {
+ multi_store_reporter_ = std::make_unique<MultiStoreMetricsReporter>(
+ profile_store.get(), account_store.get(),
+ base::BindOnce(&StoreMetricsReporter::MultiStoreMetricsDone,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void StoreMetricsReporter::MultiStoreMetricsDone() {
+ multi_store_reporter_.reset();
}
StoreMetricsReporter::~StoreMetricsReporter() = default;
diff --git a/chromium/components/password_manager/core/browser/store_metrics_reporter.h b/chromium/components/password_manager/core/browser/store_metrics_reporter.h
index 21d0ed2831b..5c017fbcf15 100644
--- a/chromium/components/password_manager/core/browser/store_metrics_reporter.h
+++ b/chromium/components/password_manager/core/browser/store_metrics_reporter.h
@@ -5,7 +5,11 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STORE_METRICS_REPORTER_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STORE_METRICS_REPORTER_H_
+#include <memory>
+
#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "components/password_manager/core/browser/password_store.h"
class PrefService;
@@ -34,7 +38,7 @@ class StoreMetricsReporter {
// |client| to obtain the password store and password syncing state. Uses
// |sync_service| and |identity_manager| to obtain the sync username to report
// about its presence among saved credentials. Uses the |prefs| to obtain
- // information wither the password manager and the leak detection feature is
+ // information whether the password manager and the leak detection feature is
// enabled.
StoreMetricsReporter(PasswordManagerClient* client,
const syncer::SyncService* sync_service,
@@ -44,6 +48,16 @@ class StoreMetricsReporter {
~StoreMetricsReporter();
private:
+ class MultiStoreMetricsReporter;
+
+ void ReportMultiStoreMetrics(scoped_refptr<PasswordStore> profile_store,
+ scoped_refptr<PasswordStore> account_store);
+ void MultiStoreMetricsDone();
+
+ std::unique_ptr<MultiStoreMetricsReporter> multi_store_reporter_;
+
+ base::WeakPtrFactory<StoreMetricsReporter> weak_ptr_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(StoreMetricsReporter);
};
diff --git a/chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc b/chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
index 3ad7ab30ed7..969961a0a04 100644
--- a/chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
+++ b/chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
@@ -6,11 +6,13 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "components/password_manager/core/browser/sync_username_test_base.h"
+#include "components/password_manager/core/browser/test_password_store.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
@@ -24,20 +26,25 @@ using ::testing::Return;
namespace password_manager {
namespace {
+autofill::PasswordForm CreateForm(const std::string& signon_realm,
+ const std::string& username,
+ const std::string& password) {
+ autofill::PasswordForm form;
+ form.signon_realm = signon_realm;
+ form.username_value = base::ASCIIToUTF16(username);
+ form.password_value = base::ASCIIToUTF16(password);
+ return form;
+}
+
class MockPasswordManagerClient : public StubPasswordManagerClient {
public:
MOCK_CONST_METHOD0(GetProfilePasswordStore, PasswordStore*());
+ MOCK_CONST_METHOD0(GetAccountPasswordStore, PasswordStore*());
MOCK_CONST_METHOD0(GetPasswordSyncState, SyncState());
MOCK_CONST_METHOD0(IsUnderAdvancedProtection, bool());
};
-// The test fixture defines two tests, one that doesn't require a password store
-// and one that does. Each of these tests depend on two boolean parameters,
-// which are declared here. Each test then assigns the desired semantics to
-// them.
-class StoreMetricsReporterTest
- : public SyncUsernameTestBase,
- public ::testing::WithParamInterface<std::tuple<bool, bool>> {
+class StoreMetricsReporterTest : public SyncUsernameTestBase {
public:
StoreMetricsReporterTest() {
prefs_.registry()->RegisterBooleanPref(prefs::kCredentialsEnableService,
@@ -56,8 +63,16 @@ class StoreMetricsReporterTest
DISALLOW_COPY_AND_ASSIGN(StoreMetricsReporterTest);
};
+// The test fixture defines two tests, one that doesn't require a password store
+// and one that does. Each of these tests depend on two boolean parameters,
+// which are declared here. Each test then assigns the desired semantics to
+// them.
+class StoreMetricsReporterTestWithParams
+ : public StoreMetricsReporterTest,
+ public ::testing::WithParamInterface<std::tuple<bool, bool>> {};
+
// Test that store-independent metrics are reported correctly.
-TEST_P(StoreMetricsReporterTest, StoreIndependentMetrics) {
+TEST_P(StoreMetricsReporterTestWithParams, StoreIndependentMetrics) {
const bool password_manager_enabled = std::get<0>(GetParam());
const bool leak_detection_enabled = std::get<1>(GetParam());
@@ -66,7 +81,8 @@ TEST_P(StoreMetricsReporterTest, StoreIndependentMetrics) {
prefs_.SetBoolean(password_manager::prefs::kPasswordLeakDetectionEnabled,
leak_detection_enabled);
base::HistogramTester histogram_tester;
- EXPECT_CALL(client_, GetProfilePasswordStore()).WillOnce(Return(nullptr));
+ EXPECT_CALL(client_, GetProfilePasswordStore())
+ .WillRepeatedly(Return(nullptr));
StoreMetricsReporter reporter(&client_, sync_service(), identity_manager(),
&prefs_);
@@ -78,7 +94,7 @@ TEST_P(StoreMetricsReporterTest, StoreIndependentMetrics) {
// Test that sync username and syncing state are passed correctly to the
// PasswordStore.
-TEST_P(StoreMetricsReporterTest, StoreDependentMetrics) {
+TEST_P(StoreMetricsReporterTestWithParams, StoreDependentMetrics) {
const bool syncing_with_passphrase = std::get<0>(GetParam());
const bool is_under_advanced_protection = std::get<1>(GetParam());
@@ -86,10 +102,12 @@ TEST_P(StoreMetricsReporterTest, StoreDependentMetrics) {
const auto sync_state = syncing_with_passphrase
? password_manager::SYNCING_WITH_CUSTOM_PASSPHRASE
: password_manager::SYNCING_NORMAL_ENCRYPTION;
- EXPECT_CALL(client_, GetPasswordSyncState()).WillOnce(Return(sync_state));
- EXPECT_CALL(client_, GetProfilePasswordStore()).WillOnce(Return(store.get()));
+ EXPECT_CALL(client_, GetPasswordSyncState())
+ .WillRepeatedly(Return(sync_state));
+ EXPECT_CALL(client_, GetProfilePasswordStore())
+ .WillRepeatedly(Return(store.get()));
EXPECT_CALL(client_, IsUnderAdvancedProtection())
- .WillOnce(Return(is_under_advanced_protection));
+ .WillRepeatedly(Return(is_under_advanced_protection));
EXPECT_CALL(*store,
ReportMetrics("some.user@gmail.com", syncing_with_passphrase,
is_under_advanced_protection));
@@ -100,8 +118,98 @@ TEST_P(StoreMetricsReporterTest, StoreDependentMetrics) {
store->ShutdownOnUIThread();
}
+// A test that covers multi-store metrics, which are recorded by the
+// StoreMetricsReporter directly.
+TEST_F(StoreMetricsReporterTest, MultiStoreMetrics) {
+ auto profile_store =
+ base::MakeRefCounted<TestPasswordStore>(/*is_account_store=*/false);
+ auto account_store =
+ base::MakeRefCounted<TestPasswordStore>(/*is_account_store=*/true);
+ profile_store->Init(&prefs_);
+ account_store->Init(&prefs_);
+
+ EXPECT_CALL(client_, GetPasswordSyncState())
+ .WillRepeatedly(
+ Return(password_manager::ACCOUNT_PASSWORDS_ACTIVE_NORMAL_ENCRYPTION));
+ EXPECT_CALL(client_, IsUnderAdvancedProtection())
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(client_, GetProfilePasswordStore())
+ .WillRepeatedly(Return(profile_store.get()));
+ EXPECT_CALL(client_, GetAccountPasswordStore())
+ .WillRepeatedly(Return(account_store.get()));
+
+ const std::string kRealm1 = "https://example.com";
+ const std::string kRealm2 = "https://example2.com";
+
+ // Add test data to the profile store:
+ // - 3 credentials that don't exist in the account store
+ // - 1 credential that conflicts with the account store (exists there with the
+ // same username but different password)
+ // - 2 credentials with identical copies in the account store
+ // Note: In the implementation, the credentials are processed in alphabetical
+ // order of usernames. Choose usernames here so that some profile-store-only
+ // credentials end up at both the start and the end of the list, to make sure
+ // these cases are handled correctly.
+ profile_store->AddLogin(
+ CreateForm(kRealm1, "aprofileuser1", "aprofilepass1"));
+ profile_store->AddLogin(
+ CreateForm(kRealm1, "aprofileuser2", "aprofilepass2"));
+ profile_store->AddLogin(
+ CreateForm(kRealm1, "zprofileuser3", "zprofilepass3"));
+ profile_store->AddLogin(CreateForm(kRealm1, "conflictinguser", "localpass"));
+ profile_store->AddLogin(
+ CreateForm(kRealm1, "identicaluser1", "identicalpass1"));
+ profile_store->AddLogin(
+ CreateForm(kRealm1, "identicaluser2", "identicalpass2"));
+
+ // Add test data to the account store:
+ // - 2 credentials that don't exist in the account store
+ // - 1 credential that conflicts with the profile store (exists there with the
+ // same username but different password)
+ // - 2 credentials with identical copies in the profile store
+ account_store->AddLogin(CreateForm(kRealm1, "accountuser1", "accountpass1"));
+ account_store->AddLogin(
+ CreateForm(kRealm1, "zaccountuser2", "zaccountpass2"));
+ account_store->AddLogin(
+ CreateForm(kRealm1, "conflictinguser", "accountpass"));
+ account_store->AddLogin(
+ CreateForm(kRealm1, "identicaluser1", "identicalpass1"));
+ account_store->AddLogin(
+ CreateForm(kRealm1, "identicaluser2", "identicalpass2"));
+
+ // Finally, add one more identical credential to the profile store. However
+ // this one is on a different signon realm, so should be counted as just
+ // another (4th) credential that's missing in the account store.
+ profile_store->AddLogin(
+ CreateForm(kRealm2, "identicaluser1", "identicalpass1"));
+
+ base::HistogramTester histogram_tester;
+
+ StoreMetricsReporter reporter(&client_, sync_service(), identity_manager(),
+ &prefs_);
+ // Wait for the metrics to get reported. This is delayed by 30 seconds, and
+ // then involves queries to the stores, i.e. to background task runners.
+ FastForwardBy(base::TimeDelta::FromSeconds(30));
+ RunUntilIdle();
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreVsProfileStore.Additional", 2, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreVsProfileStore.Missing", 4, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreVsProfileStore.Identical", 2, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreVsProfileStore.Conflicting", 1, 1);
+
+ account_store->ShutdownOnUIThread();
+ profile_store->ShutdownOnUIThread();
+ // Make sure the PasswordStore destruction parts on the background sequence
+ // finish, otherwise we get memory leak reports.
+ RunUntilIdle();
+}
+
INSTANTIATE_TEST_SUITE_P(All,
- StoreMetricsReporterTest,
+ StoreMetricsReporterTestWithParams,
testing::Combine(Bool(), Bool()));
} // namespace
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_client.cc b/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
index c6c3db72252..9faf43bf97e 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
@@ -15,7 +15,7 @@ namespace password_manager {
StubPasswordManagerClient::StubPasswordManagerClient()
: ukm_source_id_(ukm::UkmRecorder::GetNewSourceID()) {}
-StubPasswordManagerClient::~StubPasswordManagerClient() {}
+StubPasswordManagerClient::~StubPasswordManagerClient() = default;
bool StubPasswordManagerClient::PromptUserToSaveOrUpdatePassword(
std::unique_ptr<PasswordFormManagerForUI> form_to_save,
@@ -44,14 +44,14 @@ void StubPasswordManagerClient::FocusedInputChanged(
bool StubPasswordManagerClient::PromptUserToChooseCredentials(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
- const GURL& origin,
+ const url::Origin& origin,
const CredentialsCallback& callback) {
return false;
}
void StubPasswordManagerClient::NotifyUserAutoSignin(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
- const GURL& origin) {}
+ const url::Origin& origin) {}
void StubPasswordManagerClient::NotifyUserCouldBeAutoSignedIn(
std::unique_ptr<autofill::PasswordForm> form) {}
@@ -76,10 +76,14 @@ PasswordStore* StubPasswordManagerClient::GetAccountPasswordStore() const {
return nullptr;
}
-const GURL& StubPasswordManagerClient::GetLastCommittedEntryURL() const {
+const GURL& StubPasswordManagerClient::GetLastCommittedURL() const {
return GURL::EmptyGURL();
}
+url::Origin StubPasswordManagerClient::GetLastCommittedOrigin() const {
+ return url::Origin();
+}
+
const CredentialsFilter* StubPasswordManagerClient::GetStoreResultFilter()
const {
return &credentials_filter_;
@@ -132,7 +136,7 @@ ukm::SourceId StubPasswordManagerClient::GetUkmSourceId() {
PasswordManagerMetricsRecorder*
StubPasswordManagerClient::GetMetricsRecorder() {
if (!metrics_recorder_) {
- metrics_recorder_.emplace(GetUkmSourceId(), GetMainFrameURL(), nullptr);
+ metrics_recorder_.emplace(GetUkmSourceId(), nullptr);
}
return base::OptionalOrNullptr(metrics_recorder_);
}
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_client.h b/chromium/components/password_manager/core/browser/stub_password_manager_client.h
index 69cc390c1e2..d6175706b5c 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_client.h
@@ -44,11 +44,11 @@ class StubPasswordManagerClient : public PasswordManagerClient {
autofill::mojom::FocusedFieldType focused_field_type) override;
bool PromptUserToChooseCredentials(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
- const GURL& origin,
+ const url::Origin& origin,
const CredentialsCallback& callback) override;
void NotifyUserAutoSignin(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
- const GURL& origin) override;
+ const url::Origin& origin) override;
void NotifyUserCouldBeAutoSignedIn(
std::unique_ptr<autofill::PasswordForm>) override;
void NotifySuccessfulLoginWithExistingPassword(
@@ -59,7 +59,8 @@ class StubPasswordManagerClient : public PasswordManagerClient {
PrefService* GetPrefs() const override;
PasswordStore* GetProfilePasswordStore() const override;
PasswordStore* GetAccountPasswordStore() const override;
- const GURL& GetLastCommittedEntryURL() const override;
+ const GURL& GetLastCommittedURL() const override;
+ url::Origin GetLastCommittedOrigin() const override;
const CredentialsFilter* GetStoreResultFilter() const override;
const autofill::LogManager* GetLogManager() const override;
const MockPasswordFeatureManager* GetPasswordFeatureManager() const override;
diff --git a/chromium/components/password_manager/core/browser/sync/password_model_type_controller.cc b/chromium/components/password_manager/core/browser/sync/password_model_type_controller.cc
index feca14dc11a..6e1fd12ca49 100644
--- a/chromium/components/password_manager/core/browser/sync/password_model_type_controller.cc
+++ b/chromium/components/password_manager/core/browser/sync/password_model_type_controller.cc
@@ -8,6 +8,7 @@
#include "components/password_manager/core/browser/password_manager_features_util.h"
#include "components/prefs/pref_service.h"
+#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
#include "components/sync/base/model_type.h"
#include "components/sync/driver/sync_client.h"
#include "components/sync/driver/sync_service.h"
@@ -81,8 +82,10 @@ syncer::DataTypeController::PreconditionState
PasswordModelTypeController::GetPreconditionState() const {
// If Sync-the-feature is enabled, then the user has opted in to that, and no
// additional opt-in is required here.
- if (sync_service_->IsSyncFeatureEnabled())
+ if (sync_service_->IsSyncFeatureEnabled() ||
+ sync_service_->IsLocalSyncEnabled()) {
return PreconditionState::kPreconditionsMet;
+ }
// If Sync-the-feature is *not* enabled, then password sync should only be
// turned on if the user has opted in to the account-scoped storage.
return features_util::IsOptedInForAccountStorage(pref_service_, sync_service_)
@@ -96,10 +99,44 @@ void PasswordModelTypeController::OnStateChanged(syncer::SyncService* sync) {
state_changed_callback_.Run();
}
+void PasswordModelTypeController::OnAccountsInCookieUpdated(
+ const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
+ const GoogleServiceAuthError& error) {
+ // If the account information is stale, do nothing for now - wait until there
+ // is fresh information.
+ if (!accounts_in_cookie_jar_info.accounts_are_fresh) {
+ return;
+ }
+ // Collect all the known accounts (signed-in or signed-out).
+ std::vector<std::string> gaia_ids;
+ for (const gaia::ListedAccount& account :
+ accounts_in_cookie_jar_info.signed_in_accounts) {
+ gaia_ids.push_back(account.gaia_id);
+ }
+ for (const gaia::ListedAccount& account :
+ accounts_in_cookie_jar_info.signed_out_accounts) {
+ gaia_ids.push_back(account.gaia_id);
+ }
+ // Keep any account-storage settings only for known accounts.
+ features_util::KeepAccountStorageSettingsOnlyForUsers(pref_service_,
+ gaia_ids);
+}
+
void PasswordModelTypeController::OnAccountsCookieDeletedByUserAction() {
features_util::ClearAccountStorageSettingsForAllUsers(pref_service_);
}
+void PasswordModelTypeController::OnPrimaryAccountCleared(
+ const CoreAccountInfo& previous_primary_account_info) {
+ // Note: OnPrimaryAccountCleared() basically means that the consent for
+ // Sync-the-feature was revoked. In this case, also clear any possible
+ // matching opt-in for the account-scoped storage, since it'd probably be
+ // surprising to the user if their account passwords still remained after
+ // disabling Sync.
+ features_util::OptOutOfAccountStorageAndClearSettingsForAccount(
+ pref_service_, previous_primary_account_info.gaia);
+}
+
void PasswordModelTypeController::OnOptInStateMaybeChanged() {
// Note: This method gets called in many other situations as well, not just
// when the opt-in state changes, but DataTypePreconditionChanged() is cheap
diff --git a/chromium/components/password_manager/core/browser/sync/password_model_type_controller.h b/chromium/components/password_manager/core/browser/sync/password_model_type_controller.h
index a25be9fb73f..e3bfb46e6a5 100644
--- a/chromium/components/password_manager/core/browser/sync/password_model_type_controller.h
+++ b/chromium/components/password_manager/core/browser/sync/password_model_type_controller.h
@@ -50,7 +50,12 @@ class PasswordModelTypeController : public syncer::ModelTypeController,
void OnStateChanged(syncer::SyncService* sync) override;
// IdentityManager::Observer overrides.
+ void OnAccountsInCookieUpdated(
+ const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
+ const GoogleServiceAuthError& error) override;
void OnAccountsCookieDeletedByUserAction() override;
+ void OnPrimaryAccountCleared(
+ const CoreAccountInfo& previous_primary_account_info) override;
private:
void OnOptInStateMaybeChanged();
diff --git a/chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc b/chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc
index 289defba7bc..ba059757c15 100644
--- a/chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc
+++ b/chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc
@@ -67,7 +67,7 @@ sync_pb::PasswordSpecifics SpecificsFromPassword(
specifics.mutable_client_only_encrypted_data();
password_data->set_scheme(static_cast<int>(password_form.scheme));
password_data->set_signon_realm(password_form.signon_realm);
- password_data->set_origin(password_form.origin.spec());
+ password_data->set_origin(password_form.url.spec());
password_data->set_action(password_form.action.spec());
password_data->set_username_element(
base::UTF16ToUTF8(password_form.username_element));
@@ -105,7 +105,7 @@ autofill::PasswordForm PasswordFromEntityChange(
password.scheme =
static_cast<autofill::PasswordForm::Scheme>(password_data.scheme());
password.signon_realm = password_data.signon_realm();
- password.origin = GURL(password_data.origin());
+ password.url = GURL(password_data.origin());
password.action = GURL(password_data.action());
password.username_element =
base::UTF8ToUTF16(password_data.username_element());
@@ -163,7 +163,7 @@ bool AreLocalAndRemotePasswordsEqual(
return (
static_cast<int>(password_form.scheme) == password_specifics.scheme() &&
password_form.signon_realm == password_specifics.signon_realm() &&
- password_form.origin.spec() == password_specifics.origin() &&
+ password_form.url.spec() == password_specifics.origin() &&
password_form.action.spec() == password_specifics.action() &&
base::UTF16ToUTF8(password_form.username_element) ==
password_specifics.username_element() &&
@@ -817,7 +817,8 @@ void PasswordSyncBridge::ApplyStopSyncChanges(
const autofill::PasswordForm& form = *primary_key_and_form.second;
password_store_changes.emplace_back(PasswordStoreChange::REMOVE, form,
primary_key);
- if (unsynced_passwords_storage_keys.count(primary_key) != 0) {
+ if (unsynced_passwords_storage_keys.count(primary_key) != 0 &&
+ !form.blacklisted_by_user) {
unsynced_logins_being_deleted.push_back(form);
}
}
@@ -826,6 +827,10 @@ void PasswordSyncBridge::ApplyStopSyncChanges(
password_store_sync_->DeleteAndRecreateDatabaseFile();
password_store_sync_->NotifyLoginsChanged(password_store_changes);
+ base::UmaHistogramCounts100(
+ "PasswordManager.AccountStorage.UnsyncedPasswordsFoundDuringSignOut",
+ unsynced_logins_being_deleted.size());
+
if (!unsynced_logins_being_deleted.empty()) {
password_store_sync_->NotifyUnsyncedCredentialsWillBeDeleted(
unsynced_logins_being_deleted);
diff --git a/chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc b/chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
index 7e5d29e68e2..ef3b6222a11 100644
--- a/chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
+++ b/chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
@@ -12,6 +12,7 @@
#include "base/bind_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind_test_util.h"
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "build/build_config.h"
#include "components/password_manager/core/browser/password_store_sync.h"
@@ -89,7 +90,7 @@ sync_pb::PasswordSpecifics CreateSpecificsWithSignonRealm(
autofill::PasswordForm MakePasswordForm(const std::string& signon_realm) {
autofill::PasswordForm form;
- form.origin = GURL("http://www.origin.com");
+ form.url = GURL("http://www.origin.com");
form.username_element = base::UTF8ToUTF16("username_element");
form.username_value = base::UTF8ToUTF16("username_value");
form.password_element = base::UTF8ToUTF16("password_element");
@@ -97,6 +98,14 @@ autofill::PasswordForm MakePasswordForm(const std::string& signon_realm) {
return form;
}
+autofill::PasswordForm MakeBlacklistedForm(const std::string& signon_realm) {
+ autofill::PasswordForm form;
+ form.url = GURL("http://www.origin.com");
+ form.signon_realm = signon_realm;
+ form.blacklisted_by_user = true;
+ return form;
+}
+
// A mini database class the supports Add/Update/Remove functionality. It also
// supports an auto increment primary key that starts from 1. It will be used to
// empower the MockPasswordStoreSync be forwarding all database calls to an
@@ -175,9 +184,6 @@ class FakeDatabase {
class MockSyncMetadataStore : public PasswordStoreSync::MetadataStore {
public:
- MockSyncMetadataStore() = default;
- ~MockSyncMetadataStore() = default;
-
MOCK_METHOD0(GetAllSyncMetadata, std::unique_ptr<syncer::MetadataBatch>());
MOCK_METHOD0(DeleteAllSyncMetadata, void());
MOCK_METHOD3(UpdateSyncMetadata,
@@ -188,13 +194,13 @@ class MockSyncMetadataStore : public PasswordStoreSync::MetadataStore {
MOCK_METHOD2(UpdateModelTypeState,
bool(syncer::ModelType, const sync_pb::ModelTypeState&));
MOCK_METHOD1(ClearModelTypeState, bool(syncer::ModelType));
+ MOCK_METHOD1(SetDeletionsHaveSyncedCallback,
+ void(base::RepeatingCallback<void(bool)>));
+ MOCK_METHOD0(HasUnsyncedDeletions, bool());
};
class MockPasswordStoreSync : public PasswordStoreSync {
public:
- MockPasswordStoreSync() = default;
- ~MockPasswordStoreSync() = default;
-
MOCK_METHOD1(FillAutofillableLogins,
bool(std::vector<std::unique_ptr<autofill::PasswordForm>>*));
MOCK_METHOD1(FillBlacklistLogins,
@@ -211,6 +217,8 @@ class MockPasswordStoreSync : public PasswordStoreSync {
MOCK_METHOD1(RemoveLoginSync,
PasswordStoreChangeList(const autofill::PasswordForm&));
MOCK_METHOD1(NotifyLoginsChanged, void(const PasswordStoreChangeList&));
+ MOCK_METHOD1(NotifyDeletionsHaveSynced, void(bool));
+
MOCK_METHOD1(
NotifyUnsyncedCredentialsWillBeDeleted,
void(const std::vector<autofill::PasswordForm>& unsynced_credentials));
@@ -273,8 +281,6 @@ class PasswordSyncBridgeTest : public testing::Test {
return data;
}
- ~PasswordSyncBridgeTest() override {}
-
base::Optional<sync_pb::PasswordSpecifics> GetDataFromBridge(
const std::string& storage_key) {
std::unique_ptr<syncer::DataBatch> batch;
@@ -899,18 +905,22 @@ TEST_F(PasswordSyncBridgeTest, ShouldNotNotifyOnSyncDisableIfProfileStore) {
}
TEST_F(PasswordSyncBridgeTest, ShouldNotifyUnsyncedCredentialsIfAccountStore) {
+ base::HistogramTester histogram_tester;
ON_CALL(*mock_password_store_sync(), IsAccountStore())
.WillByDefault(Return(true));
const std::string kPrimaryKeyUnsyncedCredentialStr = "1000";
const std::string kPrimaryKeySyncedCredentialStr = "1001";
const std::string kPrimaryKeyUnsyncedDeletionStr = "1002";
+ const std::string kPrimaryKeyUnsyncedBlacklistStr = "1003";
ON_CALL(mock_processor(), IsEntityUnsynced(kPrimaryKeyUnsyncedCredentialStr))
.WillByDefault(Return(true));
ON_CALL(mock_processor(), IsEntityUnsynced(kPrimaryKeySyncedCredentialStr))
.WillByDefault(Return(false));
ON_CALL(mock_processor(), IsEntityUnsynced(kPrimaryKeyUnsyncedDeletionStr))
.WillByDefault(Return(true));
+ ON_CALL(mock_processor(), IsEntityUnsynced(kPrimaryKeyUnsyncedBlacklistStr))
+ .WillByDefault(Return(true));
sync_pb::EntityMetadata is_deletion_metadata;
is_deletion_metadata.set_is_deleted(true);
@@ -928,6 +938,9 @@ TEST_F(PasswordSyncBridgeTest, ShouldNotifyUnsyncedCredentialsIfAccountStore) {
batch->AddMetadata(
kPrimaryKeyUnsyncedDeletionStr,
std::make_unique<sync_pb::EntityMetadata>(is_deletion_metadata));
+ batch->AddMetadata(kPrimaryKeyUnsyncedBlacklistStr,
+ std::make_unique<sync_pb::EntityMetadata>(
+ is_not_deletion_metadata));
return batch;
});
@@ -935,25 +948,35 @@ TEST_F(PasswordSyncBridgeTest, ShouldNotifyUnsyncedCredentialsIfAccountStore) {
// because the deletion is supposed to have already removed such form.
const int kPrimaryKeyUnsyncedCredential = 1000;
const int kPrimaryKeySyncedCredential = 1001;
+ const int kPrimaryKeyUnsyncedBlacklist = 1003;
autofill::PasswordForm unsynced_credential = MakePasswordForm(kSignonRealm1);
autofill::PasswordForm synced_credential = MakePasswordForm(kSignonRealm2);
+ autofill::PasswordForm unsynced_blacklist =
+ MakeBlacklistedForm(kSignonRealm3);
fake_db()->AddLoginForPrimaryKey(kPrimaryKeyUnsyncedCredential,
unsynced_credential);
fake_db()->AddLoginForPrimaryKey(kPrimaryKeySyncedCredential,
synced_credential);
+ fake_db()->AddLoginForPrimaryKey(kPrimaryKeyUnsyncedBlacklist,
+ unsynced_blacklist);
// The notification should only contain new credentials that are unsynced,
- // ignoring both synced ones and deletion entries.
+ // ignoring both synced ones, deletion entries and blacklists.
EXPECT_CALL(*mock_password_store_sync(),
NotifyUnsyncedCredentialsWillBeDeleted(
UnorderedElementsAre(unsynced_credential)));
// The content of the metadata change list does not matter in this case.
bridge()->ApplyStopSyncChanges(bridge()->CreateMetadataChangeList());
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStorage.UnsyncedPasswordsFoundDuringSignOut", 1,
+ 1);
}
TEST_F(PasswordSyncBridgeTest,
ShouldNotNotifyUnsyncedCredentialsIfProfileStore) {
+ base::HistogramTester histogram_tester;
ON_CALL(*mock_password_store_sync(), IsAccountStore())
.WillByDefault(Return(false));
@@ -983,6 +1006,9 @@ TEST_F(PasswordSyncBridgeTest,
// The content of the metadata change list does not matter in this case.
bridge()->ApplyStopSyncChanges(bridge()->CreateMetadataChangeList());
+
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.AccountStorage.UnsyncedPasswordsFoundDuringSignOut", 0);
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/sync_credentials_filter.cc b/chromium/components/password_manager/core/browser/sync_credentials_filter.cc
index a453c4b1bcd..810192ae78a 100644
--- a/chromium/components/password_manager/core/browser/sync_credentials_filter.cc
+++ b/chromium/components/password_manager/core/browser/sync_credentials_filter.cc
@@ -28,7 +28,7 @@ SyncCredentialsFilter::SyncCredentialsFilter(
sync_service_factory_function_(std::move(sync_service_factory_function)) {
}
-SyncCredentialsFilter::~SyncCredentialsFilter() {}
+SyncCredentialsFilter::~SyncCredentialsFilter() = default;
bool SyncCredentialsFilter::ShouldSave(
const autofill::PasswordForm& form) const {
diff --git a/chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc b/chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
index 62b66d69511..36e770f14a6 100644
--- a/chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
+++ b/chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
@@ -68,8 +68,8 @@ class FakePasswordManagerClient : public StubPasswordManagerClient {
}
// PasswordManagerClient:
- const GURL& GetLastCommittedEntryURL() const override {
- return last_committed_entry_url_;
+ url::Origin GetLastCommittedOrigin() const override {
+ return last_committed_origin_;
}
MockPasswordStore* GetProfilePasswordStore() const override {
return password_store_.get();
@@ -78,8 +78,8 @@ class FakePasswordManagerClient : public StubPasswordManagerClient {
return identity_manager_;
}
- void set_last_committed_entry_url(const char* url_spec) {
- last_committed_entry_url_ = GURL(url_spec);
+ void set_last_committed_entry_url(base::StringPiece url_spec) {
+ last_committed_origin_ = url::Origin::Create(GURL(url_spec));
}
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
@@ -91,7 +91,7 @@ class FakePasswordManagerClient : public StubPasswordManagerClient {
void SetIsIncognito(bool is_incognito) { is_incognito_ = is_incognito; }
private:
- GURL last_committed_entry_url_;
+ url::Origin last_committed_origin_;
scoped_refptr<testing::NiceMock<MockPasswordStore>> password_store_ =
new testing::NiceMock<MockPasswordStore>;
bool is_incognito_ = false;
diff --git a/chromium/components/password_manager/core/browser/sync_username_test_base.cc b/chromium/components/password_manager/core/browser/sync_username_test_base.cc
index d23c5dafa7e..e9ed4042707 100644
--- a/chromium/components/password_manager/core/browser/sync_username_test_base.cc
+++ b/chromium/components/password_manager/core/browser/sync_username_test_base.cc
@@ -76,7 +76,7 @@ PasswordForm SyncUsernameTestBase::SimpleNonGaiaForm(const char* username,
PasswordForm form;
form.signon_realm = "https://site.com";
form.username_value = ASCIIToUTF16(username);
- form.origin = GURL(origin);
+ form.url = GURL(origin);
form.form_data = CreateSigninFormData(GURL(form.signon_realm), username);
return form;
}
diff --git a/chromium/components/password_manager/core/browser/sync_username_test_base.h b/chromium/components/password_manager/core/browser/sync_username_test_base.h
index 9f70d48fb86..5ac1fbb1b56 100644
--- a/chromium/components/password_manager/core/browser/sync_username_test_base.h
+++ b/chromium/components/password_manager/core/browser/sync_username_test_base.h
@@ -42,8 +42,12 @@ class SyncUsernameTestBase : public testing::Test {
return identity_test_env_.identity_manager();
}
+ void FastForwardBy(base::TimeDelta delta) { task_env_.FastForwardBy(delta); }
+ void RunUntilIdle() { task_env_.RunUntilIdle(); }
+
private:
- base::test::TaskEnvironment scoped_task_env_;
+ base::test::TaskEnvironment task_env_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
signin::IdentityTestEnvironment identity_test_env_;
syncer::TestSyncService sync_service_;
};
diff --git a/chromium/components/password_manager/core/browser/test_password_store.cc b/chromium/components/password_manager/core/browser/test_password_store.cc
index ac84adb0b6d..2ee5b021670 100644
--- a/chromium/components/password_manager/core/browser/test_password_store.cc
+++ b/chromium/components/password_manager/core/browser/test_password_store.cc
@@ -42,6 +42,9 @@ class TestPasswordSyncMetadataStore : public PasswordStoreSync::MetadataStore {
bool ClearModelTypeState(syncer::ModelType model_type) override;
std::unique_ptr<syncer::MetadataBatch> GetAllSyncMetadata() override;
void DeleteAllSyncMetadata() override;
+ void SetDeletionsHaveSyncedCallback(
+ base::RepeatingCallback<void(bool)> callback) override;
+ bool HasUnsyncedDeletions() override;
private:
sync_pb::ModelTypeState sync_model_type_state_;
@@ -60,7 +63,7 @@ bool TestPasswordSyncMetadataStore::UpdateSyncMetadata(
bool TestPasswordSyncMetadataStore::ClearSyncMetadata(
syncer::ModelType model_type,
const std::string& storage_key) {
- sync_metadata_.clear();
+ sync_metadata_.erase(storage_key);
return true;
}
@@ -96,6 +99,15 @@ void TestPasswordSyncMetadataStore::DeleteAllSyncMetadata() {
sync_metadata_.clear();
}
+void TestPasswordSyncMetadataStore::SetDeletionsHaveSyncedCallback(
+ base::RepeatingCallback<void(bool)> callback) {
+ NOTIMPLEMENTED();
+}
+
+bool TestPasswordSyncMetadataStore::HasUnsyncedDeletions() {
+ return false;
+}
+
} // namespace
TestPasswordStore::TestPasswordStore(bool is_account_store)
@@ -170,12 +182,12 @@ PasswordStoreChangeList TestPasswordStore::UpdateLoginImpl(
PasswordStoreChangeList changes;
std::vector<autofill::PasswordForm>& forms =
stored_passwords_[form.signon_realm];
- for (auto it = forms.begin(); it != forms.end(); ++it) {
- if (ArePasswordFormUniqueKeysEqual(form, *it)) {
- *it = form;
- it->in_store = is_account_store_
- ? autofill::PasswordForm::Store::kAccountStore
- : autofill::PasswordForm::Store::kProfileStore;
+ for (auto& stored_form : forms) {
+ if (ArePasswordFormUniqueKeysEqual(form, stored_form)) {
+ stored_form = form;
+ stored_form.in_store = is_account_store_
+ ? autofill::PasswordForm::Store::kAccountStore
+ : autofill::PasswordForm::Store::kProfileStore;
changes.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, form));
}
}
@@ -211,15 +223,15 @@ TestPasswordStore::FillMatchingLogins(const FormDigest& form) {
IsPublicSuffixDomainMatch(elements.first, form.signon_realm);
if (realm_matches || realm_psl_matches ||
(form.scheme == autofill::PasswordForm::Scheme::kHtml &&
- password_manager::IsFederatedRealm(elements.first, form.origin))) {
+ password_manager::IsFederatedRealm(elements.first, form.url))) {
const bool is_psl = !realm_matches && realm_psl_matches;
for (const auto& stored_form : elements.second) {
// Repeat the condition above with an additional check for origin.
if (realm_matches || realm_psl_matches ||
(form.scheme == autofill::PasswordForm::Scheme::kHtml &&
- stored_form.origin.GetOrigin() == form.origin.GetOrigin() &&
+ stored_form.url.GetOrigin() == form.url.GetOrigin() &&
password_manager::IsFederatedRealm(stored_form.signon_realm,
- form.origin))) {
+ form.url))) {
matched_forms.push_back(
std::make_unique<autofill::PasswordForm>(stored_form));
matched_forms.back()->is_public_suffix_match = is_psl;
diff --git a/chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.cc b/chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.cc
index cf7fd78a5f8..33121fcfaa5 100644
--- a/chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.cc
+++ b/chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.cc
@@ -21,7 +21,7 @@ namespace password_manager {
BulkLeakCheckServiceAdapter::BulkLeakCheckServiceAdapter(
SavedPasswordsPresenter* presenter,
- BulkLeakCheckService* service,
+ BulkLeakCheckServiceInterface* service,
PrefService* prefs)
: presenter_(presenter), service_(service), prefs_(prefs) {
DCHECK(presenter_);
@@ -37,7 +37,7 @@ BulkLeakCheckServiceAdapter::~BulkLeakCheckServiceAdapter() {
bool BulkLeakCheckServiceAdapter::StartBulkLeakCheck(
const void* key,
LeakCheckCredential::Data* data) {
- if (service_->state() == BulkLeakCheckService::State::kRunning)
+ if (service_->GetState() == BulkLeakCheckServiceInterface::State::kRunning)
return false;
// Even though the BulkLeakCheckService performs canonicalization eventually
@@ -69,9 +69,9 @@ void BulkLeakCheckServiceAdapter::StopBulkLeakCheck() {
service_->Cancel();
}
-BulkLeakCheckService::State BulkLeakCheckServiceAdapter::GetBulkLeakCheckState()
- const {
- return service_->state();
+BulkLeakCheckServiceInterface::State
+BulkLeakCheckServiceAdapter::GetBulkLeakCheckState() const {
+ return service_->GetState();
}
size_t BulkLeakCheckServiceAdapter::GetPendingChecksCount() const {
diff --git a/chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h b/chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h
index 23f0d8fbd6c..29caec471c1 100644
--- a/chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h
+++ b/chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h
@@ -5,7 +5,7 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_BULK_LEAK_CHECK_SERVICE_ADAPTER_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_BULK_LEAK_CHECK_SERVICE_ADAPTER_H_
-#include "components/password_manager/core/browser/bulk_leak_check_service.h"
+#include "components/password_manager/core/browser/bulk_leak_check_service_interface.h"
#include "components/password_manager/core/browser/leak_detection/bulk_leak_check.h"
#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
@@ -22,7 +22,7 @@ namespace password_manager {
class BulkLeakCheckServiceAdapter : public SavedPasswordsPresenter::Observer {
public:
BulkLeakCheckServiceAdapter(SavedPasswordsPresenter* presenter,
- BulkLeakCheckService* service,
+ BulkLeakCheckServiceInterface* service,
PrefService* prefs);
~BulkLeakCheckServiceAdapter() override;
@@ -39,7 +39,7 @@ class BulkLeakCheckServiceAdapter : public SavedPasswordsPresenter::Observer {
void StopBulkLeakCheck();
// Obtains the state of the bulk leak check.
- BulkLeakCheckService::State GetBulkLeakCheckState() const;
+ BulkLeakCheckServiceInterface::State GetBulkLeakCheckState() const;
// Gets the list of pending checks.
size_t GetPendingChecksCount() const;
@@ -51,7 +51,7 @@ class BulkLeakCheckServiceAdapter : public SavedPasswordsPresenter::Observer {
// Weak handles to a presenter and service, respectively. These must be not
// null and must outlive the adapter.
SavedPasswordsPresenter* presenter_ = nullptr;
- BulkLeakCheckService* service_ = nullptr;
+ BulkLeakCheckServiceInterface* service_ = nullptr;
PrefService* prefs_ = nullptr;
};
diff --git a/chromium/components/password_manager/core/browser/ui/compromised_credentials_manager.cc b/chromium/components/password_manager/core/browser/ui/compromised_credentials_manager.cc
new file mode 100644
index 00000000000..e2d92058c1c
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/ui/compromised_credentials_manager.cc
@@ -0,0 +1,269 @@
+// Copyright 2020 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/password_manager/core/browser/ui/compromised_credentials_manager.h"
+
+#include <algorithm>
+#include <iterator>
+#include <set>
+
+#include "base/containers/flat_set.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/compromised_credentials_table.h"
+#include "components/password_manager/core/browser/ui/credential_utils.h"
+#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
+
+namespace password_manager {
+
+// Extra information about CompromisedCredentials which is required by UI.
+struct CredentialMetadata {
+ std::vector<autofill::PasswordForm> forms;
+ CompromiseTypeFlags type = CompromiseTypeFlags::kNotCompromised;
+ base::Time latest_time;
+};
+
+namespace {
+
+using CredentialPasswordsMap =
+ std::map<CredentialView, CredentialMetadata, PasswordCredentialLess>;
+
+// Transparent comparator that can compare CompromisedCredentials and
+// autofill::PasswordForm.
+struct CredentialWithoutPasswordLess {
+ static std::tuple<const std::string&, const base::string16&>
+ CredentialOriginAndUsername(const autofill::PasswordForm& form) {
+ return std::tie(form.signon_realm, form.username_value);
+ }
+
+ static std::tuple<const std::string&, const base::string16&>
+ CredentialOriginAndUsername(const CompromisedCredentials& c) {
+ return std::tie(c.signon_realm, c.username);
+ }
+
+ template <typename T, typename U>
+ bool operator()(const T& lhs, const U& rhs) const {
+ return CredentialOriginAndUsername(lhs) < CredentialOriginAndUsername(rhs);
+ }
+
+ using is_transparent = void;
+};
+
+CompromiseTypeFlags ConvertCompromiseType(CompromiseType type) {
+ switch (type) {
+ case CompromiseType::kLeaked:
+ return CompromiseTypeFlags::kCredentialLeaked;
+ case CompromiseType::kPhished:
+ return CompromiseTypeFlags::kCredentialPhished;
+ }
+ NOTREACHED();
+}
+
+// This function takes two lists of compromised credentials and saved passwords
+// and joins them, producing a map that contains CredentialWithPassword as keys
+// and vector<autofill::PasswordForm> as values with CredentialCompromiseType as
+// values.
+CredentialPasswordsMap JoinCompromisedCredentialsWithSavedPasswords(
+ const std::vector<CompromisedCredentials>& credentials,
+ SavedPasswordsPresenter::SavedPasswordsView saved_passwords) {
+ CredentialPasswordsMap credentials_to_forms;
+
+ // Since a single (signon_realm, username) pair might have multiple
+ // corresponding entries in saved_passwords, we are using a multiset and doing
+ // look-up via equal_range. In most cases the resulting |range| should have a
+ // size of 1, however.
+ std::multiset<autofill::PasswordForm, CredentialWithoutPasswordLess>
+ password_forms(saved_passwords.begin(), saved_passwords.end());
+ for (const auto& credential : credentials) {
+ auto range = password_forms.equal_range(credential);
+ // Make use of a set to only filter out repeated passwords, if any.
+ std::for_each(
+ range.first, range.second, [&](const autofill::PasswordForm& form) {
+ CredentialView compromised_credential(form);
+ auto& credential_to_form =
+ credentials_to_forms[compromised_credential];
+
+ // Using |= operator to save in a bit mask both Leaked and Phished.
+ credential_to_form.type =
+ credential_to_form.type |
+ ConvertCompromiseType(credential.compromise_type);
+
+ // Use the latest time. Relevant when the same credential is both
+ // phished and compromised.
+ credential_to_form.latest_time =
+ std::max(credential_to_form.latest_time, credential.create_time);
+
+ // Populate the map. The values are vectors, because it is
+ // possible that multiple saved passwords match to the same
+ // compromised credential.
+ credential_to_form.forms.push_back(form);
+ });
+ }
+
+ return credentials_to_forms;
+}
+
+std::vector<CredentialWithPassword> ExtractCompromisedCredentials(
+ const CredentialPasswordsMap& credentials_to_forms) {
+ std::vector<CredentialWithPassword> credentials;
+ credentials.reserve(credentials_to_forms.size());
+ for (const auto& credential_to_forms : credentials_to_forms) {
+ CredentialWithPassword credential(credential_to_forms.first);
+ credential.compromise_type = credential_to_forms.second.type;
+ credential.create_time = credential_to_forms.second.latest_time;
+ credentials.push_back(std::move(credential));
+ }
+ return credentials;
+}
+
+} // namespace
+
+CredentialWithPassword::CredentialWithPassword(const CredentialView& credential)
+ : CredentialView(std::move(credential)) {}
+CredentialWithPassword::~CredentialWithPassword() = default;
+CredentialWithPassword::CredentialWithPassword(
+ const CredentialWithPassword& other) = default;
+
+CredentialWithPassword::CredentialWithPassword(CredentialWithPassword&& other) =
+ default;
+CredentialWithPassword::CredentialWithPassword(
+ const CompromisedCredentials& credential) {
+ username = credential.username;
+ signon_realm = credential.signon_realm;
+ create_time = credential.create_time;
+ compromise_type = ConvertCompromiseType(credential.compromise_type);
+}
+
+CredentialWithPassword& CredentialWithPassword::operator=(
+ const CredentialWithPassword& other) = default;
+CredentialWithPassword& CredentialWithPassword::operator=(
+ CredentialWithPassword&& other) = default;
+
+CompromisedCredentialsManager::CompromisedCredentialsManager(
+ scoped_refptr<PasswordStore> store,
+ SavedPasswordsPresenter* presenter)
+ : store_(std::move(store)), presenter_(presenter) {
+ observed_password_store_.Add(store_.get());
+ observed_saved_password_presenter_.Add(presenter_);
+}
+
+CompromisedCredentialsManager::~CompromisedCredentialsManager() = default;
+
+void CompromisedCredentialsManager::Init() {
+ store_->GetAllCompromisedCredentials(this);
+}
+
+void CompromisedCredentialsManager::SaveCompromisedCredential(
+ const LeakCheckCredential& credential) {
+ // Iterate over all currently saved credentials and mark those as compromised
+ // that have the same canonicalized username and password.
+ const base::string16 canonicalized_username =
+ CanonicalizeUsername(credential.username());
+ for (const autofill::PasswordForm& saved_password :
+ presenter_->GetSavedPasswords()) {
+ if (saved_password.password_value == credential.password() &&
+ CanonicalizeUsername(saved_password.username_value) ==
+ canonicalized_username) {
+ store_->AddCompromisedCredentials({
+ .signon_realm = saved_password.signon_realm,
+ .username = saved_password.username_value,
+ .create_time = base::Time::Now(),
+ .compromise_type = CompromiseType::kLeaked,
+ });
+ }
+ }
+}
+
+bool CompromisedCredentialsManager::UpdateCompromisedCredentials(
+ const CredentialView& credential,
+ const base::StringPiece password) {
+ auto it = credentials_to_forms_.find(credential);
+ if (it == credentials_to_forms_.end())
+ return false;
+
+ // Make sure there are matching password forms. Also erase duplicates if there
+ // are any.
+ const auto& forms = it->second.forms;
+ if (forms.empty())
+ return false;
+
+ for (size_t i = 1; i < forms.size(); ++i)
+ store_->RemoveLogin(forms[i]);
+
+ // Note: We Invoke EditPassword on the presenter rather than UpdateLogin() on
+ // the store, so that observers of the presenter get notified of this event.
+ return presenter_->EditPassword(forms[0], base::UTF8ToUTF16(password));
+}
+
+bool CompromisedCredentialsManager::RemoveCompromisedCredential(
+ const CredentialView& credential) {
+ auto it = credentials_to_forms_.find(credential);
+ if (it == credentials_to_forms_.end())
+ return false;
+
+ // Erase all matching credentials from the store. Return whether any
+ // credentials were deleted.
+ const auto& saved_passwords = it->second.forms;
+ for (const autofill::PasswordForm& saved_password : saved_passwords)
+ store_->RemoveLogin(saved_password);
+
+ return !saved_passwords.empty();
+}
+
+std::vector<CredentialWithPassword>
+CompromisedCredentialsManager::GetCompromisedCredentials() const {
+ return ExtractCompromisedCredentials(credentials_to_forms_);
+}
+
+SavedPasswordsPresenter::SavedPasswordsView
+CompromisedCredentialsManager::GetSavedPasswordsFor(
+ const CredentialView& credential) const {
+ auto it = credentials_to_forms_.find(credential);
+ return it != credentials_to_forms_.end()
+ ? it->second.forms
+ : SavedPasswordsPresenter::SavedPasswordsView();
+}
+
+void CompromisedCredentialsManager::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void CompromisedCredentialsManager::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void CompromisedCredentialsManager::OnCompromisedCredentialsChanged() {
+ // Cancel ongoing requests to the password store and issue a new request.
+ cancelable_task_tracker()->TryCancelAll();
+ store_->GetAllCompromisedCredentials(this);
+}
+
+// Re-computes the list of compromised credentials with passwords after
+// obtaining a new list of compromised credentials.
+void CompromisedCredentialsManager::OnGetCompromisedCredentials(
+ std::vector<CompromisedCredentials> compromised_credentials) {
+ compromised_credentials_ = std::move(compromised_credentials);
+ UpdateCachedDataAndNotifyObservers(presenter_->GetSavedPasswords());
+}
+
+// Re-computes the list of compromised credentials with passwords after
+// obtaining a new list of saved passwords.
+void CompromisedCredentialsManager::OnSavedPasswordsChanged(
+ SavedPasswordsPresenter::SavedPasswordsView saved_passwords) {
+ UpdateCachedDataAndNotifyObservers(saved_passwords);
+}
+
+void CompromisedCredentialsManager::UpdateCachedDataAndNotifyObservers(
+ SavedPasswordsPresenter::SavedPasswordsView saved_passwords) {
+ credentials_to_forms_ = JoinCompromisedCredentialsWithSavedPasswords(
+ compromised_credentials_, saved_passwords);
+ std::vector<CredentialWithPassword> credentials =
+ ExtractCompromisedCredentials(credentials_to_forms_);
+ for (auto& observer : observers_) {
+ observer.OnCompromisedCredentialsChanged(credentials);
+ }
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/ui/compromised_credentials_manager.h b/chromium/components/password_manager/core/browser/ui/compromised_credentials_manager.h
new file mode 100644
index 00000000000..a5578e72a84
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/ui/compromised_credentials_manager.h
@@ -0,0 +1,190 @@
+// Copyright 2020 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_PASSWORD_MANAGER_CORE_BROWSER_UI_COMPROMISED_CREDENTIALS_MANAGER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_COMPROMISED_CREDENTIALS_MANAGER_H_
+
+#include <map>
+#include <vector>
+
+#include "base/containers/span.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
+#include "base/scoped_observer.h"
+#include "base/util/type_safety/strong_alias.h"
+#include "components/password_manager/core/browser/compromised_credentials_consumer.h"
+#include "components/password_manager/core/browser/compromised_credentials_table.h"
+#include "components/password_manager/core/browser/leak_detection/bulk_leak_check.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/browser/ui/credential_utils.h"
+#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
+#include "url/gurl.h"
+
+namespace password_manager {
+
+class LeakCheckCredential;
+
+enum class CompromiseTypeFlags {
+ kNotCompromised = 0,
+ // If the credentials was leaked by a data breach.
+ kCredentialLeaked = 1 << 0,
+ // If the credentials was reused on a phishing site.
+ kCredentialPhished = 1 << 1,
+};
+
+constexpr CompromiseTypeFlags operator|(CompromiseTypeFlags lhs,
+ CompromiseTypeFlags rhs) {
+ return static_cast<CompromiseTypeFlags>(static_cast<int>(lhs) |
+ static_cast<int>(rhs));
+}
+
+// Simple struct that augments key values of CompromisedCredentials and a
+// password.
+struct CredentialView {
+ CredentialView() = default;
+ // Enable explicit construction from the autofill::PasswordForm
+ explicit CredentialView(const autofill::PasswordForm& form)
+ : signon_realm(form.signon_realm),
+ username(form.username_value),
+ password(form.password_value) {}
+
+ std::string signon_realm;
+ base::string16 username;
+ base::string16 password;
+};
+
+// All information needed by UI to represent CompromisedCredential. It's a
+// result of deduplicating CompromisedCredentials to have single entity both for
+// phished and leaked credentials with latest |create_time|, and after that
+// joining with autofill::PasswordForms to get passwords.
+struct CredentialWithPassword : CredentialView {
+ explicit CredentialWithPassword(const CredentialView& credential);
+ explicit CredentialWithPassword(const CompromisedCredentials& credential);
+
+ CredentialWithPassword(const CredentialWithPassword& other);
+ CredentialWithPassword(CredentialWithPassword&& other);
+ ~CredentialWithPassword();
+
+ CredentialWithPassword& operator=(const CredentialWithPassword& other);
+ CredentialWithPassword& operator=(CredentialWithPassword&& other);
+ base::Time create_time;
+ CompromiseTypeFlags compromise_type = CompromiseTypeFlags::kNotCompromised;
+};
+
+// Comparator that can compare CredentialView or CredentialsWithPasswords.
+struct PasswordCredentialLess {
+ bool operator()(const CredentialView& lhs, const CredentialView& rhs) const {
+ return std::tie(lhs.signon_realm, lhs.username, lhs.password) <
+ std::tie(rhs.signon_realm, rhs.username, rhs.password);
+ }
+};
+
+// Extra information about CompromisedCredentials which is required by UI.
+struct CredentialMetadata;
+
+// This class provides clients with saved compromised credentials and
+// possibility to save new LeakedCredentials, edit/delete compromised
+// credentials and match compromised credentials with corresponding
+// autofill::PasswordForms. It supports an observer interface, and clients can
+// register themselves to get notified about changes to the list.
+class CompromisedCredentialsManager
+ : public PasswordStore::DatabaseCompromisedCredentialsObserver,
+ public CompromisedCredentialsConsumer,
+ public SavedPasswordsPresenter::Observer {
+ public:
+ using CredentialsView = base::span<const CredentialWithPassword>;
+
+ // Observer interface. Clients can implement this to get notified about
+ // changes to the list of compromised credentials. Clients can register and
+ // de-register themselves, and are expected to do so before the provider gets
+ // out of scope.
+ class Observer : public base::CheckedObserver {
+ public:
+ virtual void OnCompromisedCredentialsChanged(
+ CredentialsView credentials) = 0;
+ };
+
+ explicit CompromisedCredentialsManager(scoped_refptr<PasswordStore> store,
+ SavedPasswordsPresenter* presenter);
+ ~CompromisedCredentialsManager() override;
+
+ void Init();
+
+ // Marks all saved credentials which have same username & password as
+ // compromised.
+ void SaveCompromisedCredential(const LeakCheckCredential& credential);
+
+ // Attempts to change the stored password of |credential| to |new_password|.
+ // Returns whether the change succeeded.
+ bool UpdateCompromisedCredentials(const CredentialView& credential,
+ const base::StringPiece password);
+
+ // Attempts to remove |credential| from the password store. Returns whether
+ // the remove succeeded.
+ bool RemoveCompromisedCredential(const CredentialView& credential);
+
+ // Returns a vector of currently compromised credentials.
+ std::vector<CredentialWithPassword> GetCompromisedCredentials() const;
+
+ // Returns password forms which map to provided compromised credential.
+ // In most of the cases vector will have 1 element only.
+ SavedPasswordsPresenter::SavedPasswordsView GetSavedPasswordsFor(
+ const CredentialView& credential) const;
+
+ // Allows clients and register and de-register themselves.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ private:
+ using CredentialPasswordsMap =
+ std::map<CredentialView, CredentialMetadata, PasswordCredentialLess>;
+
+ // PasswordStore::DatabaseCompromisedCredentialsObserver:
+ void OnCompromisedCredentialsChanged() override;
+
+ // CompromisedCredentialsConsumer:
+ void OnGetCompromisedCredentials(
+ std::vector<CompromisedCredentials> compromised_credentials) override;
+
+ // SavedPasswordsPresenter::Observer:
+ void OnSavedPasswordsChanged(
+ SavedPasswordsPresenter::SavedPasswordsView passwords) override;
+
+ // Function to update |credentials_to_forms_| and notify observers.
+ void UpdateCachedDataAndNotifyObservers(
+ SavedPasswordsPresenter::SavedPasswordsView saved_passwords);
+
+ // The password store containing the compromised credentials.
+ scoped_refptr<PasswordStore> store_;
+
+ // A weak handle to the presenter used to join the list of compromised
+ // credentials with saved passwords. Needs to outlive this instance.
+ SavedPasswordsPresenter* presenter_ = nullptr;
+
+ // Cache of the most recently obtained compromised credentials.
+ std::vector<CompromisedCredentials> compromised_credentials_;
+
+ // A map that matches CredentialView to corresponding PasswordForms, latest
+ // create_type and combined compromise type.
+ CredentialPasswordsMap credentials_to_forms_;
+
+ // A scoped observer for |store_| to listen changes related to
+ // CompromisedCredentials only.
+ ScopedObserver<PasswordStore,
+ PasswordStore::DatabaseCompromisedCredentialsObserver,
+ &PasswordStore::AddDatabaseCompromisedCredentialsObserver,
+ &PasswordStore::RemoveDatabaseCompromisedCredentialsObserver>
+ observed_password_store_{this};
+
+ // A scoped observer for |presenter_|.
+ ScopedObserver<SavedPasswordsPresenter, SavedPasswordsPresenter::Observer>
+ observed_saved_password_presenter_{this};
+
+ base::ObserverList<Observer, /*check_empty=*/true> observers_;
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_COMPROMISED_CREDENTIALS_MANAGER_H_
diff --git a/chromium/components/password_manager/core/browser/ui/compromised_credentials_provider_unittest.cc b/chromium/components/password_manager/core/browser/ui/compromised_credentials_manager_unittest.cc
index cc88ae687d8..114cb18d54a 100644
--- a/chromium/components/password_manager/core/browser/ui/compromised_credentials_provider_unittest.cc
+++ b/chromium/components/password_manager/core/browser/ui/compromised_credentials_manager_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/password_manager/core/browser/ui/compromised_credentials_provider.h"
+#include "components/password_manager/core/browser/ui/compromised_credentials_manager.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/string_piece_forward.h"
@@ -33,16 +33,16 @@ using ::testing::ElementsAre;
using ::testing::ElementsAreArray;
using ::testing::IsEmpty;
-struct MockCompromisedCredentialsProviderObserver
- : CompromisedCredentialsProvider::Observer {
+struct MockCompromisedCredentialsManagerObserver
+ : CompromisedCredentialsManager::Observer {
MOCK_METHOD(void,
OnCompromisedCredentialsChanged,
- (CompromisedCredentialsProvider::CredentialsView),
+ (CompromisedCredentialsManager::CredentialsView),
(override));
};
-using StrictMockCompromisedCredentialsProviderObserver =
- ::testing::StrictMock<MockCompromisedCredentialsProviderObserver>;
+using StrictMockCompromisedCredentialsManagerObserver =
+ ::testing::StrictMock<MockCompromisedCredentialsManagerObserver>;
CompromisedCredentials MakeCompromised(
base::StringPiece signon_realm,
@@ -65,37 +65,74 @@ PasswordForm MakeSavedPassword(base::StringPiece signon_realm,
return form;
}
-class CompromisedCredentialsProviderTest : public ::testing::Test {
+LeakCheckCredential MakeLeakCredential(base::StringPiece username,
+ base::StringPiece password) {
+ return LeakCheckCredential(base::ASCIIToUTF16(username),
+ base::ASCIIToUTF16(password));
+}
+
+CredentialWithPassword MakeComprmisedCredential(
+ PasswordForm form,
+ CompromisedCredentials credential) {
+ CredentialWithPassword credential_with_password((CredentialView(form)));
+ credential_with_password.create_time = credential.create_time;
+ credential_with_password.compromise_type =
+ credential.compromise_type == CompromiseType::kLeaked
+ ? CompromiseTypeFlags::kCredentialLeaked
+ : CompromiseTypeFlags::kCredentialPhished;
+ return credential_with_password;
+}
+
+class CompromisedCredentialsManagerTest : public ::testing::Test {
protected:
- CompromisedCredentialsProviderTest() { store_->Init(/*prefs=*/nullptr); }
+ CompromisedCredentialsManagerTest() { store_->Init(/*prefs=*/nullptr); }
- ~CompromisedCredentialsProviderTest() override {
+ ~CompromisedCredentialsManagerTest() override {
store_->ShutdownOnUIThread();
task_env_.RunUntilIdle();
}
TestPasswordStore& store() { return *store_; }
- CompromisedCredentialsProvider& provider() { return provider_; }
+ CompromisedCredentialsManager& provider() { return provider_; }
void RunUntilIdle() { task_env_.RunUntilIdle(); }
private:
- base::test::SingleThreadTaskEnvironment task_env_;
+ base::test::SingleThreadTaskEnvironment task_env_{
+ base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME};
scoped_refptr<TestPasswordStore> store_ =
base::MakeRefCounted<TestPasswordStore>();
SavedPasswordsPresenter presenter_{store_};
- CompromisedCredentialsProvider provider_{store_, &presenter_};
+ CompromisedCredentialsManager provider_{store_, &presenter_};
};
} // namespace
+bool operator==(const CredentialWithPassword& lhs,
+ const CredentialWithPassword& rhs) {
+ return lhs.signon_realm == rhs.signon_realm && lhs.username == rhs.username &&
+ lhs.create_time == rhs.create_time &&
+ lhs.compromise_type == rhs.compromise_type &&
+ lhs.password == rhs.password;
+}
+
+std::ostream& operator<<(std::ostream& out,
+ const CredentialWithPassword& credential) {
+ return out << "{ signon_realm: " << credential.signon_realm
+ << ", username: " << credential.username
+ << ", create_time: " << credential.create_time
+ << ", compromise_type: "
+ << static_cast<int>(credential.compromise_type)
+ << ", password: " << credential.password << " }";
+}
+
// Tests whether adding and removing an observer works as expected.
-TEST_F(CompromisedCredentialsProviderTest,
+TEST_F(CompromisedCredentialsManagerTest,
NotifyObserversAboutCompromisedCredentialChanges) {
std::vector<CompromisedCredentials> credentials = {
MakeCompromised(kExampleCom, kUsername1)};
- StrictMockCompromisedCredentialsProviderObserver observer;
+ StrictMockCompromisedCredentialsManagerObserver observer;
provider().AddObserver(&observer);
// Adding a compromised credential should notify observers.
@@ -135,14 +172,14 @@ TEST_F(CompromisedCredentialsProviderTest,
// Tests removing a compromised credentials by compromise type triggers an
// observer works as expected.
-TEST_F(CompromisedCredentialsProviderTest,
+TEST_F(CompromisedCredentialsManagerTest,
NotifyObserversAboutRemovingCompromisedCredentialsByCompromisedType) {
CompromisedCredentials phished_credentials =
MakeCompromised(kExampleCom, kUsername1, CompromiseType::kPhished);
CompromisedCredentials leaked_credentials =
MakeCompromised(kExampleCom, kUsername1, CompromiseType::kLeaked);
- StrictMockCompromisedCredentialsProviderObserver observer;
+ StrictMockCompromisedCredentialsManagerObserver observer;
provider().AddObserver(&observer);
EXPECT_CALL(observer, OnCompromisedCredentialsChanged);
store().AddCompromisedCredentials(phished_credentials);
@@ -169,9 +206,9 @@ TEST_F(CompromisedCredentialsProviderTest,
}
// Tests whether adding and removing an observer works as expected.
-TEST_F(CompromisedCredentialsProviderTest,
+TEST_F(CompromisedCredentialsManagerTest,
NotifyObserversAboutSavedPasswordsChanges) {
- StrictMockCompromisedCredentialsProviderObserver observer;
+ StrictMockCompromisedCredentialsManagerObserver observer;
provider().AddObserver(&observer);
PasswordForm saved_password =
@@ -202,7 +239,7 @@ TEST_F(CompromisedCredentialsProviderTest,
// Tests that the provider is able to join a single password with a compromised
// credential.
-TEST_F(CompromisedCredentialsProviderTest, JoinSingleCredentials) {
+TEST_F(CompromisedCredentialsManagerTest, JoinSingleCredentials) {
PasswordForm password =
MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
@@ -211,14 +248,15 @@ TEST_F(CompromisedCredentialsProviderTest, JoinSingleCredentials) {
store().AddCompromisedCredentials(credential);
RunUntilIdle();
- CredentialWithPassword expected(credential);
+ CredentialWithPassword expected =
+ MakeComprmisedCredential(password, credential);
expected.password = password.password_value;
EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
}
// Tests that the provider is able to join a password with a credential that was
// compromised in multiple ways.
-TEST_F(CompromisedCredentialsProviderTest, JoinPhishedAndLeaked) {
+TEST_F(CompromisedCredentialsManagerTest, JoinPhishedAndLeaked) {
PasswordForm password =
MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
CompromisedCredentials leaked =
@@ -231,17 +269,17 @@ TEST_F(CompromisedCredentialsProviderTest, JoinPhishedAndLeaked) {
store().AddCompromisedCredentials(phished);
RunUntilIdle();
- CredentialWithPassword expected1(leaked);
- expected1.password = password.password_value;
- CredentialWithPassword expected2(phished);
- expected2.password = password.password_value;
- EXPECT_THAT(provider().GetCompromisedCredentials(),
- ElementsAre(expected1, expected2));
+ CredentialWithPassword expected = MakeComprmisedCredential(password, leaked);
+ expected.password = password.password_value;
+ expected.compromise_type = (CompromiseTypeFlags::kCredentialLeaked |
+ CompromiseTypeFlags::kCredentialPhished);
+
+ EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
}
// Tests that the provider reacts whenever the saved passwords or the
// compromised credentials change.
-TEST_F(CompromisedCredentialsProviderTest, ReactToChangesInBothTables) {
+TEST_F(CompromisedCredentialsManagerTest, ReactToChangesInBothTables) {
std::vector<PasswordForm> passwords = {
MakeSavedPassword(kExampleCom, kUsername1, kPassword1),
MakeSavedPassword(kExampleCom, kUsername2, kPassword2)};
@@ -250,10 +288,9 @@ TEST_F(CompromisedCredentialsProviderTest, ReactToChangesInBothTables) {
MakeCompromised(kExampleCom, kUsername1),
MakeCompromised(kExampleCom, kUsername2)};
- std::vector<CredentialWithPassword> expected(credentials.begin(),
- credentials.end());
- expected[0].password = passwords[0].password_value;
- expected[1].password = passwords[1].password_value;
+ std::vector<CredentialWithPassword> expected;
+ expected.push_back(MakeComprmisedCredential(passwords[0], credentials[0]));
+ expected.push_back(MakeComprmisedCredential(passwords[1], credentials[1]));
store().AddLogin(passwords[0]);
RunUntilIdle();
@@ -283,7 +320,7 @@ TEST_F(CompromisedCredentialsProviderTest, ReactToChangesInBothTables) {
// Tests that the provider is able to join multiple passwords with compromised
// credentials.
-TEST_F(CompromisedCredentialsProviderTest, JoinMultipleCredentials) {
+TEST_F(CompromisedCredentialsManagerTest, JoinMultipleCredentials) {
std::vector<PasswordForm> passwords = {
MakeSavedPassword(kExampleCom, kUsername1, kPassword1),
MakeSavedPassword(kExampleCom, kUsername2, kPassword2)};
@@ -298,11 +335,10 @@ TEST_F(CompromisedCredentialsProviderTest, JoinMultipleCredentials) {
store().AddCompromisedCredentials(credentials[1]);
RunUntilIdle();
- CredentialWithPassword expected1(credentials[0]);
- expected1.password = passwords[0].password_value;
-
- CredentialWithPassword expected2(credentials[1]);
- expected2.password = passwords[1].password_value;
+ CredentialWithPassword expected1 =
+ MakeComprmisedCredential(passwords[0], credentials[0]);
+ CredentialWithPassword expected2 =
+ MakeComprmisedCredential(passwords[1], credentials[1]);
EXPECT_THAT(provider().GetCompromisedCredentials(),
ElementsAre(expected1, expected2));
@@ -310,7 +346,7 @@ TEST_F(CompromisedCredentialsProviderTest, JoinMultipleCredentials) {
// Tests that joining a compromised credential with saved passwords with a
// different username results in an empty list.
-TEST_F(CompromisedCredentialsProviderTest, JoinWitDifferentUsername) {
+TEST_F(CompromisedCredentialsManagerTest, JoinWitDifferentUsername) {
std::vector<PasswordForm> passwords = {
MakeSavedPassword(kExampleCom, kUsername2, kPassword1),
MakeSavedPassword(kExampleCom, kUsername2, kPassword2)};
@@ -327,7 +363,7 @@ TEST_F(CompromisedCredentialsProviderTest, JoinWitDifferentUsername) {
// Tests that joining a compromised credential with saved passwords with a
// matching username but different signon_realm results in an empty list.
-TEST_F(CompromisedCredentialsProviderTest, JoinWitDifferentSignonRealm) {
+TEST_F(CompromisedCredentialsManagerTest, JoinWitDifferentSignonRealm) {
std::vector<PasswordForm> passwords = {
MakeSavedPassword(kExampleOrg, kUsername1, kPassword1),
MakeSavedPassword(kExampleOrg, kUsername1, kPassword2)};
@@ -345,7 +381,7 @@ TEST_F(CompromisedCredentialsProviderTest, JoinWitDifferentSignonRealm) {
// Tests that joining a compromised credential with multiple saved passwords for
// the same signon_realm and username combination results in multiple entries
// when the passwords are distinct.
-TEST_F(CompromisedCredentialsProviderTest, JoinWithMultipleDistinctPasswords) {
+TEST_F(CompromisedCredentialsManagerTest, JoinWithMultipleDistinctPasswords) {
std::vector<PasswordForm> passwords = {
MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_1"),
MakeSavedPassword(kExampleCom, kUsername1, kPassword2, "element_2")};
@@ -357,11 +393,10 @@ TEST_F(CompromisedCredentialsProviderTest, JoinWithMultipleDistinctPasswords) {
store().AddCompromisedCredentials(credential);
RunUntilIdle();
- CredentialWithPassword expected1(credential);
- expected1.password = passwords[0].password_value;
-
- CredentialWithPassword expected2(credential);
- expected2.password = passwords[1].password_value;
+ CredentialWithPassword expected1 =
+ MakeComprmisedCredential(passwords[0], credential);
+ CredentialWithPassword expected2 =
+ MakeComprmisedCredential(passwords[1], credential);
EXPECT_THAT(provider().GetCompromisedCredentials(),
ElementsAre(expected1, expected2));
@@ -370,7 +405,7 @@ TEST_F(CompromisedCredentialsProviderTest, JoinWithMultipleDistinctPasswords) {
// Tests that joining a compromised credential with multiple saved passwords for
// the same signon_realm and username combination results in a single entry
// when the passwords are the same.
-TEST_F(CompromisedCredentialsProviderTest, JoinWithMultipleRepeatedPasswords) {
+TEST_F(CompromisedCredentialsManagerTest, JoinWithMultipleRepeatedPasswords) {
CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
std::vector<PasswordForm> passwords = {
MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_1"),
@@ -381,10 +416,110 @@ TEST_F(CompromisedCredentialsProviderTest, JoinWithMultipleRepeatedPasswords) {
store().AddCompromisedCredentials(credential);
RunUntilIdle();
- CredentialWithPassword expected(credential);
- expected.password = passwords[0].password_value;
+ CredentialWithPassword expected =
+ MakeComprmisedCredential(passwords[0], credential);
+
+ EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
+}
+
+// Tests that verifies mapping compromised credentials to passwords works
+// correctly.
+TEST_F(CompromisedCredentialsManagerTest, MapCompromisedPasswordsToPasswords) {
+ std::vector<PasswordForm> passwords = {
+ MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_1"),
+ MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_2"),
+ MakeSavedPassword(kExampleOrg, kUsername2, kPassword2)};
+
+ std::vector<CompromisedCredentials> credentials = {
+ MakeCompromised(kExampleCom, kUsername1),
+ MakeCompromised(kExampleOrg, kUsername2)};
+
+ std::vector<CredentialWithPassword> credentuals_with_password;
+ credentuals_with_password.push_back(
+ MakeComprmisedCredential(passwords[0], credentials[0]));
+ credentuals_with_password.push_back(
+ MakeComprmisedCredential(passwords[1], credentials[0]));
+ credentuals_with_password.push_back(
+ MakeComprmisedCredential(passwords[2], credentials[1]));
+
+ store().AddLogin(passwords[0]);
+ store().AddLogin(passwords[1]);
+ store().AddLogin(passwords[2]);
+ store().AddCompromisedCredentials(credentials[0]);
+ store().AddCompromisedCredentials(credentials[1]);
+
+ RunUntilIdle();
+ EXPECT_THAT(provider().GetSavedPasswordsFor(credentuals_with_password[0]),
+ ElementsAreArray(store().stored_passwords().at(kExampleCom)));
+
+ EXPECT_THAT(provider().GetSavedPasswordsFor(credentuals_with_password[1]),
+ ElementsAreArray(store().stored_passwords().at(kExampleCom)));
+
+ EXPECT_THAT(provider().GetSavedPasswordsFor(credentuals_with_password[2]),
+ ElementsAreArray(store().stored_passwords().at(kExampleOrg)));
+}
+
+// Test verifies that saving LeakCheckCredential via provider adds expected
+// compromised credential.
+TEST_F(CompromisedCredentialsManagerTest, SaveCompromisedPassword) {
+ PasswordForm password_form =
+ MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ LeakCheckCredential credential = MakeLeakCredential(kUsername1, kPassword1);
+ CompromisedCredentials compromised_credential =
+ MakeCompromised(kExampleCom, kUsername1);
+
+ store().AddLogin(password_form);
+ RunUntilIdle();
+
+ CredentialWithPassword expected =
+ MakeComprmisedCredential(password_form, compromised_credential);
+ expected.create_time = base::Time::Now();
+
+ provider().SaveCompromisedCredential(credential);
+ RunUntilIdle();
+
+ EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
+}
+
+// Test verifies that editing Compromised Credential via provider change the
+// original password form.
+TEST_F(CompromisedCredentialsManagerTest, UpdateCompromisedPassword) {
+ PasswordForm password_form =
+ MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
+
+ store().AddLogin(password_form);
+ store().AddCompromisedCredentials(credential);
+
+ RunUntilIdle();
+ CredentialWithPassword expected =
+ MakeComprmisedCredential(password_form, credential);
+
+ provider().UpdateCompromisedCredentials(expected, kPassword2);
+ RunUntilIdle();
+ expected.password = base::UTF8ToUTF16(kPassword2);
EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
}
+TEST_F(CompromisedCredentialsManagerTest, RemoveCompromisedCredential) {
+ CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
+ PasswordForm password =
+ MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+
+ store().AddLogin(password);
+ store().AddCompromisedCredentials(credential);
+ RunUntilIdle();
+
+ CredentialWithPassword expected =
+ MakeComprmisedCredential(password, credential);
+ expected.password = password.password_value;
+
+ EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
+
+ EXPECT_TRUE(provider().RemoveCompromisedCredential(expected));
+ RunUntilIdle();
+ EXPECT_THAT(provider().GetCompromisedCredentials(), IsEmpty());
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/ui/compromised_credentials_provider.cc b/chromium/components/password_manager/core/browser/ui/compromised_credentials_provider.cc
deleted file mode 100644
index 9478aabec58..00000000000
--- a/chromium/components/password_manager/core/browser/ui/compromised_credentials_provider.cc
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2020 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/password_manager/core/browser/ui/compromised_credentials_provider.h"
-
-#include <algorithm>
-#include <iterator>
-#include <set>
-
-#include "base/containers/flat_set.h"
-#include "base/strings/string16.h"
-#include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/browser/compromised_credentials_table.h"
-#include "components/password_manager/core/browser/ui/credential_utils.h"
-#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
-
-namespace password_manager {
-
-namespace {
-
-// Transparent comparator that can compare various types like CredentialView or
-// CompromisedCredentials.
-struct CredentialWithoutPassword {
- template <typename T, typename U>
- bool operator()(const T& lhs, const U& rhs) const {
- return std::tie(lhs.signon_realm, lhs.username) <
- std::tie(rhs.signon_realm, rhs.username);
- }
-
- using is_transparent = void;
-};
-
-// This function takes two lists of compromised credentials and saved passwords
-// and joins them, producing a new list that contains an entry for each element
-// of |saved_passwords| whose signon_realm and username are also present in
-// |compromised_credentials|.
-std::vector<CredentialWithPassword>
-JoinCompromisedCredentialsWithSavedPasswords(
- base::span<const CompromisedCredentials> compromised_credentials,
- SavedPasswordsPresenter::SavedPasswordsView saved_passwords) {
- std::vector<CredentialWithPassword> compromised_credentials_with_passwords;
- compromised_credentials_with_passwords.reserve(
- compromised_credentials.size());
-
- // Since a single (signon_realm, username) pair might have multiple
- // corresponding entries in saved_passwords, we are using a multiset and doing
- // look-up via equal_range. In most cases the resulting |range| should have a
- // size of 1, however.
- std::multiset<CredentialView, CredentialWithoutPassword> credentials(
- saved_passwords.begin(), saved_passwords.end());
- for (const auto& compromised_credential : compromised_credentials) {
- auto range = credentials.equal_range(compromised_credential);
- // Make use of a set to only filter out repeated passwords, if any.
- base::flat_set<base::string16> passwords;
- std::for_each(range.first, range.second, [&](const CredentialView& view) {
- if (passwords.insert(view.password).second) {
- compromised_credentials_with_passwords.emplace_back(
- compromised_credential);
- compromised_credentials_with_passwords.back().password = view.password;
- }
- });
- }
-
- return compromised_credentials_with_passwords;
-}
-
-} // namespace
-
-bool operator==(const CredentialWithPassword& lhs,
- const CredentialWithPassword& rhs) {
- // Upcast `lhs` to trigger the CompromisedCredentials operator==.
- return static_cast<const CompromisedCredentials&>(lhs) == rhs &&
- lhs.password == rhs.password;
-}
-
-std::ostream& operator<<(std::ostream& out,
- const CredentialWithPassword& credential) {
- return out << "{ signon_realm: " << credential.signon_realm
- << ", username: " << credential.username
- << ", create_time: " << credential.create_time
- << ", compromise_type: "
- << static_cast<int>(credential.compromise_type)
- << ", password: " << credential.password << " }";
-}
-
-CompromisedCredentialsProvider::CompromisedCredentialsProvider(
- scoped_refptr<PasswordStore> store,
- SavedPasswordsPresenter* presenter)
- : store_(std::move(store)), presenter_(presenter) {
- store_->AddDatabaseCompromisedCredentialsObserver(this);
- presenter_->AddObserver(this);
-}
-
-CompromisedCredentialsProvider::~CompromisedCredentialsProvider() {
- presenter_->RemoveObserver(this);
- store_->RemoveDatabaseCompromisedCredentialsObserver(this);
-}
-
-void CompromisedCredentialsProvider::Init() {
- store_->GetAllCompromisedCredentials(this);
-}
-
-CompromisedCredentialsProvider::CredentialsView
-CompromisedCredentialsProvider::GetCompromisedCredentials() const {
- return compromised_credentials_with_passwords_;
-}
-
-void CompromisedCredentialsProvider::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
-
-void CompromisedCredentialsProvider::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void CompromisedCredentialsProvider::OnCompromisedCredentialsChanged() {
- // Cancel ongoing requests to the password store and issue a new request.
- cancelable_task_tracker()->TryCancelAll();
- store_->GetAllCompromisedCredentials(this);
-}
-
-// Re-computes the list of compromised credentials with passwords after
-// obtaining a new list of compromised credentials.
-void CompromisedCredentialsProvider::OnGetCompromisedCredentials(
- std::vector<CompromisedCredentials> compromised_credentials) {
- compromised_credentials_ = std::move(compromised_credentials);
- compromised_credentials_with_passwords_ =
- JoinCompromisedCredentialsWithSavedPasswords(
- compromised_credentials_, presenter_->GetSavedPasswords());
- NotifyCompromisedCredentialsChanged();
-}
-
-// Re-computes the list of compromised credentials with passwords after
-// obtaining a new list of saved passwords.
-void CompromisedCredentialsProvider::OnSavedPasswordsChanged(
- SavedPasswordsPresenter::SavedPasswordsView saved_passwords) {
- compromised_credentials_with_passwords_ =
- JoinCompromisedCredentialsWithSavedPasswords(compromised_credentials_,
- saved_passwords);
- NotifyCompromisedCredentialsChanged();
-}
-
-void CompromisedCredentialsProvider::NotifyCompromisedCredentialsChanged() {
- for (auto& observer : observers_) {
- observer.OnCompromisedCredentialsChanged(
- compromised_credentials_with_passwords_);
- }
-}
-
-} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/ui/compromised_credentials_provider.h b/chromium/components/password_manager/core/browser/ui/compromised_credentials_provider.h
deleted file mode 100644
index 53d8132f404..00000000000
--- a/chromium/components/password_manager/core/browser/ui/compromised_credentials_provider.h
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2020 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_PASSWORD_MANAGER_CORE_BROWSER_UI_COMPROMISED_CREDENTIALS_PROVIDER_H_
-#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_COMPROMISED_CREDENTIALS_PROVIDER_H_
-
-#include "base/containers/span.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/observer_list.h"
-#include "base/observer_list_types.h"
-#include "base/strings/string16.h"
-#include "components/password_manager/core/browser/compromised_credentials_consumer.h"
-#include "components/password_manager/core/browser/compromised_credentials_table.h"
-#include "components/password_manager/core/browser/password_store.h"
-#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
-#include "url/gurl.h"
-
-namespace password_manager {
-
-// Simple struct that augments the CompromisedCredentials with a password.
-struct CredentialWithPassword : CompromisedCredentials {
- // Enable explicit construction from the parent struct. This will leave
- // |password| empty.
- explicit CredentialWithPassword(CompromisedCredentials credential)
- : CompromisedCredentials(std::move(credential)) {}
-
- base::string16 password;
-};
-
-bool operator==(const CredentialWithPassword& lhs,
- const CredentialWithPassword& rhs);
-
-std::ostream& operator<<(std::ostream& out,
- const CredentialWithPassword& credential);
-
-// This class provides a read-only view over saved compromised credentials. It
-// supports an observer interface, and clients can register themselves to get
-// notified about changes to the list.
-class CompromisedCredentialsProvider
- : public PasswordStore::DatabaseCompromisedCredentialsObserver,
- public CompromisedCredentialsConsumer,
- public SavedPasswordsPresenter::Observer {
- public:
-
- using CredentialsView = base::span<const CredentialWithPassword>;
-
- // Observer interface. Clients can implement this to get notified about
- // changes to the list of compromised credentials. Clients can register and
- // de-register themselves, and are expected to do so before the provider gets
- // out of scope.
- class Observer : public base::CheckedObserver {
- public:
- virtual void OnCompromisedCredentialsChanged(
- CredentialsView credentials) = 0;
- };
-
- explicit CompromisedCredentialsProvider(scoped_refptr<PasswordStore> store,
- SavedPasswordsPresenter* presenter);
- ~CompromisedCredentialsProvider() override;
-
- void Init();
-
- // Returns a read-only view over the currently compromised credentials.
- CredentialsView GetCompromisedCredentials() const;
-
- // Allows clients and register and de-register themselves.
- void AddObserver(Observer* observer);
- void RemoveObserver(Observer* observer);
-
- private:
- // PasswordStore::DatabaseCompromisedCredentialsObserver:
- void OnCompromisedCredentialsChanged() override;
-
- // CompromisedCredentialsConsumer:
- void OnGetCompromisedCredentials(
- std::vector<CompromisedCredentials> compromised_credentials) override;
-
- // SavedPasswordsPresenter::Observer:
- void OnSavedPasswordsChanged(
- SavedPasswordsPresenter::SavedPasswordsView passwords) override;
-
- // Notify observers about changes to
- // |compromised_credentials_with_passwords_|.
- void NotifyCompromisedCredentialsChanged();
-
- // The password store containing the compromised credentials.
- scoped_refptr<PasswordStore> store_;
-
- // A weak handle to the presenter used to join the list of compromised
- // credentials with saved passwords. Needs to outlive this instance.
- SavedPasswordsPresenter* presenter_ = nullptr;
-
- // Cache of the most recently obtained compromised credentials.
- std::vector<CompromisedCredentials> compromised_credentials_;
-
- // Cache of the most recently obtained compromised credentials with passwords.
- std::vector<CredentialWithPassword> compromised_credentials_with_passwords_;
-
- base::ObserverList<Observer, /*check_empty=*/true> observers_;
-};
-
-} // namespace password_manager
-
-#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_COMPROMISED_CREDENTIALS_PROVIDER_H_
diff --git a/chromium/components/password_manager/core/browser/ui/credential_utils.h b/chromium/components/password_manager/core/browser/ui/credential_utils.h
index 828d92c4a5a..b0d4240ece7 100644
--- a/chromium/components/password_manager/core/browser/ui/credential_utils.h
+++ b/chromium/components/password_manager/core/browser/ui/credential_utils.h
@@ -18,19 +18,6 @@
namespace password_manager {
-// A view over a PasswordForm that only stores the signon_realm, username and
-// password. An implicit constructor is provided for convenience.
-struct CredentialView {
- CredentialView(const autofill::PasswordForm& form)
- : signon_realm(form.signon_realm),
- username(form.username_value),
- password(form.password_value) {}
-
- std::string signon_realm;
- base::string16 username;
- base::string16 password;
-};
-
// Simple struct that stores a canonicalized credential. Allows implicit
// constructon from PasswordForm and LeakCheckCredentail for convenience.
struct CanonicalizedCredential {
@@ -52,18 +39,6 @@ inline bool operator<(const CanonicalizedCredential& lhs,
std::tie(rhs.canonicalized_username, rhs.password);
}
-// Transparent comparator that can compare various types like CredentialView or
-// CredentialsWithPasswords.
-struct PasswordCredentialLess {
- template <typename T, typename U>
- bool operator()(const T& lhs, const U& rhs) const {
- return std::tie(lhs.signon_realm, lhs.username, lhs.password) <
- std::tie(rhs.signon_realm, rhs.username, rhs.password);
- }
-
- using is_transparent = void;
-};
-
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_CREDENTIAL_UTILS_H_
diff --git a/chromium/components/password_manager/core/browser/ui/post_save_compromised_helper.cc b/chromium/components/password_manager/core/browser/ui/post_save_compromised_helper.cc
new file mode 100644
index 00000000000..1804ec99f5f
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/ui/post_save_compromised_helper.cc
@@ -0,0 +1,66 @@
+// Copyright 2020 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/password_manager/core/browser/ui/post_save_compromised_helper.h"
+
+#include "base/stl_util.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_service.h"
+
+namespace password_manager {
+
+// Maximum time since the last password check while the result is considered
+// up to date.
+constexpr auto kMaxTimeSinceLastCheck = base::TimeDelta::FromMinutes(30);
+
+PostSaveCompromisedHelper::PostSaveCompromisedHelper(
+ base::span<const CompromisedCredentials> compromised,
+ const base::string16& current_username) {
+ for (const CompromisedCredentials& credential : compromised) {
+ if (credential.username == current_username)
+ current_leak_ = credential;
+ }
+}
+
+PostSaveCompromisedHelper::~PostSaveCompromisedHelper() = default;
+
+void PostSaveCompromisedHelper::AnalyzeLeakedCredentials(
+ PasswordStore* store,
+ PrefService* prefs,
+ BubbleCallback callback) {
+ DCHECK(store);
+ DCHECK(prefs);
+ callback_ = std::move(callback);
+ prefs_ = prefs;
+ store->GetAllCompromisedCredentials(this);
+}
+
+void PostSaveCompromisedHelper::OnGetCompromisedCredentials(
+ std::vector<CompromisedCredentials> compromised_credentials) {
+ const bool compromised_password_changed =
+ current_leak_ && !base::Contains(compromised_credentials, *current_leak_);
+ bubble_type_ = BubbleType::kNoBubble;
+ if (compromised_credentials.empty()) {
+ if (compromised_password_changed) {
+ // Obtain the timestamp of the last completed check. This is 0.0 in case
+ // the check never completely ran before.
+ const double last_check_completed =
+ prefs_->GetDouble(prefs::kLastTimePasswordCheckCompleted);
+ if (last_check_completed &&
+ base::Time::Now() - base::Time::FromDoubleT(last_check_completed) <
+ kMaxTimeSinceLastCheck) {
+ bubble_type_ = BubbleType::kPasswordUpdatedSafeState;
+ }
+ }
+ } else {
+ bubble_type_ = compromised_password_changed
+ ? BubbleType::kPasswordUpdatedWithMoreToFix
+ : BubbleType::kUnsafeState;
+ }
+ compromised_count_ = compromised_credentials.size();
+ std::move(callback_).Run(bubble_type_, compromised_count_);
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/ui/post_save_compromised_helper.h b/chromium/components/password_manager/core/browser/ui/post_save_compromised_helper.h
new file mode 100644
index 00000000000..bdd9d4ded7c
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/ui/post_save_compromised_helper.h
@@ -0,0 +1,80 @@
+// Copyright 2020 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_PASSWORD_MANAGER_CORE_BROWSER_UI_POST_SAVE_COMPROMISED_HELPER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_POST_SAVE_COMPROMISED_HELPER_H_
+
+#include "base/callback.h"
+#include "base/containers/span.h"
+#include "base/optional.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "components/password_manager/core/browser/compromised_credentials_consumer.h"
+#include "components/password_manager/core/browser/compromised_credentials_table.h"
+
+class PrefService;
+
+namespace password_manager {
+
+class PasswordStore;
+
+// Helps to choose a compromised credential bubble after a password was saved.
+class PostSaveCompromisedHelper : public CompromisedCredentialsConsumer {
+ public:
+ enum class BubbleType {
+ // No follow-up bubble should be shown.
+ kNoBubble,
+ // Last compromised password was updated and the password check completed
+ // recently. The user is presumed safe.
+ kPasswordUpdatedSafeState,
+ // A compromised password was updated and there are more issues to fix.
+ kPasswordUpdatedWithMoreToFix,
+ // A random password was saved/updated. There are stored compromised
+ // credentials.
+ kUnsafeState,
+ };
+
+ // The callback is told which bubble to bring up and how many compromised
+ // credentials in total should be still fixed.
+ using BubbleCallback = base::OnceCallback<void(BubbleType, size_t)>;
+
+ // |compromised| contains all compromised credentials for the current site.
+ // |current_username| is the username that was just saved or updated.
+ PostSaveCompromisedHelper(
+ base::span<const CompromisedCredentials> compromised,
+ const base::string16& current_username);
+ ~PostSaveCompromisedHelper() override;
+
+ PostSaveCompromisedHelper(const PostSaveCompromisedHelper&) = delete;
+ PostSaveCompromisedHelper& operator=(const PostSaveCompromisedHelper&) =
+ delete;
+
+ // Asynchronously queries the password store for the compromised credentials
+ // and notifies |callback| with the result of analysis.
+ void AnalyzeLeakedCredentials(PasswordStore* store,
+ PrefService* prefs,
+ BubbleCallback callback);
+
+ BubbleType bubble_type() const { return bubble_type_; }
+ size_t compromised_count() const { return compromised_count_; }
+
+ private:
+ void OnGetCompromisedCredentials(
+ std::vector<CompromisedCredentials> compromised_credentials) override;
+
+ // Contains the entry for the currently leaked credentials if it was leaked.
+ base::Optional<CompromisedCredentials> current_leak_;
+ // Profile prefs.
+ PrefService* prefs_ = nullptr;
+ // Callback to notify the caller about the bubble type.
+ BubbleCallback callback_;
+ // BubbleType after the callback was executed.
+ BubbleType bubble_type_ = BubbleType::kNoBubble;
+ // Count of compromised credentials after the callback was executed.
+ size_t compromised_count_ = 0;
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_POST_SAVE_COMPROMISED_HELPER_H_
diff --git a/chromium/components/password_manager/core/browser/ui/post_save_compromised_helper_unittest.cc b/chromium/components/password_manager/core/browser/ui/post_save_compromised_helper_unittest.cc
new file mode 100644
index 00000000000..80bff25b570
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/ui/post_save_compromised_helper_unittest.cc
@@ -0,0 +1,169 @@
+// Copyright 2020 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/password_manager/core/browser/ui/post_save_compromised_helper.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
+#include "components/password_manager/core/browser/mock_password_store.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+namespace {
+
+using BubbleType = PostSaveCompromisedHelper::BubbleType;
+using prefs::kLastTimePasswordCheckCompleted;
+using testing::Return;
+
+constexpr char kSignonRealm[] = "https://example.com/";
+constexpr char kUsername[] = "user";
+constexpr char kUsername2[] = "user2";
+
+CompromisedCredentials CreateCompromised(base::StringPiece username) {
+ return CompromisedCredentials{
+ .signon_realm = kSignonRealm,
+ .username = base::ASCIIToUTF16(username),
+ .compromise_type = CompromiseType::kLeaked,
+ };
+}
+
+} // namespace
+
+class PostSaveCompromisedHelperTest : public testing::Test {
+ public:
+ PostSaveCompromisedHelperTest() {
+ mock_store_ = new MockPasswordStore;
+ EXPECT_TRUE(mock_store_->Init(&prefs_));
+ prefs_.registry()->RegisterDoublePref(kLastTimePasswordCheckCompleted, 0.0);
+ }
+
+ ~PostSaveCompromisedHelperTest() override {
+ mock_store_->ShutdownOnUIThread();
+ }
+
+ void WaitForPasswordStore() { task_environment_.RunUntilIdle(); }
+
+ MockPasswordStore* store() { return mock_store_.get(); }
+ TestingPrefServiceSimple* prefs() { return &prefs_; }
+
+ private:
+ base::test::SingleThreadTaskEnvironment task_environment_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+ scoped_refptr<MockPasswordStore> mock_store_;
+ TestingPrefServiceSimple prefs_;
+};
+
+TEST_F(PostSaveCompromisedHelperTest, DefaultState) {
+ PostSaveCompromisedHelper helper({}, base::ASCIIToUTF16(kUsername));
+ EXPECT_EQ(BubbleType::kNoBubble, helper.bubble_type());
+ EXPECT_EQ(0u, helper.compromised_count());
+}
+
+TEST_F(PostSaveCompromisedHelperTest, EmptyStore) {
+ PostSaveCompromisedHelper helper({}, base::ASCIIToUTF16(kUsername));
+ base::MockCallback<PostSaveCompromisedHelper::BubbleCallback> callback;
+ EXPECT_CALL(callback, Run(BubbleType::kNoBubble, 0));
+ EXPECT_CALL(*store(), GetAllCompromisedCredentialsImpl);
+ helper.AnalyzeLeakedCredentials(store(), prefs(), callback.Get());
+ WaitForPasswordStore();
+ EXPECT_EQ(BubbleType::kNoBubble, helper.bubble_type());
+ EXPECT_EQ(0u, helper.compromised_count());
+}
+
+TEST_F(PostSaveCompromisedHelperTest, RandomSite_FullStore) {
+ PostSaveCompromisedHelper helper({}, base::ASCIIToUTF16(kUsername));
+ base::MockCallback<PostSaveCompromisedHelper::BubbleCallback> callback;
+ EXPECT_CALL(callback, Run(BubbleType::kUnsafeState, 1));
+ std::vector<CompromisedCredentials> saved = {CreateCompromised(kUsername2)};
+ EXPECT_CALL(*store(), GetAllCompromisedCredentialsImpl)
+ .WillOnce(Return(saved));
+ helper.AnalyzeLeakedCredentials(store(), prefs(), callback.Get());
+ WaitForPasswordStore();
+ EXPECT_EQ(BubbleType::kUnsafeState, helper.bubble_type());
+ EXPECT_EQ(1u, helper.compromised_count());
+}
+
+TEST_F(PostSaveCompromisedHelperTest, CompromisedSite_ItemStayed) {
+ std::vector<CompromisedCredentials> saved = {CreateCompromised(kUsername),
+ CreateCompromised(kUsername2)};
+ PostSaveCompromisedHelper helper({saved}, base::ASCIIToUTF16(kUsername));
+ base::MockCallback<PostSaveCompromisedHelper::BubbleCallback> callback;
+ EXPECT_CALL(callback, Run(BubbleType::kUnsafeState, 2));
+ EXPECT_CALL(*store(), GetAllCompromisedCredentialsImpl)
+ .WillOnce(Return(saved));
+ helper.AnalyzeLeakedCredentials(store(), prefs(), callback.Get());
+ WaitForPasswordStore();
+ EXPECT_EQ(BubbleType::kUnsafeState, helper.bubble_type());
+ EXPECT_EQ(2u, helper.compromised_count());
+}
+
+TEST_F(PostSaveCompromisedHelperTest, CompromisedSite_ItemGone) {
+ std::vector<CompromisedCredentials> saved = {CreateCompromised(kUsername),
+ CreateCompromised(kUsername2)};
+ PostSaveCompromisedHelper helper({saved}, base::ASCIIToUTF16(kUsername));
+ base::MockCallback<PostSaveCompromisedHelper::BubbleCallback> callback;
+ EXPECT_CALL(callback, Run(BubbleType::kPasswordUpdatedWithMoreToFix, 1));
+ saved = {CreateCompromised(kUsername2)};
+ EXPECT_CALL(*store(), GetAllCompromisedCredentialsImpl)
+ .WillOnce(Return(saved));
+ helper.AnalyzeLeakedCredentials(store(), prefs(), callback.Get());
+ WaitForPasswordStore();
+ EXPECT_EQ(BubbleType::kPasswordUpdatedWithMoreToFix, helper.bubble_type());
+ EXPECT_EQ(1u, helper.compromised_count());
+}
+
+TEST_F(PostSaveCompromisedHelperTest, FixedLast_BulkCheckNeverDone) {
+ std::vector<CompromisedCredentials> saved = {CreateCompromised(kUsername)};
+ PostSaveCompromisedHelper helper({saved}, base::ASCIIToUTF16(kUsername));
+ base::MockCallback<PostSaveCompromisedHelper::BubbleCallback> callback;
+ EXPECT_CALL(callback, Run(BubbleType::kNoBubble, 0));
+ saved = {};
+ EXPECT_CALL(*store(), GetAllCompromisedCredentialsImpl)
+ .WillOnce(Return(saved));
+ helper.AnalyzeLeakedCredentials(store(), prefs(), callback.Get());
+ WaitForPasswordStore();
+ EXPECT_EQ(BubbleType::kNoBubble, helper.bubble_type());
+ EXPECT_EQ(0u, helper.compromised_count());
+}
+
+TEST_F(PostSaveCompromisedHelperTest, FixedLast_BulkCheckDoneLongAgo) {
+ prefs()->SetDouble(
+ kLastTimePasswordCheckCompleted,
+ (base::Time::Now() - base::TimeDelta::FromDays(5)).ToDoubleT());
+ std::vector<CompromisedCredentials> saved = {CreateCompromised(kUsername)};
+ PostSaveCompromisedHelper helper({saved}, base::ASCIIToUTF16(kUsername));
+ base::MockCallback<PostSaveCompromisedHelper::BubbleCallback> callback;
+ EXPECT_CALL(callback, Run(BubbleType::kNoBubble, 0));
+ saved = {};
+ EXPECT_CALL(*store(), GetAllCompromisedCredentialsImpl)
+ .WillOnce(Return(saved));
+ helper.AnalyzeLeakedCredentials(store(), prefs(), callback.Get());
+ WaitForPasswordStore();
+ EXPECT_EQ(BubbleType::kNoBubble, helper.bubble_type());
+ EXPECT_EQ(0u, helper.compromised_count());
+}
+
+TEST_F(PostSaveCompromisedHelperTest, FixedLast_BulkCheckDoneRecently) {
+ prefs()->SetDouble(
+ kLastTimePasswordCheckCompleted,
+ (base::Time::Now() - base::TimeDelta::FromMinutes(1)).ToDoubleT());
+ std::vector<CompromisedCredentials> saved = {CreateCompromised(kUsername)};
+ PostSaveCompromisedHelper helper({saved}, base::ASCIIToUTF16(kUsername));
+ base::MockCallback<PostSaveCompromisedHelper::BubbleCallback> callback;
+ EXPECT_CALL(callback, Run(BubbleType::kPasswordUpdatedSafeState, 0));
+ saved = {};
+ EXPECT_CALL(*store(), GetAllCompromisedCredentialsImpl)
+ .WillOnce(Return(saved));
+ helper.AnalyzeLeakedCredentials(store(), prefs(), callback.Get());
+ WaitForPasswordStore();
+ EXPECT_EQ(BubbleType::kPasswordUpdatedSafeState, helper.bubble_type());
+ EXPECT_EQ(0u, helper.compromised_count());
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/votes_uploader.cc b/chromium/components/password_manager/core/browser/votes_uploader.cc
index 6ef392a67ae..622c8a6751f 100644
--- a/chromium/components/password_manager/core/browser/votes_uploader.cc
+++ b/chromium/components/password_manager/core/browser/votes_uploader.cc
@@ -523,7 +523,7 @@ void VotesUploader::AddGeneratedVote(FormStructure* form_structure) {
DCHECK(form_structure);
DCHECK(generation_popup_was_shown_);
- if (generation_element_.empty())
+ if (!generation_element_)
return;
AutofillUploadContents::Field::PasswordGenerationType type =
@@ -551,7 +551,7 @@ void VotesUploader::AddGeneratedVote(FormStructure* form_structure) {
for (size_t i = 0; i < form_structure->field_count(); ++i) {
AutofillField* field = form_structure->field(i);
- if (field->name == generation_element_) {
+ if (field->unique_renderer_id == generation_element_) {
field->set_generation_type(type);
if (has_generated_password_) {
field->set_generated_password_changed(generated_password_changed_);
diff --git a/chromium/components/password_manager/core/browser/votes_uploader.h b/chromium/components/password_manager/core/browser/votes_uploader.h
index bac1c279848..ef5bc256dac 100644
--- a/chromium/components/password_manager/core/browser/votes_uploader.h
+++ b/chromium/components/password_manager/core/browser/votes_uploader.h
@@ -130,11 +130,11 @@ class VotesUploader {
is_manual_generation_ = is_manual_generation;
}
- const base::string16& get_generation_element() const {
+ autofill::FieldRendererId get_generation_element() const {
return generation_element_;
}
- void set_generation_element(const base::string16& generation_element) {
+ void set_generation_element(autofill::FieldRendererId generation_element) {
generation_element_ = generation_element;
}
@@ -213,8 +213,7 @@ class VotesUploader {
bool is_manual_generation_ = false;
// A password field name that is used for generation.
- // TODO(crbug.com/1075444): Use unique renderer id of a field instead.
- base::string16 generation_element_;
+ autofill::FieldRendererId generation_element_;
// True iff a user edited the username value in a prompt and new username is
// the value of another field of the observed form.
diff --git a/chromium/components/password_manager/core/browser/votes_uploader_unittest.cc b/chromium/components/password_manager/core/browser/votes_uploader_unittest.cc
index ab1c10bbd1a..d8cb59ea3dc 100644
--- a/chromium/components/password_manager/core/browser/votes_uploader_unittest.cc
+++ b/chromium/components/password_manager/core/browser/votes_uploader_unittest.cc
@@ -82,7 +82,7 @@ class MockAutofillDownloadManager : public AutofillDownloadManager {
class StubObserver : public AutofillDownloadManager::Observer {
void OnLoadedServerPredictions(
std::string response,
- const std::vector<std::string>& form_signatures) override {}
+ const autofill::FormAndFieldSignatures& form_signatures) override {}
};
StubObserver fake_observer;
diff --git a/chromium/components/password_manager/core/common/credential_manager_types.cc b/chromium/components/password_manager/core/common/credential_manager_types.cc
index 6d90c1e7dee..ff5a5da4c0f 100644
--- a/chromium/components/password_manager/core/common/credential_manager_types.cc
+++ b/chromium/components/password_manager/core/common/credential_manager_types.cc
@@ -4,6 +4,8 @@
#include "components/password_manager/core/common/credential_manager_types.h"
+#include <memory>
+
#include "base/strings/string_number_conversions.h"
#include "components/autofill/core/common/password_form.h"
@@ -53,8 +55,7 @@ CredentialInfo::CredentialInfo(const autofill::PasswordForm& form,
CredentialInfo::CredentialInfo(const CredentialInfo& other) = default;
-CredentialInfo::~CredentialInfo() {
-}
+CredentialInfo::~CredentialInfo() = default;
bool CredentialInfo::operator==(const CredentialInfo& rhs) const {
return (type == rhs.type && id == rhs.id && name == rhs.name &&
@@ -64,16 +65,16 @@ bool CredentialInfo::operator==(const CredentialInfo& rhs) const {
std::unique_ptr<autofill::PasswordForm> CreatePasswordFormFromCredentialInfo(
const CredentialInfo& info,
- const GURL& origin) {
+ const url::Origin& origin) {
std::unique_ptr<autofill::PasswordForm> form;
if (info.type == CredentialType::CREDENTIAL_TYPE_EMPTY)
return form;
- form.reset(new autofill::PasswordForm);
+ form = std::make_unique<autofill::PasswordForm>();
form->icon_url = info.icon;
form->display_name = info.name.value_or(base::string16());
form->federation_origin = info.federation;
- form->origin = origin;
+ form->url = origin.GetURL();
form->password_value = info.password.value_or(base::string16());
form->username_value = info.id.value_or(base::string16());
form->scheme = autofill::PasswordForm::Scheme::kHtml;
@@ -81,7 +82,7 @@ std::unique_ptr<autofill::PasswordForm> CreatePasswordFormFromCredentialInfo(
form->signon_realm =
info.type == CredentialType::CREDENTIAL_TYPE_PASSWORD
- ? origin.GetOrigin().spec()
+ ? form->url.spec()
: "federation://" + origin.host() + "/" + info.federation.host();
return form;
}
diff --git a/chromium/components/password_manager/core/common/credential_manager_types.h b/chromium/components/password_manager/core/common/credential_manager_types.h
index b50567f6592..b4fd4e95962 100644
--- a/chromium/components/password_manager/core/common/credential_manager_types.h
+++ b/chromium/components/password_manager/core/common/credential_manager_types.h
@@ -80,7 +80,7 @@ struct CredentialInfo {
// CREDENTIAL_TYPE_EMPTY.
std::unique_ptr<autofill::PasswordForm> CreatePasswordFormFromCredentialInfo(
const CredentialInfo& info,
- const GURL& origin);
+ const url::Origin& origin);
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/credential_manager_types_unittest.cc b/chromium/components/password_manager/core/common/credential_manager_types_unittest.cc
index e0ccf39f045..169faefe3b7 100644
--- a/chromium/components/password_manager/core/common/credential_manager_types_unittest.cc
+++ b/chromium/components/password_manager/core/common/credential_manager_types_unittest.cc
@@ -16,12 +16,12 @@ namespace password_manager {
class CredentialManagerTypesTest : public testing::Test {
public:
CredentialManagerTypesTest()
- : origin_(GURL("https://example.test/")),
+ : origin_(url::Origin::Create(GURL("https://example.test/"))),
icon_(GURL("https://fast-cdn.test/icon.png")),
federation_(url::Origin::Create(GURL("https://federation.test/"))) {}
protected:
- GURL origin_;
+ url::Origin origin_;
GURL icon_;
url::Origin federation_;
};
@@ -51,7 +51,7 @@ TEST_F(CredentialManagerTypesTest, CreatePasswordFormFederation) {
EXPECT_EQ(autofill::PasswordForm::Type::kApi, form->type);
EXPECT_EQ(info.icon, form->icon_url);
EXPECT_EQ(info.name, form->display_name);
- EXPECT_EQ(origin_, form->origin);
+ EXPECT_EQ(origin_.GetURL(), form->url);
EXPECT_EQ(autofill::PasswordForm::Scheme::kHtml, form->scheme);
// Federated credentials have empty passwords, non-empty federation_origins,
@@ -76,14 +76,14 @@ TEST_F(CredentialManagerTypesTest, CreatePasswordFormLocal) {
EXPECT_EQ(info.icon, form->icon_url);
EXPECT_EQ(info.name, form->display_name);
- EXPECT_EQ(origin_, form->origin);
+ EXPECT_EQ(origin_.GetURL().spec(), form->url);
EXPECT_EQ(autofill::PasswordForm::Scheme::kHtml, form->scheme);
// Local credentials have empty federation_origins, non-empty passwords, and
// a signon realm that matches the origin.
EXPECT_TRUE(form->federation_origin.opaque());
EXPECT_EQ(info.password, form->password_value);
- EXPECT_EQ(origin_.spec(), form->signon_realm);
+ EXPECT_EQ(origin_.GetURL().spec(), form->signon_realm);
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/password_manager_features.cc b/chromium/components/password_manager/core/common/password_manager_features.cc
index 04e63e92dcc..c85f0c83240 100644
--- a/chromium/components/password_manager/core/common/password_manager_features.cc
+++ b/chromium/components/password_manager/core/common/password_manager_features.cc
@@ -4,6 +4,8 @@
#include "components/password_manager/core/common/password_manager_features.h"
+#include "build/build_config.h"
+
namespace password_manager {
// NOTE: It is strongly recommended to use UpperCamelCase style for feature
@@ -15,6 +17,11 @@ namespace features {
const base::Feature kBiometricTouchToFill = {"BiometricTouchToFill",
base::FEATURE_DISABLED_BY_DEFAULT};
+// After saving/updating a password show a bubble reminder about the status of
+// other compromised credentials.
+const base::Feature kCompromisedPasswordsReengagement = {
+ "CompromisedPasswordsReengagement", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enables the editing of passwords in chrome://settings/passwords, i.e. the
// Desktop passwords settings page.
const base::Feature kEditPasswordsInDesktopSettings = {
@@ -54,7 +61,12 @@ const base::Feature kPasswordChange = {"PasswordChange",
// Enables the bulk Password Check feature for signed in users.
const base::Feature kPasswordCheck = {"PasswordCheck",
- base::FEATURE_DISABLED_BY_DEFAULT};
+#if defined(OS_ANDROID) || defined(OS_IOS)
+ base::FEATURE_DISABLED_BY_DEFAULT
+#else
+ base::FEATURE_ENABLED_BY_DEFAULT
+#endif
+};
// Enables editing saved passwords for Android.
const base::Feature kPasswordEditingAndroid = {
@@ -78,6 +90,10 @@ const base::Feature kRecoverFromNeverSaveAndroid = {
const base::Feature kUsernameFirstFlow = {"UsernameFirstFlow",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Enable support for .well-known/change-password URLs.
+const base::Feature kWellKnownChangePassword = {
+ "WellKnownChangePassword", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Field trial identifier for password generation requirements.
const char kGenerationRequirementsFieldTrial[] =
"PasswordGenerationRequirements";
@@ -98,6 +114,10 @@ const char kGenerationRequirementsPrefixLength[] = "prefix_length";
// Default to 5000 ms.
const char kGenerationRequirementsTimeout[] = "timeout";
+// Enables showing leaked dialog after every successful form submission.
+const char kPasswordChangeWithForcedDialogAfterEverySuccessfulSubmission[] =
+ "should_force_dialog_after_every_sucessful_form_submission";
+
} // namespace features
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/password_manager_features.h b/chromium/components/password_manager/core/common/password_manager_features.h
index e7c8ee3ad5a..7ad602aa0b0 100644
--- a/chromium/components/password_manager/core/common/password_manager_features.h
+++ b/chromium/components/password_manager/core/common/password_manager_features.h
@@ -18,6 +18,7 @@ namespace features {
// alongside the definition of their values in the .cc file.
extern const base::Feature kBiometricTouchToFill;
+extern const base::Feature kCompromisedPasswordsReengagement;
extern const base::Feature kEditPasswordsInDesktopSettings;
extern const base::Feature kDeleteCorruptedPasswords;
extern const base::Feature kEnableOverwritingPlaceholderUsernames;
@@ -32,6 +33,7 @@ extern const base::Feature kPasswordImport;
extern const base::Feature kPasswordManagerOnboardingAndroid;
extern const base::Feature kRecoverFromNeverSaveAndroid;
extern const base::Feature kUsernameFirstFlow;
+extern const base::Feature kWellKnownChangePassword;
// Field trial and corresponding parameters.
// To manually override this, start Chrome with the following parameters:
@@ -45,6 +47,12 @@ extern const char kGenerationRequirementsVersion[];
extern const char kGenerationRequirementsPrefixLength[];
extern const char kGenerationRequirementsTimeout[];
+// Password change feature variation.
+// The new variation will allow showing credential leaked dialog after
+// every form submission (helpful for testing).
+extern const char
+ kPasswordChangeWithForcedDialogAfterEverySuccessfulSubmission[];
+
} // namespace features
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/password_manager_pref_names.cc b/chromium/components/password_manager/core/common/password_manager_pref_names.cc
index 9cac5d4b33d..c64c046fdff 100644
--- a/chromium/components/password_manager/core/common/password_manager_pref_names.cc
+++ b/chromium/components/password_manager/core/common/password_manager_pref_names.cc
@@ -63,5 +63,10 @@ const char kPasswordLeakDetectionEnabled[] =
const char kWasOnboardingFeatureCheckedBefore[] =
"profile.was_pwm_onboarding_feature_checked_before";
+const char kProfileStoreDateLastUsedForFilling[] =
+ "password_manager.profile_store_date_last_used_for_filling";
+const char kAccountStoreDateLastUsedForFilling[] =
+ "password_manager.account_store_date_last_used_for_filling";
+
} // namespace prefs
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/password_manager_pref_names.h b/chromium/components/password_manager/core/common/password_manager_pref_names.h
index 0f45890c207..4f350f60e8b 100644
--- a/chromium/components/password_manager/core/common/password_manager_pref_names.h
+++ b/chromium/components/password_manager/core/common/password_manager_pref_names.h
@@ -99,6 +99,11 @@ extern const char kPasswordLeakDetectionEnabled[];
// subsequent feature checks to ensure data completeness.
extern const char kWasOnboardingFeatureCheckedBefore[];
+// Timestamps of when credentials from the profile / account store were last
+// used to fill a form, in microseconds since Windows epoch.
+extern const char kProfileStoreDateLastUsedForFilling[];
+extern const char kAccountStoreDateLastUsedForFilling[];
+
} // namespace prefs
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/password_manager_ui.h b/chromium/components/password_manager/core/common/password_manager_ui.h
index 28c077ca476..ce1a22c2a1f 100644
--- a/chromium/components/password_manager/core/common/password_manager_ui.h
+++ b/chromium/components/password_manager/core/common/password_manager_ui.h
@@ -46,6 +46,15 @@ enum State {
// The user used a profile credential to log in successfully and should see a
// prompt that allows them to move the credential to their account store.
CAN_MOVE_PASSWORD_TO_ACCOUNT_STATE,
+
+ // Last compromised password was updated and the user is safe.
+ PASSWORD_UPDATED_SAFE_STATE,
+
+ // A compromised password was updated and the user has more to fix.
+ PASSWORD_UPDATED_MORE_TO_FIX,
+
+ // Remind the user to fix the compromised passwords.
+ PASSWORD_UPDATED_UNSAFE_STATE,
};
} // namespace ui
diff --git a/chromium/components/password_manager/ios/account_select_fill_data.cc b/chromium/components/password_manager/ios/account_select_fill_data.cc
index 5b0ad486c51..158bdd81ca9 100644
--- a/chromium/components/password_manager/ios/account_select_fill_data.cc
+++ b/chromium/components/password_manager/ios/account_select_fill_data.cc
@@ -33,7 +33,7 @@ void AccountSelectFillData::Add(
auto iter_ok = forms_.insert(
std::make_pair(form_data.form_renderer_id.value(), FormInfo()));
FormInfo& form_info = iter_ok.first->second;
- form_info.origin = form_data.origin;
+ form_info.origin = form_data.url;
form_info.form_id = form_data.form_renderer_id;
form_info.username_element_id = form_data.username_field.unique_renderer_id;
form_info.password_element_id = form_data.password_field.unique_renderer_id;
diff --git a/chromium/components/password_manager/ios/account_select_fill_data_unittest.cc b/chromium/components/password_manager/ios/account_select_fill_data_unittest.cc
index 1e0018f25fd..92d0c38d8af 100644
--- a/chromium/components/password_manager/ios/account_select_fill_data_unittest.cc
+++ b/chromium/components/password_manager/ios/account_select_fill_data_unittest.cc
@@ -197,7 +197,7 @@ TEST_F(AccountSelectFillDataTest, GetFillData) {
base::ASCIIToUTF16(kUsernames[1]));
ASSERT_TRUE(fill_data);
- EXPECT_EQ(form_data.origin, fill_data->origin);
+ EXPECT_EQ(form_data.url, fill_data->origin);
EXPECT_EQ(form_data.form_renderer_id.value(), fill_data->form_id.value());
EXPECT_EQ(kUsernameUniqueIDs[form_i],
fill_data->username_element_id.value());
diff --git a/chromium/components/password_manager/ios/js_password_manager.h b/chromium/components/password_manager/ios/js_password_manager.h
index ebd5a2575d4..834d8e17143 100644
--- a/chromium/components/password_manager/ios/js_password_manager.h
+++ b/chromium/components/password_manager/ios/js_password_manager.h
@@ -7,7 +7,7 @@
#include "base/ios/block_types.h"
#include "components/autofill/core/common/renderer_id.h"
-#import "ios/web/public/deprecated/crw_js_injection_receiver.h"
+#include "ios/web/public/js_messaging/web_frame.h"
namespace autofill {
struct PasswordFormFillData;
@@ -17,13 +17,12 @@ namespace password_manager {
struct FillData;
-// Serializes |fillData| into a JSON string that can be used by the JS side
-// of PasswordController.
-NSString* SerializeFillData(const password_manager::FillData& fillData);
+// Serializes |fillData| so it can be used by the JS side of PasswordController.
+std::unique_ptr<base::Value> SerializeFillData(
+ const password_manager::FillData& fillData);
-// Serializes |formData| into a JSON string that can be used by the JS side
-// of PasswordController.
-NSString* SerializePasswordFormFillData(
+// Serializes |formData| so it can be used by the JS side of PasswordController.
+std::unique_ptr<base::Value> SerializePasswordFormFillData(
const autofill::PasswordFormFillData& formData);
} // namespace password_manager
@@ -42,8 +41,8 @@ NSString* SerializePasswordFormFillData(
// For example the JSON string for a form with a single password field is:
// [{"action":null,"method":null,"usernameElement":"","usernameValue":"","
// passwords":[{"element":"","value":"asd"}]}]
-- (void)findPasswordFormsWithCompletionHandler:
- (void (^)(NSString*))completionHandler;
+- (void)findPasswordFormsInFrame:(web::WebFrame*)frame
+ completionHandler:(void (^)(NSString*))completionHandler;
// Extracts the password form with the given name from a web page.
// |completionHandler| is called with the JSON string containing the info about
@@ -53,6 +52,7 @@ NSString* SerializePasswordFormFillData(
// {"action":null,"method":null,"usernameElement":"","usernameValue":"",
// "passwords":[{"element":"","value":"asd"}]}
- (void)extractForm:(autofill::FormRendererId)formIdentifier
+ inFrame:(web::WebFrame*)frame
completionHandler:(void (^)(NSString*))completionHandler;
// Fills in the password form specified by |JSONString| with the given
@@ -61,30 +61,27 @@ NSString* SerializePasswordFormFillData(
// |extractSubmittedFormWithCompletionHandler|. Calls |completionHandler| with
// YES if the filling of the password was successful, NO otherwise.
// |completionHandler| cannot be nil.
-- (void)fillPasswordForm:(NSString*)JSONString
+- (void)fillPasswordForm:(std::unique_ptr<base::Value>)form
+ inFrame:(web::WebFrame*)frame
withUsername:(NSString*)username
password:(NSString*)password
- completionHandler:(void (^)(BOOL))completionHandler;
+ completionHandler:(void (^)(NSString*))completionHandler;
// Fills new password field for (optional) |newPasswordIdentifier| and for
// (optional) confirm password field |confirmPasswordIdentifier| in the form
// identified by |formData|. Invokes |completionHandler| with true if any fields
// were filled, false otherwise.
- (void)fillPasswordForm:(autofill::FormRendererId)formIdentifier
+ inFrame:(web::WebFrame*)frame
newPasswordIdentifier:(autofill::FieldRendererId)newPasswordIdentifier
confirmPasswordIdentifier:
(autofill::FieldRendererId)confirmPasswordIdentifier
generatedPassword:(NSString*)generatedPassword
- completionHandler:(void (^)(BOOL))completionHandler;
+ completionHandler:(void (^)(NSString*))completionHandler;
// Sets up the next available unique ID value in a document.
-- (void)setUpForUniqueIDsWithInitialState:(uint32_t)nextAvailableID;
-
-// Designated initializer. |receiver| should not be nil.
-- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver
- NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)init NS_UNAVAILABLE;
+- (void)setUpForUniqueIDsWithInitialState:(uint32_t)nextAvailableID
+ inFrame:(web::WebFrame*)frame;
@end
diff --git a/chromium/components/password_manager/ios/js_password_manager.mm b/chromium/components/password_manager/ios/js_password_manager.mm
index 7766708a674..91edfacafaa 100644
--- a/chromium/components/password_manager/ios/js_password_manager.mm
+++ b/chromium/components/password_manager/ios/js_password_manager.mm
@@ -5,8 +5,6 @@
#import "components/password_manager/ios/js_password_manager.h"
#include "base/check.h"
-#include "base/json/json_writer.h"
-#include "base/json/string_escape.h"
#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
@@ -20,18 +18,20 @@
using autofill::FormRendererId;
using autofill::FieldRendererId;
+using base::SysNSStringToUTF8;
namespace password_manager {
-NSString* SerializeFillData(const GURL& origin,
- FormRendererId form_renderer_id,
- FieldRendererId username_element,
- const base::string16& username_value,
- FieldRendererId password_element,
- const base::string16& password_value) {
- base::DictionaryValue rootDict;
- rootDict.SetString("origin", origin.spec());
- rootDict.SetInteger("unique_renderer_id", form_renderer_id.value());
+std::unique_ptr<base::Value> SerializeFillData(
+ const GURL& origin,
+ FormRendererId form_renderer_id,
+ FieldRendererId username_element,
+ const base::string16& username_value,
+ FieldRendererId password_element,
+ const base::string16& password_value) {
+ auto rootDict = std::make_unique<base::DictionaryValue>();
+ rootDict->SetString("origin", origin.spec());
+ rootDict->SetInteger("unique_renderer_id", form_renderer_id.value());
auto fieldList = std::make_unique<base::ListValue>();
@@ -47,23 +47,22 @@ NSString* SerializeFillData(const GURL& origin,
passwordField->SetString("value", password_value);
fieldList->Append(std::move(passwordField));
- rootDict.Set("fields", std::move(fieldList));
+ rootDict->Set("fields", std::move(fieldList));
- std::string jsonString;
- base::JSONWriter::Write(rootDict, &jsonString);
- return base::SysUTF8ToNSString(jsonString);
+ return rootDict;
}
-NSString* SerializePasswordFormFillData(
+std::unique_ptr<base::Value> SerializePasswordFormFillData(
const autofill::PasswordFormFillData& formData) {
- return SerializeFillData(formData.origin, formData.form_renderer_id,
+ return SerializeFillData(formData.url, formData.form_renderer_id,
formData.username_field.unique_renderer_id,
formData.username_field.value,
formData.password_field.unique_renderer_id,
formData.password_field.value);
}
-NSString* SerializeFillData(const password_manager::FillData& fillData) {
+std::unique_ptr<base::Value> SerializeFillData(
+ const password_manager::FillData& fillData) {
return SerializeFillData(
fillData.origin, fillData.form_id, fillData.username_element_id,
fillData.username_value, fillData.password_element_id,
@@ -72,88 +71,71 @@ NSString* SerializeFillData(const password_manager::FillData& fillData) {
} // namespace password_manager
-namespace {
-// Sanitizes |JSONString| and wraps it in quotes so it can be injected safely in
-// JavaScript.
-NSString* JSONEscape(NSString* JSONString) {
- return base::SysUTF8ToNSString(
- base::GetQuotedJSONString(base::SysNSStringToUTF8(JSONString)));
-}
-} // namespace
-
-@implementation JsPasswordManager {
- // The injection receiver used to evaluate JavaScript.
- __weak CRWJSInjectionReceiver* _receiver;
-}
+@implementation JsPasswordManager
-- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver {
- DCHECK(receiver);
- self = [super init];
- if (self) {
- _receiver = receiver;
- }
- return self;
-}
-
-- (void)findPasswordFormsWithCompletionHandler:
- (void (^)(NSString*))completionHandler {
+- (void)findPasswordFormsInFrame:(web::WebFrame*)frame
+ completionHandler:(void (^)(NSString*))completionHandler {
DCHECK(completionHandler);
- [_receiver executeJavaScript:@"__gCrWeb.passwords.findPasswordForms()"
- completionHandler:^(id result, NSError*) {
- completionHandler(base::mac::ObjCCastStrict<NSString>(result));
- }];
+ std::vector<base::Value> parameters;
+ autofill::ExecuteJavaScriptFunction("passwords.findPasswordForms", parameters,
+ frame, base::BindOnce(completionHandler));
}
- (void)extractForm:(FormRendererId)formIdentifier
+ inFrame:(web::WebFrame*)frame
completionHandler:(void (^)(NSString*))completionHandler {
DCHECK(completionHandler);
- NSString* extra = [NSString
- stringWithFormat:@"__gCrWeb.passwords.getPasswordFormDataAsString(%u)",
- formIdentifier.value()];
- [_receiver executeJavaScript:extra
- completionHandler:^(id result, NSError*) {
- completionHandler(base::mac::ObjCCastStrict<NSString>(result));
- }];
+ std::vector<base::Value> parameters;
+ parameters.push_back(base::Value(static_cast<int>(formIdentifier.value())));
+ autofill::ExecuteJavaScriptFunction("passwords.getPasswordFormDataAsString",
+ parameters, frame,
+ base::BindOnce(completionHandler));
}
-- (void)fillPasswordForm:(NSString*)JSONString
+// TODO(crbug.com/1075444): Receive strings as std::string as they are being
+// converted twice.
+- (void)fillPasswordForm:(std::unique_ptr<base::Value>)form
+ inFrame:(web::WebFrame*)frame
withUsername:(NSString*)username
password:(NSString*)password
- completionHandler:(void (^)(BOOL))completionHandler {
+ completionHandler:(void (^)(NSString*))completionHandler {
DCHECK(completionHandler);
- NSString* script = [NSString
- stringWithFormat:@"__gCrWeb.passwords.fillPasswordForm(%@, %@, %@)",
- JSONString, JSONEscape(username), JSONEscape(password)];
- [_receiver executeJavaScript:script
- completionHandler:^(id result, NSError*) {
- completionHandler([result isEqual:@YES]);
- }];
+ std::vector<base::Value> parameters;
+ parameters.push_back(std::move(*form));
+ parameters.push_back(base::Value(SysNSStringToUTF8(username)));
+ parameters.push_back(base::Value(SysNSStringToUTF8(password)));
+ autofill::ExecuteJavaScriptFunction("passwords.fillPasswordForm", parameters,
+ frame, base::BindOnce(completionHandler));
}
+// TODO(crbug.com/1075444): Receive strings as std::string as they are being
+// converted twice.
- (void)fillPasswordForm:(FormRendererId)formIdentifier
+ inFrame:(web::WebFrame*)frame
newPasswordIdentifier:(FieldRendererId)newPasswordIdentifier
confirmPasswordIdentifier:(FieldRendererId)confirmPasswordIdentifier
generatedPassword:(NSString*)generatedPassword
- completionHandler:(void (^)(BOOL))completionHandler {
- NSString* script = [NSString
- stringWithFormat:@"__gCrWeb.passwords."
- @"fillPasswordFormWithGeneratedPassword(%u, %u, %u, %@)",
- formIdentifier.value(), newPasswordIdentifier.value(),
- confirmPasswordIdentifier.value(),
- JSONEscape(generatedPassword)];
- [_receiver executeJavaScript:script
- completionHandler:^(id result, NSError*) {
- completionHandler([result isEqual:@YES]);
- }];
+ completionHandler:(void (^)(NSString*))completionHandler {
+ DCHECK(completionHandler);
+ std::vector<base::Value> parameters;
+ parameters.push_back(base::Value(static_cast<int>(formIdentifier.value())));
+ parameters.push_back(
+ base::Value(static_cast<int>(newPasswordIdentifier.value())));
+ parameters.push_back(
+ base::Value(static_cast<int>(confirmPasswordIdentifier.value())));
+ parameters.push_back(base::Value(SysNSStringToUTF8(generatedPassword)));
+ autofill::ExecuteJavaScriptFunction(
+ "passwords.fillPasswordFormWithGeneratedPassword", parameters, frame,
+ base::BindOnce(completionHandler));
}
-- (void)setUpForUniqueIDsWithInitialState:(uint32_t)nextAvailableID {
- NSString* script = [NSString
- stringWithFormat:@"__gCrWeb.fill.setUpForUniqueIDs(%d)", nextAvailableID];
- [_receiver executeJavaScript:script
- completionHandler:^(id result, NSError*) {
- [result isEqual:@YES];
- }];
+- (void)setUpForUniqueIDsWithInitialState:(uint32_t)nextAvailableID
+ inFrame:(web::WebFrame*)frame {
+ std::vector<base::Value> parameters;
+ parameters.push_back(base::Value(static_cast<int>(nextAvailableID)));
+ autofill::ExecuteJavaScriptFunction("fill.setUpForUniqueIDs", parameters,
+ frame,
+ base::OnceCallback<void(NSString*)>());
}
@end
diff --git a/chromium/components/password_manager/ios/password_form_helper.h b/chromium/components/password_manager/ios/password_form_helper.h
index aaab8314a8d..5d5939086ea 100644
--- a/chromium/components/password_manager/ios/password_form_helper.h
+++ b/chromium/components/password_manager/ios/password_form_helper.h
@@ -99,7 +99,10 @@ class WebState;
(void (^)(BOOL found,
const autofill::FormData& form))completionHandler;
-- (void)setUpForUniqueIDsWithInitialState:(uint32_t)nextAvailableID;
+// Sets up the next available numeric value for setting unique renderer ids
+// in |frame|.
+- (void)setUpForUniqueIDsWithInitialState:(uint32_t)nextAvailableID
+ inFrame:(web::WebFrame*)frame;
// Creates a instance with the given WebState, observer and delegate.
- (instancetype)initWithWebState:(web::WebState*)webState
diff --git a/chromium/components/password_manager/ios/password_form_helper.mm b/chromium/components/password_manager/ios/password_form_helper.mm
index db706546abd..7a30b33d7d8 100644
--- a/chromium/components/password_manager/ios/password_form_helper.mm
+++ b/chromium/components/password_manager/ios/password_form_helper.mm
@@ -18,6 +18,8 @@
#include "components/password_manager/ios/account_select_fill_data.h"
#include "components/password_manager/ios/js_password_manager.h"
#import "ios/web/public/js_messaging/web_frame.h"
+#import "ios/web/public/js_messaging/web_frame_util.h"
+#import "ios/web/public/js_messaging/web_frames_manager.h"
#import "ios/web/public/web_state.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -123,8 +125,7 @@ constexpr char kCommandPrefix[] = "passwordForm";
_webState->AddObserver(_webStateObserverBridge.get());
_formActivityObserverBridge =
std::make_unique<autofill::FormActivityObserverBridge>(_webState, self);
- _jsPasswordManager = [[JsPasswordManager alloc]
- initWithReceiver:_webState->GetJSInjectionReceiver()];
+ _jsPasswordManager = [[JsPasswordManager alloc] init];
__weak PasswordFormHelper* weakSelf = self;
auto callback = base::BindRepeating(
@@ -238,7 +239,7 @@ constexpr char kCommandPrefix[] = "passwordForm";
withUsername:(const base::string16&)username
password:(const base::string16&)password
completionHandler:(nullable void (^)(BOOL))completionHandler {
- if (formData.origin.GetOrigin() != self.lastCommittedURL.GetOrigin()) {
+ if (formData.url.GetOrigin() != self.lastCommittedURL.GetOrigin()) {
if (completionHandler) {
completionHandler(NO);
}
@@ -248,11 +249,12 @@ constexpr char kCommandPrefix[] = "passwordForm";
// Send JSON over to the web view.
[self.jsPasswordManager
fillPasswordForm:SerializePasswordFormFillData(formData)
+ inFrame:GetMainFrame(_webState)
withUsername:base::SysUTF16ToNSString(username)
password:base::SysUTF16ToNSString(password)
- completionHandler:^(BOOL result) {
+ completionHandler:^(NSString* result) {
if (completionHandler) {
- completionHandler(result);
+ completionHandler([result isEqual:@"true"]);
}
}];
}
@@ -278,23 +280,24 @@ constexpr char kCommandPrefix[] = "passwordForm";
__weak PasswordFormHelper* weakSelf = self;
[self.jsPasswordManager
- findPasswordFormsWithCompletionHandler:^(NSString* jsonString) {
- std::vector<FormData> forms;
- [weakSelf getPasswordFormsFromJSON:jsonString
- pageURL:pageURL
- forms:&forms];
- // Find the maximum extracted value.
- uint32_t maxID = 0;
- for (const auto& form : forms) {
- if (form.unique_renderer_id)
- maxID = std::max(maxID, form.unique_renderer_id.value());
- for (const auto& field : form.fields) {
- if (field.unique_renderer_id)
- maxID = std::max(maxID, field.unique_renderer_id.value());
- }
- }
- completionHandler(forms, maxID);
- }];
+ findPasswordFormsInFrame:GetMainFrame(_webState)
+ completionHandler:^(NSString* jsonString) {
+ std::vector<FormData> forms;
+ [weakSelf getPasswordFormsFromJSON:jsonString
+ pageURL:pageURL
+ forms:&forms];
+ // Find the maximum extracted value.
+ uint32_t maxID = 0;
+ for (const auto& form : forms) {
+ if (form.unique_renderer_id)
+ maxID = std::max(maxID, form.unique_renderer_id.value());
+ for (const auto& field : form.fields) {
+ if (field.unique_renderer_id)
+ maxID = std::max(maxID, field.unique_renderer_id.value());
+ }
+ }
+ completionHandler(forms, maxID);
+ }];
}
- (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
@@ -320,12 +323,13 @@ constexpr char kCommandPrefix[] = "passwordForm";
completionHandler:(nullable void (^)(BOOL))completionHandler {
// Send JSON over to the web view.
[self.jsPasswordManager fillPasswordForm:formIdentifier
+ inFrame:GetMainFrame(_webState)
newPasswordIdentifier:newPasswordIdentifier
confirmPasswordIdentifier:confirmPasswordIdentifier
generatedPassword:generatedPassword
- completionHandler:^(BOOL result) {
+ completionHandler:^(NSString* result) {
if (completionHandler) {
- completionHandler(result);
+ completionHandler([result isEqual:@"true"]);
}
}];
}
@@ -335,11 +339,12 @@ constexpr char kCommandPrefix[] = "passwordForm";
(nullable void (^)(BOOL))completionHandler {
[self.jsPasswordManager
fillPasswordForm:SerializeFillData(fillData)
+ inFrame:GetMainFrame(_webState)
withUsername:base::SysUTF16ToNSString(fillData.username_value)
password:base::SysUTF16ToNSString(fillData.password_value)
- completionHandler:^(BOOL result) {
+ completionHandler:^(NSString* result) {
if (completionHandler) {
- completionHandler(result);
+ completionHandler([result isEqual:@"true"]);
}
}];
}
@@ -410,11 +415,14 @@ constexpr char kCommandPrefix[] = "passwordForm";
};
[self.jsPasswordManager extractForm:formIdentifier
+ inFrame:GetMainFrame(_webState)
completionHandler:extractFormDataCompletionHandler];
}
-- (void)setUpForUniqueIDsWithInitialState:(uint32_t)nextAvailableID {
- [self.jsPasswordManager setUpForUniqueIDsWithInitialState:nextAvailableID];
+- (void)setUpForUniqueIDsWithInitialState:(uint32_t)nextAvailableID
+ inFrame:(web::WebFrame*)frame {
+ [self.jsPasswordManager setUpForUniqueIDsWithInitialState:nextAvailableID
+ inFrame:frame];
}
@end
diff --git a/chromium/components/password_manager/ios/password_form_helper_unittest.mm b/chromium/components/password_manager/ios/password_form_helper_unittest.mm
index ccd4d33950f..7051050a218 100644
--- a/chromium/components/password_manager/ios/password_form_helper_unittest.mm
+++ b/chromium/components/password_manager/ios/password_form_helper_unittest.mm
@@ -51,12 +51,6 @@ using test_helpers::SetFillData;
// Mocks JsPasswordManager to simluate javascript execution failure.
@interface MockJsPasswordManager : JsPasswordManager
-// Designated initializer.
-- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver
- NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)init NS_UNAVAILABLE;
-
// For the first |targetFailureCount| calls to
// |fillPasswordForm:withUserName:password:completionHandler:|, skips the
// invocation of the real JavaScript manager, giving the effect that password
@@ -70,26 +64,24 @@ using test_helpers::SetFillData;
NSUInteger _fillPasswordFormFailureCountRemaining;
}
-- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver {
- return [super initWithReceiver:receiver];
-}
-
- (void)setFillPasswordFormTargetFailureCount:(NSUInteger)targetFailureCount {
_fillPasswordFormFailureCountRemaining = targetFailureCount;
}
-- (void)fillPasswordForm:(NSString*)JSONString
+- (void)fillPasswordForm:(std::unique_ptr<base::Value>)form
+ inFrame:(web::WebFrame*)frame
withUsername:(NSString*)username
password:(NSString*)password
- completionHandler:(void (^)(BOOL))completionHandler {
+ completionHandler:(void (^)(NSString*))completionHandler {
if (_fillPasswordFormFailureCountRemaining > 0) {
--_fillPasswordFormFailureCountRemaining;
if (completionHandler) {
- completionHandler(NO);
+ completionHandler(@"false");
}
return;
}
- [super fillPasswordForm:JSONString
+ [super fillPasswordForm:std::move(form)
+ inFrame:frame
withUsername:username
password:password
completionHandler:completionHandler];
@@ -331,8 +323,8 @@ TEST_F(PasswordFormHelperTest, FindAndFillOnePasswordForm) {
// that completion handler is called with the proper values.
TEST_F(PasswordFormHelperTest, FindAndFillMultiplePasswordForms) {
// Fails the first call to fill password form.
- MockJsPasswordManager* mockJsPasswordManager = [[MockJsPasswordManager alloc]
- initWithReceiver:web_state()->GetJSInjectionReceiver()];
+ MockJsPasswordManager* mockJsPasswordManager =
+ [[MockJsPasswordManager alloc] init];
[mockJsPasswordManager setFillPasswordFormTargetFailureCount:1];
[helper_ setJsPasswordManager:mockJsPasswordManager];
LoadHtml(
@@ -370,8 +362,8 @@ TEST_F(PasswordFormHelperTest, FindAndFillMultiplePasswordForms) {
// Tests that extractPasswordFormData extracts wanted form on page with mutiple
// forms.
TEST_F(PasswordFormHelperTest, ExtractPasswordFormData) {
- MockJsPasswordManager* mockJsPasswordManager = [[MockJsPasswordManager alloc]
- initWithReceiver:web_state()->GetJSInjectionReceiver()];
+ MockJsPasswordManager* mockJsPasswordManager =
+ [[MockJsPasswordManager alloc] init];
[helper_ setJsPasswordManager:mockJsPasswordManager];
LoadHtml(@"<form><input id='u1' type='text' name='un1'>"
"<input id='p1' type='password' name='pw1'></form>"
diff --git a/chromium/components/password_manager/ios/resources/password_controller.js b/chromium/components/password_manager/ios/resources/password_controller.js
index 55a75c9c671..6343a3c7381 100644
--- a/chromium/components/password_manager/ios/resources/password_controller.js
+++ b/chromium/components/password_manager/ios/resources/password_controller.js
@@ -112,7 +112,7 @@ const addSubmitButtonTouchEndHandler = function(form) {
*/
const onSubmitButtonTouchEnd = function(evt) {
const form = evt.currentTarget.form;
- const formData = __gCrWeb.passwords.getPasswordFormData(form);
+ const formData = __gCrWeb.passwords.getPasswordFormData(form, window);
if (!formData) {
return;
}
@@ -128,7 +128,7 @@ const onSubmitButtonTouchEnd = function(evt) {
* @return {HTMLInputElement}
*/
const findInputByUniqueFieldId = function(inputs, identifier) {
- const uniqueID = Symbol.for('__gChrome~uniqueID');
+ const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME);
for (let i = 0; i < inputs.length; ++i) {
if (identifier === inputs[i][uniqueID]) {
return inputs[i];
@@ -181,7 +181,7 @@ __gCrWeb.passwords['getPasswordFormDataAsString'] = function(identifier) {
if (!el) {
return '{}';
}
- const formData = __gCrWeb.passwords.getPasswordFormData(el);
+ const formData = __gCrWeb.passwords.getPasswordFormData(el, window);
if (!formData) {
return '{}';
}
@@ -198,7 +198,10 @@ __gCrWeb.passwords['getPasswordFormDataAsString'] = function(identifier) {
* @param {AutofillFormData} formData Form data.
* @param {string} username The username to fill.
* @param {string} password The password to fill.
- * @return {boolean} Whether a form field has been filled.
+ * @return {string} Whether a form field has been filled.
+ *
+ * TODO(crbug.com/1075444): Rewrite callback handler to accept various
+ * return types and return boolean.
*/
__gCrWeb.passwords['fillPasswordForm'] = function(
formData, username, password) {
@@ -206,9 +209,10 @@ __gCrWeb.passwords['fillPasswordForm'] = function(
__gCrWeb.common.removeQueryAndReferenceFromURL(window.location.href);
const origin = /** @type {string} */ (formData['origin']);
if (!__gCrWeb.common.isSameOrigin(origin, normalizedOrigin)) {
- return false;
+ return 'false';
}
- return fillPasswordFormWithData(formData, username, password, window);
+ return fillPasswordFormWithData(formData, username, password, window)
+ .toString();
};
/**
@@ -220,20 +224,23 @@ __gCrWeb.passwords['fillPasswordForm'] = function(
* @param {number} confirmPasswordIdentifier The id of confirm password element
* to fill.
* @param {string} password The password to fill.
- * @return {boolean} Whether new password field has been filled.
+ * @return {string} Whether new password field has been filled.
+ *
+ * TODO(crbug.com/1075444): Rewrite callback handler to accept various
+ * return types and return boolean.
*/
__gCrWeb.passwords['fillPasswordFormWithGeneratedPassword'] = function(
formIdentifier, newPasswordIdentifier, confirmPasswordIdentifier,
password) {
const form = __gCrWeb.form.getFormElementFromUniqueFormId(formIdentifier);
if (!form) {
- return false;
+ return 'false';
}
const inputs = getFormInputElements(form);
const newPasswordField =
findInputByUniqueFieldId(inputs, newPasswordIdentifier);
if (!newPasswordField) {
- return false;
+ return 'false';
}
// Avoid resetting if same value, as it moves cursor to the end.
if (newPasswordField.value !== password) {
@@ -244,7 +251,7 @@ __gCrWeb.passwords['fillPasswordFormWithGeneratedPassword'] = function(
if (confirmPasswordField && confirmPasswordField.value !== password) {
__gCrWeb.fill.setInputElementValue(password, confirmPasswordField);
}
- return true;
+ return 'true';
};
/**
@@ -341,7 +348,7 @@ const getPasswordFormDataList = function(formDataList, win) {
const doc = win.document;
const forms = doc.forms;
for (let i = 0; i < forms.length; i++) {
- const formData = __gCrWeb.passwords.getPasswordFormData(forms[i]);
+ const formData = __gCrWeb.passwords.getPasswordFormData(forms[i], win);
if (formData) {
formDataList.push(formData);
addSubmitButtonTouchEndHandler(forms[i]);
@@ -384,13 +391,14 @@ function getPasswordFormDataFromUnownedElements_(formDataList, window) {
/**
* Returns a JS object containing the data from |formElement|.
* @param {HTMLFormElement} formElement An HTML Form element.
+ * @param {Window} win A window or a frame containing formData.
* @return {Object} Object of data from formElement.
*/
-__gCrWeb.passwords.getPasswordFormData = function(formElement) {
+__gCrWeb.passwords.getPasswordFormData = function(formElement, win) {
const extractMask = __gCrWeb.fill.EXTRACT_MASK_VALUE;
const formData = {};
const ok = __gCrWeb.fill.webFormElementToFormData(
- window, formElement, null /* formControlElement */, extractMask, formData,
+ win, formElement, null /* formControlElement */, extractMask, formData,
null /* field */);
return ok ? formData : null;
};
diff --git a/chromium/components/password_manager/ios/test_helpers.cc b/chromium/components/password_manager/ios/test_helpers.cc
index 103d97451bd..b8e06bb2e0b 100644
--- a/chromium/components/password_manager/ios/test_helpers.cc
+++ b/chromium/components/password_manager/ios/test_helpers.cc
@@ -16,7 +16,7 @@ using password_manager::FillData;
namespace test_helpers {
-void SetPasswordFormFillData(const std::string& origin,
+void SetPasswordFormFillData(const std::string& url,
const char* form_name,
uint32_t unique_renderer_id,
const char* username_field,
@@ -29,7 +29,7 @@ void SetPasswordFormFillData(const std::string& origin,
const char* additional_password,
bool wait_for_username,
PasswordFormFillData* form_data) {
- form_data->origin = GURL(origin);
+ form_data->url = GURL(url);
form_data->name = base::UTF8ToUTF16(form_name);
form_data->form_renderer_id = FormRendererId(unique_renderer_id);
autofill::FormFieldData username;