summaryrefslogtreecommitdiff
path: root/chromium/components/password_manager/core
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-31 16:33:43 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-02-06 16:33:22 +0000
commitda51f56cc21233c2d30f0fe0d171727c3102b2e0 (patch)
tree4e579ab70ce4b19bee7984237f3ce05a96d59d83 /chromium/components/password_manager/core
parentc8c2d1901aec01e934adf561a9fdf0cc776cdef8 (diff)
downloadqtwebengine-chromium-da51f56cc21233c2d30f0fe0d171727c3102b2e0.tar.gz
BASELINE: Update Chromium to 65.0.3525.40
Also imports missing submodules Change-Id: I36901b7c6a325cda3d2c10cedb2186c25af3b79b Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/components/password_manager/core')
-rw-r--r--chromium/components/password_manager/core/browser/BUILD.gn27
-rw-r--r--chromium/components/password_manager/core/browser/DEPS1
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc6
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl.cc8
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc20
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc3
-rw-r--r--chromium/components/password_manager/core/browser/export/destination.h25
-rw-r--r--chromium/components/password_manager/core/browser/export/password_manager_exporter.cc24
-rw-r--r--chromium/components/password_manager/core/browser/export/password_manager_exporter.h20
-rw-r--r--chromium/components/password_manager/core/browser/export/password_manager_exporter_unittest.cc102
-rw-r--r--chromium/components/password_manager/core/browser/form_saver.h11
-rw-r--r--chromium/components/password_manager/core/browser/form_saver_impl.cc5
-rw-r--r--chromium/components/password_manager/core/browser/form_saver_impl.h3
-rw-r--r--chromium/components/password_manager/core/browser/form_saver_impl_unittest.cc20
-rw-r--r--chromium/components/password_manager/core/browser/hash_password_manager.cc93
-rw-r--r--chromium/components/password_manager/core/browser/hash_password_manager.h26
-rw-r--r--chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc45
-rw-r--r--chromium/components/password_manager/core/browser/login_database.cc6
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_store.h2
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc15
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.cc166
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.h11
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager_unittest.cc673
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc13
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder.h23
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc19
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.cc56
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.h7
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.h12
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc33
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h51
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_recorder_unittest.cc49
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.cc3
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.h18
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_unittest.cc86
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util.cc36
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util.h5
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util_unittest.cc22
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_defines.h2
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detector.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc3
-rw-r--r--chromium/components/password_manager/core/browser/password_store.cc35
-rw-r--r--chromium/components/password_manager/core/browser/password_store.h17
-rw-r--r--chromium/components/password_manager/core/browser/password_store_default_unittest.cc3
-rw-r--r--chromium/components/password_manager/core/browser/password_store_factory_util.cc21
-rw-r--r--chromium/components/password_manager/core/browser/stub_form_saver.h3
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.cc11
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.h1
-rw-r--r--chromium/components/password_manager/core/common/credential_manager_types.h3
-rw-r--r--chromium/components/password_manager/core/common/experiments.cc2
-rw-r--r--chromium/components/password_manager/core/common/password_manager_features.cc24
-rw-r--r--chromium/components/password_manager/core/common/password_manager_features.h4
53 files changed, 1082 insertions, 800 deletions
diff --git a/chromium/components/password_manager/core/browser/BUILD.gn b/chromium/components/password_manager/core/browser/BUILD.gn
index ae73f912d27..d4f2b3c4bf6 100644
--- a/chromium/components/password_manager/core/browser/BUILD.gn
+++ b/chromium/components/password_manager/core/browser/BUILD.gn
@@ -49,7 +49,6 @@ static_library("browser") {
"credentials_filter.h",
"export/csv_writer.cc",
"export/csv_writer.h",
- "export/destination.h",
"export/password_csv_writer.cc",
"export/password_csv_writer.h",
"export/password_manager_exporter.cc",
@@ -160,11 +159,8 @@ static_library("browser") {
"password_reuse_detector_consumer.cc",
"password_reuse_detector_consumer.h",
]
-
- if (is_win || is_mac || (is_linux && !is_chromeos)) {
+ if (is_win || is_mac || is_linux || is_chromeos) {
sources += [
- "hash_password_manager.cc",
- "hash_password_manager.h",
"password_store_signin_notifier.cc",
"password_store_signin_notifier.h",
]
@@ -176,6 +172,7 @@ static_library("browser") {
"//components/sync",
]
deps = [
+ ":hash_password_manager",
":proto",
"//base",
"//base:i18n",
@@ -193,7 +190,6 @@ static_library("browser") {
"//components/url_formatter",
"//components/variations",
"//components/webdata/common",
- "//crypto",
"//google_apis",
"//net",
"//services/metrics/public/cpp:metrics_cpp",
@@ -229,6 +225,20 @@ proto_library("proto") {
]
}
+static_library("hash_password_manager") {
+ sources = [
+ "hash_password_manager.cc",
+ "hash_password_manager.h",
+ ]
+ deps = [
+ "//base:base",
+ "//components/os_crypt",
+ "//components/password_manager/core/common",
+ "//components/prefs",
+ "//crypto",
+ ]
+}
+
static_library("test_support") {
testonly = true
sources = [
@@ -376,10 +386,13 @@ source_set("unit_tests") {
"password_reuse_detector_unittest.cc",
]
}
- if (is_win || is_mac || (is_linux && !is_chromeos)) {
+
+ if (is_win || is_mac || is_linux || is_chromeos) {
sources += [ "hash_password_manager_unittest.cc" ]
}
+
deps = [
+ ":hash_password_manager",
":test_support",
":unit_tests_bundle_data",
"//base/test:test_support",
diff --git a/chromium/components/password_manager/core/browser/DEPS b/chromium/components/password_manager/core/browser/DEPS
index 0a0aeeabe7c..abf89f4cae0 100644
--- a/chromium/components/password_manager/core/browser/DEPS
+++ b/chromium/components/password_manager/core/browser/DEPS
@@ -11,6 +11,7 @@ include_rules = [
"+crypto",
"+google_apis",
"+grit",
+ "+net",
"+services/metrics/public/cpp",
]
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc
index eac6188b986..83e9f38d65b 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc
@@ -11,8 +11,8 @@
#include <string>
#include <utility>
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_api.pb.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
#include "components/password_manager/core/browser/android_affiliation/test_affiliation_fetcher_factory.h"
@@ -46,11 +46,11 @@ void ReportStatistics(AffiliationFetchResult result,
UMA_HISTOGRAM_ENUMERATION("PasswordManager.AffiliationFetcher.FetchResult",
result, AFFILIATION_FETCH_RESULT_MAX);
if (fetcher) {
- UMA_HISTOGRAM_SPARSE_SLOWLY(
+ base::UmaHistogramSparse(
"PasswordManager.AffiliationFetcher.FetchHttpResponseCode",
fetcher->GetResponseCode());
// Network error codes are negative. See: src/net/base/net_error_list.h.
- UMA_HISTOGRAM_SPARSE_SLOWLY(
+ base::UmaHistogramSparse(
"PasswordManager.AffiliationFetcher.FetchErrorCode",
-fetcher->GetStatus().error());
}
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 cb80feeb77d..c8d85dd967d 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_impl.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_impl.cc
@@ -103,7 +103,7 @@ void CredentialManagerImpl::Get(CredentialMediationRequirement mediation,
if (pending_request_ || !store) {
// Callback error.
std::move(callback).Run(
- pending_request_ ? CredentialManagerError::PENDINGREQUEST
+ pending_request_ ? CredentialManagerError::PENDING_REQUEST
: CredentialManagerError::PASSWORDSTOREUNAVAILABLE,
base::nullopt);
LogCredentialManagerGetResult(metrics_util::CREDENTIAL_MANAGER_GET_REJECTED,
@@ -244,11 +244,7 @@ void CredentialManagerImpl::OnProvisionalSaveComplete() {
// 'skip_zero_click' state, as we've gotten an explicit signal that the page
// understands the credential management API and so can be trusted to notify
// us when they sign the user out.
- auto best_match = form_manager_->best_matches().find(form.username_value);
- // NOTE: We can't use DCHECK_NE here, since std::map<>::iterator does not
- // support operator<<.
- DCHECK(best_match != form_manager_->best_matches().end());
- form_manager_->Update(*best_match->second);
+ form_manager_->Update(form_manager_->pending_credentials());
return;
}
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 4a09597d5ec..46fca823813 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
@@ -457,7 +457,13 @@ TEST_F(CredentialManagerImplTest, StoreFederatedAfterPassword) {
}
TEST_F(CredentialManagerImplTest, CredentialManagerStoreOverwrite) {
+ // Add an unrelated form to complicate the task.
+ origin_path_form_.preferred = true;
+ store_->AddLogin(origin_path_form_);
// Populate the PasswordStore with a form.
+ form_.preferred = false;
+ form_.display_name = base::ASCIIToUTF16("Old Name");
+ form_.icon_url = GURL();
store_->AddLogin(form_);
RunAllPendingTasks();
@@ -465,6 +471,8 @@ TEST_F(CredentialManagerImplTest, CredentialManagerStoreOverwrite) {
// the password without prompting the user.
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
info.password = base::ASCIIToUTF16("Totally new password.");
+ info.name = base::ASCIIToUTF16("New Name");
+ info.icon = GURL("https://example.com/icon.png");
EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_)).Times(0);
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
bool called = false;
@@ -478,9 +486,15 @@ TEST_F(CredentialManagerImplTest, CredentialManagerStoreOverwrite) {
TestPasswordStore::PasswordMap passwords = store_->stored_passwords();
EXPECT_EQ(1U, passwords.size());
- EXPECT_EQ(1U, passwords[form_.signon_realm].size());
+ EXPECT_EQ(2U, passwords[form_.signon_realm].size());
+ origin_path_form_.preferred = false;
+ EXPECT_EQ(origin_path_form_, passwords[form_.signon_realm][0]);
EXPECT_EQ(base::ASCIIToUTF16("Totally new password."),
- passwords[form_.signon_realm][0].password_value);
+ passwords[form_.signon_realm][1].password_value);
+ EXPECT_EQ(base::ASCIIToUTF16("New Name"),
+ passwords[form_.signon_realm][1].display_name);
+ EXPECT_EQ(GURL("https://example.com/icon.png"),
+ passwords[form_.signon_realm][1].icon_url);
}
TEST_F(CredentialManagerImplTest,
@@ -1215,7 +1229,7 @@ TEST_F(CredentialManagerImplTest,
// Check that the second request triggered a rejection.
EXPECT_TRUE(called_2);
- EXPECT_EQ(CredentialManagerError::PENDINGREQUEST, error_2);
+ EXPECT_EQ(CredentialManagerError::PENDING_REQUEST, error_2);
EXPECT_FALSE(credential_2);
// Check that the first request resolves.
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 23588189cf1..b3e71fabb46 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
@@ -19,6 +19,7 @@
#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/common/credential_manager_types.h"
+#include "net/cert/cert_status_flags.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -121,7 +122,7 @@ CredentialManagerPendingRequestTask::CredentialManagerPendingRequestTask(
mediation_(mediation),
origin_(delegate_->GetOrigin()),
include_passwords_(include_passwords) {
- CHECK(!delegate_->client()->DidLastPageLoadEncounterSSLErrors());
+ CHECK(!net::IsCertStatusError(delegate_->client()->GetMainFrameCertStatus()));
for (const GURL& federation : request_federations)
federations_.insert(
url::Origin::Create(federation.GetOrigin()).Serialize());
diff --git a/chromium/components/password_manager/core/browser/export/destination.h b/chromium/components/password_manager/core/browser/export/destination.h
deleted file mode 100644
index 342601e3c72..00000000000
--- a/chromium/components/password_manager/core/browser/export/destination.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_EXPORT_DESTINATION_H_
-#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_EXPORT_DESTINATION_H_
-
-#include <string>
-
-namespace password_manager {
-
-// Interface of a medium, to where a serialised list of passwords can be
-// exported.
-class Destination {
- public:
- Destination() = default;
- virtual ~Destination() = default;
-
- // Send the data to the destination, synchronously.
- virtual bool Write(const std::string& data) = 0;
-};
-
-} // namespace password_manager
-
-#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_EXPORT_DESTINATION_H_
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 b0aa794fd4e..d606ad497aa 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
@@ -6,12 +6,12 @@
#include <utility>
+#include "base/files/file_util.h"
#include "base/location.h"
#include "base/metrics/histogram_macros.h"
#include "base/task_runner_util.h"
#include "base/task_scheduler/post_task.h"
#include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/browser/export/destination.h"
#include "components/password_manager/core/browser/export/password_csv_writer.h"
#include "components/password_manager/core/browser/ui/credential_provider_interface.h"
@@ -34,6 +34,7 @@ PasswordManagerExporter::PasswordManagerExporter(
password_manager::CredentialProviderInterface*
credential_provider_interface)
: credential_provider_interface_(credential_provider_interface),
+ write_function_(&base::WriteFile),
task_runner_(base::CreateSequencedTaskRunnerWithTraits(
{base::TaskPriority::USER_VISIBLE, base::MayBlock()})),
weak_factory_(this) {}
@@ -48,8 +49,8 @@ void PasswordManagerExporter::PreparePasswordsForExport() {
}
void PasswordManagerExporter::SetDestination(
- std::unique_ptr<Destination> destination) {
- destination_ = std::move(destination);
+ const base::FilePath& destination) {
+ destination_ = destination;
if (IsReadyForExport())
Export();
@@ -59,12 +60,19 @@ void PasswordManagerExporter::Cancel() {
// Tasks which had their pointers invalidated won't run.
weak_factory_.InvalidateWeakPtrs();
- destination_.reset();
+ destination_.clear();
password_list_.clear();
}
+void PasswordManagerExporter::SetWriteForTesting(
+ int (*write_function)(const base::FilePath& filename,
+ const char* data,
+ int size)) {
+ write_function_ = write_function;
+}
+
bool PasswordManagerExporter::IsReadyForExport() {
- return destination_ && !password_list_.empty();
+ return !destination_.empty() && !password_list_.empty();
}
void PasswordManagerExporter::Export() {
@@ -80,13 +88,13 @@ void PasswordManagerExporter::Export() {
base::Passed(std::move(destination_))));
password_list_.clear();
- destination_.reset();
+ destination_.clear();
}
void PasswordManagerExporter::OnPasswordsSerialised(
- std::unique_ptr<Destination> destination,
+ base::FilePath destination,
const std::string& serialised) {
- destination->Write(serialised);
+ write_function_(destination, serialised.c_str(), serialised.size());
}
} // namespace password_manager
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 471601b570e..154832097c4 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
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
@@ -20,7 +21,6 @@ struct PasswordForm;
namespace password_manager {
class CredentialProviderInterface;
-class Destination;
// Controls the exporting of passwords. PasswordManagerExporter will perform
// the export asynchrnously as soon as all the required info is available
@@ -38,11 +38,17 @@ class PasswordManagerExporter {
// Set the destination, where the passwords will be written when they are
// ready.
- virtual void SetDestination(std::unique_ptr<Destination> destination);
+ virtual void SetDestination(const base::FilePath& destination);
// Best-effort canceling of any on-going task related to exporting.
virtual void Cancel();
+ // Replace the function which writes to the filesystem with a custom action.
+ // The return value is -1 on error, otherwise the number of bytes written.
+ void SetWriteForTesting(int (*write_function)(const base::FilePath& filename,
+ const char* data,
+ int size));
+
private:
// Returns true if all the necessary data is available.
bool IsReadyForExport();
@@ -53,7 +59,7 @@ class PasswordManagerExporter {
void Export();
// Callback after the passwords have been serialised.
- void OnPasswordsSerialised(std::unique_ptr<Destination> destination,
+ void OnPasswordsSerialised(base::FilePath destination,
const std::string& serialised);
// The source of the password list which will be exported.
@@ -65,7 +71,13 @@ class PasswordManagerExporter {
// The destination which was provided and where the password list will be
// sent. It will be cleared once exporting is complete.
- std::unique_ptr<Destination> destination_;
+ base::FilePath destination_;
+
+ // The function which does the actual writing. It should point to
+ // base::WriteFile, unless it's changed for testing purposes.
+ int (*write_function_)(const base::FilePath& filename,
+ const char* data,
+ int size);
// |task_runner_| is used for time-consuming tasks during exporting. The tasks
// will dereference a WeakPtr to |*this|, which means they all need to run on
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 48dec4b0fd6..17312a3f159 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
@@ -10,9 +10,10 @@
#include <vector>
#include "base/strings/utf_string_conversions.h"
+#include "base/test/mock_callback.h"
#include "base/test/scoped_task_environment.h"
+#include "build/build_config.h"
#include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/browser/export/destination.h"
#include "components/password_manager/core/browser/export/password_csv_writer.h"
#include "components/password_manager/core/browser/ui/credential_provider_interface.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -21,8 +22,20 @@
namespace {
using ::testing::_;
+using ::testing::ReturnArg;
+using ::testing::StrEq;
using ::testing::StrictMock;
+// A callback that matches the signature of base::WriteFile
+using WriteCallback =
+ base::RepeatingCallback<int(const base::FilePath&, const char*, int)>;
+
+#if defined(OS_WIN)
+const base::FilePath::CharType kNullFileName[] = FILE_PATH_LITERAL("/nul");
+#else
+const base::FilePath::CharType kNullFileName[] = FILE_PATH_LITERAL("/dev/null");
+#endif
+
// Provides a predetermined set of credentials
class FakeCredentialProvider
: public password_manager::CredentialProviderInterface {
@@ -54,16 +67,16 @@ class FakeCredentialProvider
DISALLOW_COPY_AND_ASSIGN(FakeCredentialProvider);
};
-class MockDestination : public password_manager::Destination {
- public:
- MockDestination() = default;
- ~MockDestination() override = default;
+// WriteFunction will delegate to this callback, if set. Use for setting
+// expectations for base::WriteFile in PasswordManagerExporter.
+base::MockCallback<WriteCallback>* g_write_callback = nullptr;
- MOCK_METHOD1(Write, bool(const std::string& data));
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockDestination);
-};
+// Mock for base::WriteFile. Expectations should be set on |g_write_callback|.
+int WriteFunction(const base::FilePath& filename, const char* data, int size) {
+ if (g_write_callback)
+ return g_write_callback->Get().Run(filename, data, size);
+ return size;
+}
// Creates a hardcoded set of credentials for tests.
std::vector<std::unique_ptr<autofill::PasswordForm>> CreatePasswordList() {
@@ -82,13 +95,20 @@ class PasswordManagerExporterTest : public testing::Test {
PasswordManagerExporterTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI),
- exporter_(&fake_credential_provider_) {}
- ~PasswordManagerExporterTest() override = default;
+ exporter_(&fake_credential_provider_),
+ destination_path_(kNullFileName) {
+ g_write_callback = &mock_write_file_;
+ exporter_.SetWriteForTesting(&WriteFunction);
+ }
+
+ ~PasswordManagerExporterTest() override { g_write_callback = nullptr; }
protected:
base::test::ScopedTaskEnvironment scoped_task_environment_;
FakeCredentialProvider fake_credential_provider_;
password_manager::PasswordManagerExporter exporter_;
+ StrictMock<base::MockCallback<WriteCallback>> mock_write_file_;
+ base::FilePath destination_path_;
private:
DISALLOW_COPY_AND_ASSIGN(PasswordManagerExporterTest);
@@ -101,12 +121,12 @@ TEST_F(PasswordManagerExporterTest, PasswordExportSetPasswordListFirst) {
const std::string serialised(
password_manager::PasswordCSVWriter::SerializePasswords(password_list));
- std::unique_ptr<MockDestination> mock_destination =
- std::make_unique<StrictMock<MockDestination>>();
- EXPECT_CALL(*mock_destination, Write(serialised));
+ EXPECT_CALL(mock_write_file_,
+ Run(destination_path_, StrEq(serialised), serialised.size()))
+ .WillOnce(ReturnArg<2>());
exporter_.PreparePasswordsForExport();
- exporter_.SetDestination(std::move(mock_destination));
+ exporter_.SetDestination(destination_path_);
scoped_task_environment_.RunUntilIdle();
}
@@ -118,11 +138,11 @@ TEST_F(PasswordManagerExporterTest, PasswordExportSetDestinationFirst) {
const std::string serialised(
password_manager::PasswordCSVWriter::SerializePasswords(password_list));
- std::unique_ptr<MockDestination> mock_destination =
- std::make_unique<MockDestination>();
- EXPECT_CALL(*mock_destination, Write(serialised));
+ EXPECT_CALL(mock_write_file_,
+ Run(destination_path_, StrEq(serialised), serialised.size()))
+ .WillOnce(ReturnArg<2>());
- exporter_.SetDestination(std::move(mock_destination));
+ exporter_.SetDestination(destination_path_);
exporter_.PreparePasswordsForExport();
scoped_task_environment_.RunUntilIdle();
@@ -133,11 +153,9 @@ TEST_F(PasswordManagerExporterTest, DontExportWithOnlyDestination) {
CreatePasswordList();
fake_credential_provider_.SetPasswordList(password_list);
- std::unique_ptr<MockDestination> mock_destination =
- std::make_unique<MockDestination>();
- EXPECT_CALL(*mock_destination, Write(_)).Times(0);
+ EXPECT_CALL(mock_write_file_, Run(_, _, _)).Times(0);
- exporter_.SetDestination(std::move(mock_destination));
+ exporter_.SetDestination(destination_path_);
scoped_task_environment_.RunUntilIdle();
}
@@ -146,14 +164,12 @@ TEST_F(PasswordManagerExporterTest, CancelAfterPasswords) {
std::vector<std::unique_ptr<autofill::PasswordForm>> password_list =
CreatePasswordList();
fake_credential_provider_.SetPasswordList(password_list);
- std::unique_ptr<MockDestination> mock_destination =
- std::make_unique<MockDestination>();
- EXPECT_CALL(*mock_destination, Write(_)).Times(0);
+ EXPECT_CALL(mock_write_file_, Run(_, _, _)).Times(0);
exporter_.PreparePasswordsForExport();
exporter_.Cancel();
- exporter_.SetDestination(std::move(mock_destination));
+ exporter_.SetDestination(destination_path_);
scoped_task_environment_.RunUntilIdle();
}
@@ -162,12 +178,10 @@ TEST_F(PasswordManagerExporterTest, CancelAfterDestination) {
std::vector<std::unique_ptr<autofill::PasswordForm>> password_list =
CreatePasswordList();
fake_credential_provider_.SetPasswordList(password_list);
- std::unique_ptr<MockDestination> mock_destination =
- std::make_unique<MockDestination>();
- EXPECT_CALL(*mock_destination, Write(_)).Times(0);
+ EXPECT_CALL(mock_write_file_, Run(_, _, _)).Times(0);
- exporter_.SetDestination(std::move(mock_destination));
+ exporter_.SetDestination(destination_path_);
exporter_.Cancel();
exporter_.PreparePasswordsForExport();
@@ -182,14 +196,14 @@ TEST_F(PasswordManagerExporterTest, CancelAfterPasswordsThenExport) {
const std::string serialised(
password_manager::PasswordCSVWriter::SerializePasswords(password_list));
fake_credential_provider_.SetPasswordList(password_list);
- std::unique_ptr<MockDestination> mock_destination =
- std::make_unique<MockDestination>();
- EXPECT_CALL(*mock_destination, Write(serialised));
+ EXPECT_CALL(mock_write_file_,
+ Run(destination_path_, StrEq(serialised), serialised.size()))
+ .WillOnce(ReturnArg<2>());
exporter_.PreparePasswordsForExport();
exporter_.Cancel();
- exporter_.SetDestination(std::move(mock_destination));
+ exporter_.SetDestination(destination_path_);
exporter_.PreparePasswordsForExport();
scoped_task_environment_.RunUntilIdle();
@@ -203,18 +217,18 @@ TEST_F(PasswordManagerExporterTest, CancelAfterDestinationThenExport) {
const std::string serialised(
password_manager::PasswordCSVWriter::SerializePasswords(password_list));
fake_credential_provider_.SetPasswordList(password_list);
- std::unique_ptr<MockDestination> mock_destination_cancelled =
- std::make_unique<MockDestination>();
- std::unique_ptr<MockDestination> mock_destination =
- std::make_unique<MockDestination>();
- EXPECT_CALL(*mock_destination_cancelled, Write(_)).Times(0);
- EXPECT_CALL(*mock_destination, Write(serialised));
+ base::FilePath cancelled_path(FILE_PATH_LITERAL("clean_me_up"));
+
+ EXPECT_CALL(mock_write_file_, Run(cancelled_path, _, _)).Times(0);
+ EXPECT_CALL(mock_write_file_,
+ Run(destination_path_, StrEq(serialised), serialised.size()))
+ .WillOnce(ReturnArg<2>());
- exporter_.SetDestination(std::move(mock_destination_cancelled));
+ exporter_.SetDestination(std::move(cancelled_path));
exporter_.Cancel();
exporter_.PreparePasswordsForExport();
- exporter_.SetDestination(std::move(mock_destination));
+ exporter_.SetDestination(destination_path_);
scoped_task_environment_.RunUntilIdle();
}
diff --git a/chromium/components/password_manager/core/browser/form_saver.h b/chromium/components/password_manager/core/browser/form_saver.h
index 634c6a776ed..651853372b7 100644
--- a/chromium/components/password_manager/core/browser/form_saver.h
+++ b/chromium/components/password_manager/core/browser/form_saver.h
@@ -28,12 +28,11 @@ class FormSaver {
virtual void PermanentlyBlacklist(autofill::PasswordForm* observed) = 0;
// Saves the |pending| form and updates the stored preference on
- // |best_matches|. If |old_primary_key| is given, uses it for saving
- // |pending|.
- virtual void Save(const autofill::PasswordForm& pending,
- const std::map<base::string16,
- const autofill::PasswordForm*>& best_matches,
- const autofill::PasswordForm* old_primary_key) = 0;
+ // |best_matches|.
+ virtual void Save(
+ const autofill::PasswordForm& pending,
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ best_matches) = 0;
// Updates the |pending| form and updates the stored preference on
// |best_matches|. If |old_primary_key| is given, uses it for saving
diff --git a/chromium/components/password_manager/core/browser/form_saver_impl.cc b/chromium/components/password_manager/core/browser/form_saver_impl.cc
index be12e073c05..802cd1c5fe6 100644
--- a/chromium/components/password_manager/core/browser/form_saver_impl.cc
+++ b/chromium/components/password_manager/core/browser/form_saver_impl.cc
@@ -37,9 +37,8 @@ void FormSaverImpl::PermanentlyBlacklist(PasswordForm* observed) {
void FormSaverImpl::Save(
const PasswordForm& pending,
- const std::map<base::string16, const PasswordForm*>& best_matches,
- const PasswordForm* old_primary_key) {
- SaveImpl(pending, true, best_matches, nullptr, old_primary_key);
+ const std::map<base::string16, const PasswordForm*>& best_matches) {
+ SaveImpl(pending, true, best_matches, nullptr, nullptr);
}
void FormSaverImpl::Update(
diff --git a/chromium/components/password_manager/core/browser/form_saver_impl.h b/chromium/components/password_manager/core/browser/form_saver_impl.h
index 7fa8459873e..0833dc0ab63 100644
--- a/chromium/components/password_manager/core/browser/form_saver_impl.h
+++ b/chromium/components/password_manager/core/browser/form_saver_impl.h
@@ -27,8 +27,7 @@ class FormSaverImpl : public FormSaver {
void PermanentlyBlacklist(autofill::PasswordForm* observed) override;
void Save(const autofill::PasswordForm& pending,
const std::map<base::string16, const autofill::PasswordForm*>&
- best_matches,
- const autofill::PasswordForm* old_primary_key) override;
+ best_matches) override;
void Update(const autofill::PasswordForm& pending,
const std::map<base::string16, const autofill::PasswordForm*>&
best_matches,
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 bd5ed867496..49766a74282 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
@@ -107,8 +107,7 @@ TEST_F(FormSaverImplTest, Save_AsNew) {
EXPECT_CALL(*mock_store_, AddLogin(_)).WillOnce(SaveArg<0>(&saved));
EXPECT_CALL(*mock_store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
- form_saver_.Save(pending, std::map<base::string16, const PasswordForm*>(),
- nullptr);
+ form_saver_.Save(pending, std::map<base::string16, const PasswordForm*>());
EXPECT_EQ(ASCIIToUTF16("nameofuser"), saved.username_value);
EXPECT_EQ(ASCIIToUTF16("wordToP4a55"), saved.password_value);
}
@@ -206,7 +205,7 @@ TEST_F(FormSaverImplTest, Save_AndUpdatePreferredLoginState) {
EXPECT_CALL(*mock_store_, AddLogin(_)).WillOnce(SaveArg<0>(&saved));
EXPECT_CALL(*mock_store_, UpdateLogin(_)).WillOnce(SaveArg<0>(&updated));
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
- form_saver_.Save(pending, best_matches, nullptr);
+ form_saver_.Save(pending, best_matches);
EXPECT_EQ(ASCIIToUTF16("nameofuser"), saved.username_value);
EXPECT_EQ(ASCIIToUTF16("wordToP4a55"), saved.password_value);
EXPECT_TRUE(saved.preferred);
@@ -237,7 +236,7 @@ TEST_F(FormSaverImplTest, Save_AndDeleteEmptyUsernameCredentials) {
EXPECT_CALL(*mock_store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
EXPECT_CALL(*mock_store_, RemoveLogin(_)).WillOnce(SaveArg<0>(&removed));
- form_saver_.Save(pending, best_matches, nullptr);
+ form_saver_.Save(pending, best_matches);
EXPECT_EQ(ASCIIToUTF16("nameofuser"), saved.username_value);
EXPECT_EQ(ASCIIToUTF16("wordToP4a55"), saved.password_value);
EXPECT_TRUE(removed.username_value.empty());
@@ -265,7 +264,7 @@ TEST_F(FormSaverImplTest,
EXPECT_CALL(*mock_store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
EXPECT_CALL(*mock_store_, RemoveLogin(_)).Times(0);
- form_saver_.Save(pending, best_matches, nullptr);
+ form_saver_.Save(pending, best_matches);
EXPECT_EQ(ASCIIToUTF16("nameofuser"), saved.username_value);
EXPECT_EQ(ASCIIToUTF16("wordToP4a55"), saved.password_value);
}
@@ -291,7 +290,7 @@ TEST_F(FormSaverImplTest,
EXPECT_CALL(*mock_store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
EXPECT_CALL(*mock_store_, RemoveLogin(_)).Times(0);
- form_saver_.Save(pending, best_matches, nullptr);
+ form_saver_.Save(pending, best_matches);
EXPECT_EQ(ASCIIToUTF16("abc"), saved.username_value);
EXPECT_EQ(ASCIIToUTF16("def"), saved.password_value);
}
@@ -314,7 +313,7 @@ TEST_F(FormSaverImplTest, Save_EmptyUsernameWillNotCauseDeletion) {
EXPECT_CALL(*mock_store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
EXPECT_CALL(*mock_store_, RemoveLogin(_)).Times(0);
- form_saver_.Save(pending, best_matches, nullptr);
+ form_saver_.Save(pending, best_matches);
EXPECT_TRUE(saved.username_value.empty());
EXPECT_EQ(ASCIIToUTF16("wordToP4a55"), saved.password_value);
}
@@ -338,7 +337,7 @@ TEST_F(FormSaverImplTest, Save_AndDoNotDeleteEmptyUsernamePSLCredentials) {
EXPECT_CALL(*mock_store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
EXPECT_CALL(*mock_store_, RemoveLogin(_)).Times(0);
- form_saver_.Save(pending, best_matches, nullptr);
+ form_saver_.Save(pending, best_matches);
EXPECT_EQ(ASCIIToUTF16("nameofuser"), saved.username_value);
EXPECT_EQ(ASCIIToUTF16("wordToP4a55"), saved.password_value);
}
@@ -361,7 +360,7 @@ TEST_F(FormSaverImplTest, Save_AndDoNotDeleteNonEmptyUsernameCredentials) {
EXPECT_CALL(*mock_store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
EXPECT_CALL(*mock_store_, RemoveLogin(_)).Times(0);
- form_saver_.Save(pending, best_matches, nullptr);
+ form_saver_.Save(pending, best_matches);
EXPECT_EQ(ASCIIToUTF16("nameofuser"), saved.username_value);
EXPECT_EQ(ASCIIToUTF16("wordToP4a55"), saved.password_value);
}
@@ -416,8 +415,7 @@ TEST_F(FormSaverImplTest, PresaveGeneratedPassword_ThenSaveAsNew) {
EXPECT_CALL(*mock_store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _))
.WillOnce(DoAll(SaveArg<0>(&saved_new), SaveArg<1>(&saved_old)));
- form_saver_.Save(pending, std::map<base::string16, const PasswordForm*>(),
- nullptr);
+ form_saver_.Save(pending, std::map<base::string16, const PasswordForm*>());
EXPECT_EQ(ASCIIToUTF16("generatedU"), saved_old.username_value);
EXPECT_EQ(ASCIIToUTF16("generatedP"), saved_old.password_value);
EXPECT_EQ(ASCIIToUTF16("nameofuser"), saved_new.username_value);
diff --git a/chromium/components/password_manager/core/browser/hash_password_manager.cc b/chromium/components/password_manager/core/browser/hash_password_manager.cc
index d65b27d652d..ebbcf2ee168 100644
--- a/chromium/components/password_manager/core/browser/hash_password_manager.cc
+++ b/chromium/components/password_manager/core/browser/hash_password_manager.cc
@@ -7,11 +7,11 @@
#include "base/base64.h"
#include "base/strings/string_number_conversions.h"
#include "components/os_crypt/os_crypt.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/common/password_manager_pref_names.h"
#include "components/prefs/pref_service.h"
+#include "crypto/openssl_util.h"
#include "crypto/random.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
namespace {
constexpr size_t kSyncPasswordSaltLength = 16;
@@ -20,6 +20,22 @@ constexpr char kSeparator = '.';
namespace password_manager {
+SyncPasswordData::SyncPasswordData(const base::string16& password,
+ bool force_update)
+ : length(password.size()),
+ salt(HashPasswordManager::CreateRandomSalt()),
+ hash(HashPasswordManager::CalculateSyncPasswordHash(password, salt)),
+ force_update(force_update) {}
+
+bool SyncPasswordData::MatchesPassword(const base::string16& password) {
+ if (password.size() != this->length)
+ return false;
+ return HashPasswordManager::CalculateSyncPasswordHash(password, this->salt) ==
+ this->hash;
+}
+
+HashPasswordManager::HashPasswordManager(PrefService* prefs) : prefs_(prefs) {}
+
bool HashPasswordManager::SavePasswordHash(const base::string16& password) {
if (!prefs_)
return false;
@@ -28,21 +44,25 @@ bool HashPasswordManager::SavePasswordHash(const base::string16& password) {
RetrievePasswordHash();
// If it is the same password, no need to save password hash again.
if (current_sync_password_data.has_value() &&
- password_manager_util::CalculateSyncPasswordHash(
- password, current_sync_password_data->salt) ==
- current_sync_password_data->hash) {
+ current_sync_password_data->MatchesPassword(password)) {
return true;
}
- std::string salt = CreateRandomSalt();
- std::string hash = base::Uint64ToString(
- password_manager_util::CalculateSyncPasswordHash(password, salt));
- EncryptAndSaveToPrefs(prefs::kSyncPasswordHash, hash);
+ return SavePasswordHash(SyncPasswordData(password, true));
+}
- // Password length and salt are stored together.
- std::string length_salt = LengthAndSaltToString(salt, password.size());
- return EncryptAndSaveToPrefs(prefs::kSyncPasswordLengthAndHashSalt,
- length_salt);
+bool HashPasswordManager::SavePasswordHash(
+ const SyncPasswordData& sync_password_data) {
+ bool should_save = sync_password_data.force_update ||
+ !prefs_->HasPrefPath(prefs::kSyncPasswordHash);
+ return should_save ? (EncryptAndSaveToPrefs(
+ prefs::kSyncPasswordHash,
+ base::NumberToString(sync_password_data.hash)) &&
+ EncryptAndSaveToPrefs(
+ prefs::kSyncPasswordLengthAndHashSalt,
+ LengthAndSaltToString(sync_password_data.salt,
+ sync_password_data.length)))
+ : false;
}
void HashPasswordManager::ClearSavedPasswordHash() {
@@ -66,16 +86,11 @@ base::Optional<SyncPasswordData> HashPasswordManager::RetrievePasswordHash() {
return result;
}
-void HashPasswordManager::ReportIsSyncPasswordHashSavedMetric() {
- if (!prefs_)
- return;
- auto hash_password_state =
- prefs_->HasPrefPath(prefs::kSyncPasswordHash)
- ? metrics_util::IsSyncPasswordHashSaved::SAVED
- : metrics_util::IsSyncPasswordHashSaved::NOT_SAVED;
- metrics_util::LogIsSyncPasswordHashSaved(hash_password_state);
+bool HashPasswordManager::HasPasswordHash() {
+ return prefs_ ? prefs_->HasPrefPath(prefs::kSyncPasswordHash) : false;
}
+// static
std::string HashPasswordManager::CreateRandomSalt() {
char buffer[kSyncPasswordSaltLength];
crypto::RandBytes(buffer, kSyncPasswordSaltLength);
@@ -85,6 +100,42 @@ std::string HashPasswordManager::CreateRandomSalt() {
return result;
}
+// static
+uint64_t HashPasswordManager::CalculateSyncPasswordHash(
+ const base::StringPiece16& text,
+ const std::string& salt) {
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ constexpr size_t kBytesFromHash = 8;
+ constexpr uint64_t kScryptCost = 32; // It must be power of 2.
+ constexpr uint64_t kScryptBlockSize = 8;
+ constexpr uint64_t kScryptParallelization = 1;
+ constexpr size_t kScryptMaxMemory = 1024 * 1024;
+
+ uint8_t hash[kBytesFromHash];
+ base::StringPiece text_8bits(reinterpret_cast<const char*>(text.data()),
+ text.size() * 2);
+ const uint8_t* salt_ptr = reinterpret_cast<const uint8_t*>(salt.c_str());
+
+ int scrypt_ok = EVP_PBE_scrypt(text_8bits.data(), text_8bits.size(), salt_ptr,
+ salt.size(), kScryptCost, kScryptBlockSize,
+ kScryptParallelization, kScryptMaxMemory, hash,
+ kBytesFromHash);
+
+ // EVP_PBE_scrypt can only fail due to memory allocation error (which aborts
+ // Chromium) or invalid parameters. In case of a failure a hash could leak
+ // information from the stack, so using CHECK is better than DCHECK.
+ CHECK(scrypt_ok);
+
+ // Take 37 bits of |hash|.
+ uint64_t hash37 = ((static_cast<uint64_t>(hash[0]))) |
+ ((static_cast<uint64_t>(hash[1])) << 8) |
+ ((static_cast<uint64_t>(hash[2])) << 16) |
+ ((static_cast<uint64_t>(hash[3])) << 24) |
+ (((static_cast<uint64_t>(hash[4])) & 0x1F) << 32);
+
+ return hash37;
+}
+
std::string HashPasswordManager::LengthAndSaltToString(const std::string& salt,
size_t password_length) {
return base::NumberToString(password_length) + kSeparator + salt;
diff --git a/chromium/components/password_manager/core/browser/hash_password_manager.h b/chromium/components/password_manager/core/browser/hash_password_manager.h
index 217f4d4f816..8fc62196a96 100644
--- a/chromium/components/password_manager/core/browser/hash_password_manager.h
+++ b/chromium/components/password_manager/core/browser/hash_password_manager.h
@@ -14,9 +14,17 @@ class PrefService;
namespace password_manager {
struct SyncPasswordData {
- uint64_t hash;
- std::string salt;
+ SyncPasswordData() = default;
+ SyncPasswordData(const SyncPasswordData& other) = default;
+ SyncPasswordData(const base::string16& password, bool force_update);
+ bool MatchesPassword(const base::string16& password);
+
size_t length;
+ std::string salt;
+ uint64_t hash;
+ // Signal that we need to update password hash, salt, and length in profile
+ // prefs.
+ bool force_update;
};
// Responsible for saving, clearing, retrieving and encryption of a sync
@@ -25,21 +33,29 @@ struct SyncPasswordData {
class HashPasswordManager {
public:
HashPasswordManager() = default;
+ explicit HashPasswordManager(PrefService* prefs);
~HashPasswordManager() = default;
bool SavePasswordHash(const base::string16& password);
+ bool SavePasswordHash(const SyncPasswordData& sync_password_data);
void ClearSavedPasswordHash();
// Returns empty if no hash is available.
base::Optional<SyncPasswordData> RetrievePasswordHash();
- void ReportIsSyncPasswordHashSavedMetric();
+ // Whether |prefs_| has |kSyncPasswordHash| pref path.
+ bool HasPasswordHash();
void set_prefs(PrefService* prefs) { prefs_ = prefs; }
- private:
- std::string CreateRandomSalt();
+ static std::string CreateRandomSalt();
+ // Calculates 37 bits hash for a sync password. The calculation is based on a
+ // slow hash function. The running time is ~10^{-4} seconds on Desktop.
+ static uint64_t CalculateSyncPasswordHash(const base::StringPiece16& text,
+ const std::string& salt);
+
+ private:
// Packs |salt| and |password_length| to a string.
std::string LengthAndSaltToString(const std::string& salt,
size_t password_length);
diff --git a/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc b/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc
index 74559c5bfcc..5ff06f30fb7 100644
--- a/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc
@@ -6,7 +6,6 @@
#include "base/strings/utf_string_conversions.h"
#include "components/os_crypt/os_crypt_mocker.h"
-#include "components/password_manager/core/browser/password_manager_util.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"
@@ -39,24 +38,34 @@ TEST_F(HashPasswordManagerTest, Saving) {
ASSERT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
HashPasswordManager hash_password_manager;
hash_password_manager.set_prefs(&prefs_);
- hash_password_manager.SavePasswordHash(base::ASCIIToUTF16("sync_password"));
+ base::string16 password(base::UTF8ToUTF16("sync_password"));
+
+ // Verify |SavePasswordHash(const base::string16&)| behavior.
+ hash_password_manager.SavePasswordHash(password);
EXPECT_TRUE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
// Saves the same password again won't change password hash, length or salt.
const std::string current_hash = prefs_.GetString(prefs::kSyncPasswordHash);
const std::string current_length_and_salt =
prefs_.GetString(prefs::kSyncPasswordLengthAndHashSalt);
- hash_password_manager.SavePasswordHash(base::ASCIIToUTF16("sync_password"));
+ hash_password_manager.SavePasswordHash(password);
EXPECT_EQ(current_hash, prefs_.GetString(prefs::kSyncPasswordHash));
EXPECT_EQ(current_length_and_salt,
prefs_.GetString(prefs::kSyncPasswordLengthAndHashSalt));
+
+ // Verify |SavePasswordHash(const SyncPasswordData&)| behavior.
+ base::string16 new_password(base::UTF8ToUTF16("new_sync_password"));
+ SyncPasswordData sync_password_data(new_password, /*force_update=*/true);
+ EXPECT_TRUE(sync_password_data.MatchesPassword(new_password));
+ hash_password_manager.SavePasswordHash(sync_password_data);
+ EXPECT_TRUE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
}
TEST_F(HashPasswordManagerTest, Clearing) {
ASSERT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
HashPasswordManager hash_password_manager;
hash_password_manager.set_prefs(&prefs_);
- hash_password_manager.SavePasswordHash(base::ASCIIToUTF16("sync_password"));
+ hash_password_manager.SavePasswordHash(base::UTF8ToUTF16("sync_password"));
hash_password_manager.ClearSavedPasswordHash();
EXPECT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
}
@@ -65,7 +74,7 @@ TEST_F(HashPasswordManagerTest, Retrieving) {
ASSERT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
HashPasswordManager hash_password_manager;
hash_password_manager.set_prefs(&prefs_);
- hash_password_manager.SavePasswordHash(base::ASCIIToUTF16("sync_password"));
+ hash_password_manager.SavePasswordHash(base::UTF8ToUTF16("sync_password"));
EXPECT_TRUE(prefs_.HasPrefPath(prefs::kSyncPasswordLengthAndHashSalt));
base::Optional<SyncPasswordData> sync_password_data =
@@ -73,10 +82,32 @@ TEST_F(HashPasswordManagerTest, Retrieving) {
ASSERT_TRUE(sync_password_data);
EXPECT_EQ(13u, sync_password_data->length);
EXPECT_EQ(16u, sync_password_data->salt.size());
- uint64_t expected_hash = password_manager_util::CalculateSyncPasswordHash(
- base::ASCIIToUTF16("sync_password"), sync_password_data->salt);
+ uint64_t expected_hash = HashPasswordManager::CalculateSyncPasswordHash(
+ base::UTF8ToUTF16("sync_password"), sync_password_data->salt);
EXPECT_EQ(expected_hash, sync_password_data->hash);
}
+TEST_F(HashPasswordManagerTest, CalculateSyncPasswordHash) {
+ const char* kPlainText[] = {"", "password", "password", "secret"};
+ const char* kSalt[] = {"", "salt", "123", "456"};
+
+ constexpr uint64_t kExpectedHash[] = {
+ UINT64_C(0x1c610a7950), UINT64_C(0x1927dc525e), UINT64_C(0xf72f81aa6),
+ UINT64_C(0x3645af77f),
+ };
+
+ static_assert(arraysize(kPlainText) == arraysize(kSalt),
+ "Arrays must have the same size");
+ static_assert(arraysize(kPlainText) == arraysize(kExpectedHash),
+ "Arrays must have the same size");
+
+ for (size_t i = 0; i < arraysize(kPlainText); ++i) {
+ SCOPED_TRACE(i);
+ base::string16 text = base::UTF8ToUTF16(kPlainText[i]);
+ EXPECT_EQ(kExpectedHash[i],
+ HashPasswordManager::CalculateSyncPasswordHash(text, kSalt[i]));
+ }
+}
+
} // namespace
} // 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 5870ea411bc..8c0767774f2 100644
--- a/chromium/components/password_manager/core/browser/login_database.cc
+++ b/chromium/components/password_manager/core/browser/login_database.cc
@@ -16,8 +16,8 @@
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
#include "base/numerics/safe_conversions.h"
#include "base/pickle.h"
#include "base/stl_util.h"
@@ -600,8 +600,8 @@ bool LoginDatabase::Init() {
meta_table_.SetVersionNumber(kCurrentVersionNumber);
} else {
LogDatabaseInitError(MIGRATION_ERROR);
- UMA_HISTOGRAM_SPARSE_SLOWLY("PasswordManager.LoginDatabaseFailedVersion",
- meta_table_.GetVersionNumber());
+ base::UmaHistogramSparse("PasswordManager.LoginDatabaseFailedVersion",
+ meta_table_.GetVersionNumber());
LOG(ERROR) << "Unable to migrate database from "
<< meta_table_.GetVersionNumber() << " to "
<< kCurrentVersionNumber;
diff --git a/chromium/components/password_manager/core/browser/mock_password_store.h b/chromium/components/password_manager/core/browser/mock_password_store.h
index 18a9cc62bfb..11603b98e2b 100644
--- a/chromium/components/password_manager/core/browser/mock_password_store.h
+++ b/chromium/components/password_manager/core/browser/mock_password_store.h
@@ -76,11 +76,9 @@ class MockPasswordStore : public PasswordStore {
void(const base::string16&,
const std::string&,
PasswordReuseDetectorConsumer*));
-#if !defined(OS_CHROMEOS)
MOCK_METHOD1(SaveSyncPasswordHash, void(const base::string16&));
MOCK_METHOD0(ClearSyncPasswordHash, void());
#endif
-#endif
PasswordStoreSync* GetSyncInterface() { return this; }
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 1fa952acc98..187b77b4630 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
@@ -32,6 +32,7 @@
#include "components/strings/grit/components_strings.h"
#include "components/sync/driver/fake_sync_service.h"
#include "components/ukm/test_ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
@@ -55,6 +56,8 @@ using autofill::SuggestionVectorValuesAre;
using autofill::SuggestionVectorLabelsAre;
using testing::_;
+using UkmEntry = ukm::builders::PageWithPassword;
+
namespace autofill {
class AutofillPopupDelegate;
}
@@ -1178,17 +1181,18 @@ TEST_F(PasswordAutofillManagerTest, ShowAllPasswordsOptionOnPasswordField) {
kAcceptedContextHistogram,
metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_PASSWORD, 1);
// Trigger UKM reporting, which happens at destruction time.
+ ukm::SourceId expected_source_id = client->GetUkmSourceId();
manager.reset();
autofill_client.reset();
client.reset();
const auto& entries =
- test_ukm_recorder.GetEntriesByName("PageWithPassword");
+ test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(1u, entries.size());
for (const auto* entry : entries) {
- test_ukm_recorder.ExpectEntrySourceHasUrl(entry, GURL(kMainFrameUrl));
+ EXPECT_EQ(expected_source_id, entry->source_id);
test_ukm_recorder.ExpectEntryMetric(
- entry, password_manager::kUkmPageLevelUserAction,
+ entry, UkmEntry::kPageLevelUserActionName,
static_cast<int64_t>(
password_manager::PasswordManagerMetricsRecorder::
PageLevelUserAction::kShowAllPasswordsWhileSomeAreSuggested));
@@ -1267,6 +1271,7 @@ TEST_F(PasswordAutofillManagerTest, ShowStandaloneShowAllPasswords) {
kAcceptedContextHistogram,
metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_MANUAL_FALLBACK, 1);
// Trigger UKM reporting, which happens at destruction time.
+ ukm::SourceId expected_source_id = client->GetUkmSourceId();
manager.reset();
autofill_client.reset();
client.reset();
@@ -1275,9 +1280,9 @@ TEST_F(PasswordAutofillManagerTest, ShowStandaloneShowAllPasswords) {
test_ukm_recorder.GetEntriesByName("PageWithPassword");
EXPECT_EQ(1u, entries.size());
for (const auto* entry : entries) {
- test_ukm_recorder.ExpectEntrySourceHasUrl(entry, GURL(kMainFrameUrl));
+ EXPECT_EQ(expected_source_id, entry->source_id);
test_ukm_recorder.ExpectEntryMetric(
- entry, password_manager::kUkmPageLevelUserAction,
+ entry, UkmEntry::kPageLevelUserActionName,
static_cast<int64_t>(
password_manager::PasswordManagerMetricsRecorder::
PageLevelUserAction::kShowAllPasswordsWhileNoneAreSuggested));
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 ee374a28cb9..18b678fcf10 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager.cc
@@ -56,12 +56,6 @@ std::vector<std::string> SplitPathToSegments(const std::string& path) {
base::SPLIT_WANT_ALL);
}
-// Return false iff the strings are neither empty nor equal.
-bool AreStringsEqualOrEmpty(const base::string16& s1,
- const base::string16& s2) {
- return s1.empty() || s2.empty() || s1 == s2;
-}
-
bool DoesStringContainOnlyDigits(const base::string16& s) {
for (auto c : s) {
if (!base::IsAsciiDigit(c))
@@ -192,8 +186,11 @@ void LabelFields(const FieldTypeMap& field_types,
if (iter != field_types.end()) {
type = iter->second;
available_field_types->insert(type);
- if (type == autofill::USERNAME)
+ if (type == autofill::USERNAME) {
field->set_username_vote_type(username_vote_type);
+ DCHECK_NE(autofill::AutofillUploadContents::Field::NO_INFORMATION,
+ username_vote_type);
+ }
}
}
@@ -261,8 +258,7 @@ void PasswordFormManager::Init(
metrics_recorder_ = std::move(metrics_recorder);
if (!metrics_recorder_) {
metrics_recorder_ = base::MakeRefCounted<PasswordFormMetricsRecorder>(
- client_->IsMainFrameSecure(), client_->GetUkmRecorder(),
- client_->GetUkmSourceId(), client_->GetMainFrameURL());
+ client_->IsMainFrameSecure(), client_->GetUkmSourceId());
}
if (owned_form_fetcher_)
@@ -409,17 +405,17 @@ void PasswordFormManager::Save() {
DidPreferenceChange(best_matches_, pending_credentials_.username_value)) {
SetUserAction(UserAction::kChoose);
}
- base::Optional<PasswordForm> old_primary_key;
+
if (is_new_login_) {
SanitizePossibleUsernames(&pending_credentials_);
pending_credentials_.date_created = base::Time::Now();
SendVotesOnSave();
- form_saver_->Save(pending_credentials_, best_matches_,
- old_primary_key ? &old_primary_key.value() : nullptr);
+ form_saver_->Save(pending_credentials_, best_matches_);
} else {
ProcessUpdate();
std::vector<PasswordForm> credentials_to_update;
- old_primary_key = UpdatePendingAndGetOldKey(&credentials_to_update);
+ base::Optional<PasswordForm> old_primary_key =
+ UpdatePendingAndGetOldKey(&credentials_to_update);
form_saver_->Update(pending_credentials_, best_matches_,
&credentials_to_update,
old_primary_key ? &old_primary_key.value() : nullptr);
@@ -463,28 +459,41 @@ void PasswordFormManager::Update(
}
void PasswordFormManager::UpdateUsername(const base::string16& new_username) {
- pending_credentials_.username_value = new_username;
- // Check if the username already exists.
- const PasswordForm* match = FindBestSavedMatch(&pending_credentials_);
- is_new_login_ = !match || match->is_public_suffix_match;
- // Searching for the field of |match| where |new_username| was typed. If it is
- // found, the field name is saved to |corrected_username_element_|. Otherwise,
- // |corrected_username_element_| has no value.
- base::string16 trimmed_username_value;
- base::TrimString(new_username, base::ASCIIToUTF16(" "),
- &trimmed_username_value);
- corrected_username_element_.reset();
- if (!trimmed_username_value.empty()) {
- for (size_t i = 0; i < pending_credentials_.other_possible_usernames.size();
- ++i) {
- if (pending_credentials_.other_possible_usernames[i].first ==
- trimmed_username_value) {
- corrected_username_element_ =
- pending_credentials_.other_possible_usernames[i].second;
+ PasswordForm credential(*submitted_form_);
+ credential.username_value = new_username;
+ // If |new_username| is not found in |other_possible_usernames|, store empty
+ // |username_element|.
+ credential.username_element.clear();
+
+ // |has_username_edited_vote_| is true iff |new_username| was typed in another
+ // field. Otherwise, |has_username_edited_vote_| is false and no vote will be
+ // uploaded.
+ has_username_edited_vote_ = false;
+ if (!new_username.empty()) {
+ for (size_t i = 0; i < credential.other_possible_usernames.size(); ++i) {
+ if (credential.other_possible_usernames[i].first == new_username) {
+ credential.username_element =
+ credential.other_possible_usernames[i].second;
+
+ credential.other_possible_usernames.erase(
+ credential.other_possible_usernames.begin() + i);
+
+ // Set |corrected_username_element_| to upload a username vote.
+ has_username_edited_vote_ = true;
break;
}
}
}
+ // A user may make a mistake and remove the correct username. So, save
+ // |username_value| and |username_element| of the submitted form. When the
+ // user has to override the username, Chrome will send a username vote.
+ if (!submitted_form_->username_value.empty()) {
+ credential.other_possible_usernames.push_back(
+ autofill::PossibleUsernamePair(submitted_form_->username_value,
+ submitted_form_->username_element));
+ }
+
+ ProvisionallySave(credential, IGNORE_OTHER_POSSIBLE_USERNAMES);
}
void PasswordFormManager::UpdatePasswordValue(
@@ -517,7 +526,7 @@ void PasswordFormManager::SaveSubmittedFormTypeForMetrics(
!form.new_password_value.empty() && !form.password_value.empty();
bool is_signup_form =
!form.new_password_value.empty() && form.password_value.empty();
- bool no_username = form.username_element.empty();
+ bool no_username = form.username_value.empty();
PasswordFormMetricsRecorder::SubmittedFormType type =
PasswordFormMetricsRecorder::kSubmittedFormTypeUnspecified;
@@ -597,7 +606,6 @@ void PasswordFormManager::ProcessMatches(
size_t filtered_count) {
blacklisted_matches_.clear();
new_blacklisted_.reset();
- blacklisted_origin_found_ = false;
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
@@ -614,15 +622,6 @@ void PasswordFormManager::ProcessMatches(
[this](const PasswordForm* form) { return IsMatch(*form); });
ScoreMatches(matches);
- auto find_blacklisted_match_it = std::find_if(
- non_federated.begin(), non_federated.end(),
- [this](const PasswordForm* form) {
- return form->blacklisted_by_user &&
- form->origin.GetOrigin() == observed_form_.origin.GetOrigin();
- });
- blacklisted_origin_found_ =
- (find_blacklisted_match_it != non_federated.end());
-
// Copy out blacklisted matches.
blacklisted_matches_.resize(std::count_if(
non_federated.begin(), non_federated.end(),
@@ -674,7 +673,7 @@ void PasswordFormManager::ProcessFrameInternal(
if (!driver)
return;
- if (blacklisted_origin_found_)
+ if (IsBlacklisted())
driver->MatchingBlacklistedFormFound();
driver->AllowPasswordGenerationForForm(observed_form_);
@@ -794,6 +793,8 @@ bool PasswordFormManager::FindUsernameInOtherPossibleUsernames(
bool PasswordFormManager::FindCorrectedUsernameElement(
const base::string16& username,
const base::string16& password) {
+ if (username.empty())
+ return false;
for (const auto& key_value : best_matches_) {
const PasswordForm* match = key_value.second;
if ((match->password_value == password) &&
@@ -856,10 +857,10 @@ void PasswordFormManager::SendVoteOnCredentialsReuse(
bool PasswordFormManager::UploadPasswordVote(
const autofill::PasswordForm& form_to_upload,
- const autofill::ServerFieldType& password_type,
+ const autofill::ServerFieldType& autofill_type,
const std::string& login_form_signature) {
// Check if there is any vote to be sent.
- bool has_autofill_vote = password_type != autofill::UNKNOWN_TYPE;
+ bool has_autofill_vote = autofill_type != autofill::UNKNOWN_TYPE;
bool has_password_generation_vote = generation_popup_was_shown_;
if (!has_autofill_vote && !has_password_generation_vote)
return false;
@@ -883,37 +884,44 @@ bool PasswordFormManager::UploadPasswordVote(
FieldTypeMap field_types;
autofill::AutofillUploadContents::Field::UsernameVoteType username_vote_type =
autofill::AutofillUploadContents::Field::NO_INFORMATION;
- if (password_type != autofill::USERNAME) {
+ if (autofill_type != autofill::USERNAME) {
if (has_autofill_vote) {
DCHECK(submitted_form_);
- bool is_update = password_type == autofill::NEW_PASSWORD ||
- password_type == autofill::PROBABLY_NEW_PASSWORD ||
- password_type == autofill::NOT_NEW_PASSWORD;
+ bool is_update = autofill_type == autofill::NEW_PASSWORD ||
+ autofill_type == autofill::PROBABLY_NEW_PASSWORD ||
+ autofill_type == autofill::NOT_NEW_PASSWORD;
if (is_update) {
if (submitted_form_->new_password_element.empty())
return false;
- SetFieldLabelsOnUpdate(password_type, *submitted_form_, &field_types);
+ SetFieldLabelsOnUpdate(autofill_type, *submitted_form_, &field_types);
} else { // Saving.
- SetFieldLabelsOnSave(password_type, *submitted_form_, &field_types);
+ SetFieldLabelsOnSave(autofill_type, *submitted_form_, &field_types);
}
field_types[submitted_form_->confirmation_password_element] =
autofill::CONFIRMATION_PASSWORD;
}
- if (password_type != autofill::ACCOUNT_CREATION_PASSWORD) {
+ if (autofill_type != autofill::ACCOUNT_CREATION_PASSWORD) {
if (generation_popup_was_shown_)
AddGeneratedVote(&form_structure);
if (form_classifier_outcome_ != kNoOutcome)
AddFormClassifierVote(&form_structure);
+ if (has_username_edited_vote_) {
+ field_types[form_to_upload.username_element] = autofill::USERNAME;
+ username_vote_type =
+ autofill::AutofillUploadContents::Field::USERNAME_EDITED;
+ }
} else { // User reuses credentials.
- field_types[form_to_upload.username_element] = autofill::USERNAME;
- username_vote_type =
- autofill::AutofillUploadContents::Field::CREDENTIALS_REUSED;
- }
- if (corrected_username_element_.has_value()) {
- field_types[corrected_username_element_.value()] = autofill::USERNAME;
- username_vote_type =
- autofill::AutofillUploadContents::Field::USERNAME_EDITED;
+ // If the saved username value was used, then send a confirmation vote for
+ // username.
+ if (!submitted_form_->username_value.empty()) {
+ DCHECK(submitted_form_->username_value ==
+ form_to_upload.username_value);
+ field_types[form_to_upload.username_element] = autofill::USERNAME;
+ username_vote_type =
+ autofill::AutofillUploadContents::Field::CREDENTIALS_REUSED;
+ }
}
+
} else { // User overwrites username.
field_types[form_to_upload.username_element] = autofill::USERNAME;
field_types[form_to_upload.password_element] =
@@ -1085,7 +1093,7 @@ void PasswordFormManager::CreatePendingCredentials() {
is_new_login_ = false;
} else if (!best_matches_.empty() &&
submitted_form_->type != autofill::PasswordForm::TYPE_API &&
- submitted_form_->username_element.empty()) {
+ submitted_form_->username_value.empty()) {
// This branch deals with the case that the submitted form has no username
// element and needs to decide whether to offer to update any credentials.
// In that case, the user can select any previously stored credential as
@@ -1099,8 +1107,8 @@ void PasswordFormManager::CreatePendingCredentials() {
// A retry password form is one that consists of only an "old password"
// field, i.e. one that is not a "new password".
retry_password_form_password_update_ =
- submitted_form_->username_element.empty() &&
- submitted_form_->new_password_element.empty();
+ submitted_form_->username_value.empty() &&
+ submitted_form_->new_password_value.empty();
is_new_login_ = false;
if (best_update_match) {
@@ -1120,6 +1128,7 @@ void PasswordFormManager::CreatePendingCredentials() {
pending_credentials_.origin = submitted_form_->origin;
}
} else {
+ is_new_login_ = true;
// No stored credentials can be matched to the submitted form. Offer to
// save new credentials.
CreatePendingCredentialsForNewCredentials();
@@ -1246,25 +1255,11 @@ bool PasswordFormManager::IsMatch(const autofill::PasswordForm& form) const {
bool PasswordFormManager::IsBlacklistMatch(
const autofill::PasswordForm& blacklisted_form) const {
- if (!blacklisted_form.blacklisted_by_user ||
- blacklisted_form.is_public_suffix_match ||
- blacklisted_form.scheme != observed_form_.scheme ||
- blacklisted_form.origin.GetOrigin() !=
- observed_form_.origin.GetOrigin()) {
- return false;
- }
-
- if (observed_form_.scheme == PasswordForm::SCHEME_HTML) {
- return (blacklisted_form.origin.path_piece() ==
- observed_form_.origin.path_piece()) ||
- (AreStringsEqualOrEmpty(blacklisted_form.submit_element,
- observed_form_.submit_element) &&
- AreStringsEqualOrEmpty(blacklisted_form.password_element,
- observed_form_.password_element) &&
- AreStringsEqualOrEmpty(blacklisted_form.username_element,
- observed_form_.username_element));
- }
- return true;
+ return blacklisted_form.blacklisted_by_user &&
+ !blacklisted_form.is_public_suffix_match &&
+ blacklisted_form.scheme == observed_form_.scheme &&
+ blacklisted_form.origin.GetOrigin() ==
+ observed_form_.origin.GetOrigin();
}
const PasswordForm* PasswordFormManager::FindBestMatchForUpdatePassword(
@@ -1306,9 +1301,9 @@ const PasswordForm* PasswordFormManager::FindBestSavedMatch(
// Verify that the submitted form has no username and no "new password"
// and bail out with a nullptr otherwise.
- bool submitted_form_has_username = !submitted_form->username_element.empty();
+ bool submitted_form_has_username = !submitted_form->username_value.empty();
bool submitted_form_has_new_password_element =
- !submitted_form->new_password_element.empty();
+ !submitted_form->new_password_value.empty();
if (submitted_form_has_username || submitted_form_has_new_password_element)
return nullptr;
@@ -1326,8 +1321,7 @@ void PasswordFormManager::CreatePendingCredentialsForNewCredentials() {
// User typed in a new, unknown username.
SetUserAction(UserAction::kOverrideUsernameAndPassword);
pending_credentials_ = observed_form_;
- if (submitted_form_->was_parsed_using_autofill_predictions)
- pending_credentials_.username_element = submitted_form_->username_element;
+ pending_credentials_.username_element = submitted_form_->username_element;
pending_credentials_.username_value = submitted_form_->username_value;
pending_credentials_.other_possible_usernames =
submitted_form_->other_possible_usernames;
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 c40125a6780..ea76f0b5c94 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.h
+++ b/chromium/components/password_manager/core/browser/password_form_manager.h
@@ -597,14 +597,9 @@ class PasswordFormManager : public FormFetcher::Consumer {
// Make sure to call Init before using |*this|, to ensure it is not null.
scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder_;
- // Set if the user has edited username value in prompt. The value is the
- // matched field name from |PasswordForm.other_possible_usernames| if the
- // match found.
- base::Optional<base::string16> corrected_username_element_;
-
- // Tracks if a form with same origin as |observed_form_| found in blacklisted
- // forms.
- bool blacklisted_origin_found_ = false;
+ // True iff a user edited the username value in a prompt and new username is
+ // the value of another field of the observed form.
+ bool has_username_edited_vote_ = false;
// If Chrome has already autofilled a few times, it is probable that autofill
// is triggered by programmatic changes in the page. We set a maximum number
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 7625fe3256d..9f66ed38774 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
@@ -57,11 +57,13 @@ using autofill::PasswordForm;
using autofill::PossibleUsernamePair;
using base::ASCIIToUTF16;
using ::testing::_;
+using ::testing::Contains;
using ::testing::ElementsAre;
using ::testing::InSequence;
using ::testing::IsEmpty;
using ::testing::Mock;
using ::testing::NiceMock;
+using ::testing::Not;
using ::testing::Pair;
using ::testing::Pointee;
using ::testing::Return;
@@ -85,11 +87,10 @@ class MockFormSaver : public StubFormSaver {
// FormSaver:
MOCK_METHOD1(PermanentlyBlacklist, void(autofill::PasswordForm* observed));
- MOCK_METHOD3(
+ MOCK_METHOD2(
Save,
void(const autofill::PasswordForm& pending,
- const std::map<base::string16, const PasswordForm*>& best_matches,
- const autofill::PasswordForm* old_primary_key));
+ const std::map<base::string16, const PasswordForm*>& best_matches));
MOCK_METHOD4(
Update,
void(const autofill::PasswordForm& pending,
@@ -296,11 +297,12 @@ class MockAutofillManager : public autofill::AutofillManager {
}
// Workaround for std::unique_ptr<> lacking a copy constructor.
- void StartUploadProcess(std::unique_ptr<FormStructure> form_structure,
+ bool StartUploadProcess(std::unique_ptr<FormStructure> form_structure,
const base::TimeTicks& timestamp,
bool observed_submission) {
StartUploadProcessPtr(form_structure.release(), timestamp,
observed_submission);
+ return true;
}
MOCK_METHOD3(StartUploadProcessPtr,
@@ -406,13 +408,6 @@ class PasswordFormManagerTest : public testing::Test {
saved_match_.other_possible_usernames.push_back(PossibleUsernamePair(
ASCIIToUTF16("test2@gmail.com"), ASCIIToUTF16("full_name")));
- psl_saved_match_ = saved_match_;
- psl_saved_match_.is_public_suffix_match = true;
- psl_saved_match_.origin =
- GURL("http://m.accounts.google.com/a/ServiceLoginAuth");
- psl_saved_match_.action = GURL("http://m.accounts.google.com/a/Login");
- psl_saved_match_.signon_realm = "http://m.accounts.google.com";
-
autofill::FormFieldData field;
field.label = ASCIIToUTF16("Full name");
field.name = ASCIIToUTF16("full_name");
@@ -429,6 +424,13 @@ class PasswordFormManagerTest : public testing::Test {
field.form_control_type = "password";
saved_match_.form_data.fields.push_back(field);
+ psl_saved_match_ = saved_match_;
+ psl_saved_match_.is_public_suffix_match = true;
+ psl_saved_match_.origin =
+ GURL("http://m.accounts.google.com/a/ServiceLoginAuth");
+ psl_saved_match_.action = GURL("http://m.accounts.google.com/a/Login");
+ psl_saved_match_.signon_realm = "http://m.accounts.google.com";
+
password_manager_.reset(new PasswordManager(&client_));
form_manager_.reset(new PasswordFormManager(
password_manager_.get(), &client_, client_.driver(), observed_form_,
@@ -992,63 +994,35 @@ TEST_F(PasswordFormManagerTest, TestBlacklist) {
// Test that stored blacklisted forms are correctly evaluated for whether they
// apply to the observed form.
TEST_F(PasswordFormManagerTest, TestBlacklistMatching) {
- observed_form()->origin = GURL("http://accounts.google.com/a/LoginAuth");
- observed_form()->action = GURL("http://accounts.google.com/a/Login");
- observed_form()->signon_realm = "http://accounts.google.com";
- FakeFormFetcher fetcher;
- fetcher.Fetch();
- PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(),
- std::make_unique<MockFormSaver>(), &fetcher);
- form_manager.Init(nullptr);
-
// Doesn't apply because it is just a PSL match of the observed form.
PasswordForm blacklisted_psl = *observed_form();
blacklisted_psl.signon_realm = "http://m.accounts.google.com";
blacklisted_psl.is_public_suffix_match = true;
blacklisted_psl.blacklisted_by_user = true;
- // Doesn't apply because of different origin.
- PasswordForm blacklisted_not_match = *observed_form();
- blacklisted_not_match.origin = GURL("http://google.com/a/LoginAuth");
- blacklisted_not_match.blacklisted_by_user = true;
-
- // Doesn't apply because of different username element and different page.
- PasswordForm blacklisted_not_match2 = *observed_form();
- blacklisted_not_match2.origin = GURL("http://accounts.google.com/a/Login123");
- blacklisted_not_match2.username_element = ASCIIToUTF16("Element");
- blacklisted_not_match2.blacklisted_by_user = true;
-
// Doesn't apply because of different PasswordForm::Scheme.
- PasswordForm blacklisted_not_match3 = *observed_form();
- blacklisted_not_match3.scheme = PasswordForm::SCHEME_BASIC;
+ PasswordForm blacklisted_not_match = *observed_form();
+ blacklisted_not_match.scheme = PasswordForm::SCHEME_BASIC;
- // Applies because of same element names, despite different page
+ // Applies despite different element names and path.
PasswordForm blacklisted_match = *observed_form();
blacklisted_match.origin = GURL("http://accounts.google.com/a/LoginAuth1234");
+ blacklisted_match.username_element = ASCIIToUTF16("Element1");
+ blacklisted_match.password_element = ASCIIToUTF16("Element2");
+ blacklisted_match.submit_element = ASCIIToUTF16("Element3");
blacklisted_match.blacklisted_by_user = true;
- // Applies because of same page, despite different element names
- PasswordForm blacklisted_match2 = *observed_form();
- blacklisted_match2.origin = GURL("http://accounts.google.com/a/LoginAuth");
- blacklisted_match2.username_element = ASCIIToUTF16("Element");
- blacklisted_match2.blacklisted_by_user = true;
-
std::vector<const PasswordForm*> matches = {&blacklisted_psl,
&blacklisted_not_match,
- &blacklisted_not_match2,
- &blacklisted_not_match3,
&blacklisted_match,
- &blacklisted_match2,
saved_match()};
- fetcher.SetNonFederated(matches, 0u);
+ fake_form_fetcher()->SetNonFederated(matches, 0u);
- EXPECT_TRUE(form_manager.IsBlacklisted());
- EXPECT_THAT(form_manager.blacklisted_matches(),
- UnorderedElementsAre(Pointee(blacklisted_match),
- Pointee(blacklisted_match2)));
- EXPECT_EQ(1u, form_manager.best_matches().size());
- EXPECT_EQ(*saved_match(), *form_manager.preferred_match());
+ EXPECT_TRUE(form_manager()->IsBlacklisted());
+ EXPECT_THAT(form_manager()->blacklisted_matches(),
+ ElementsAre(Pointee(blacklisted_match)));
+ EXPECT_EQ(1u, form_manager()->best_matches().size());
+ EXPECT_EQ(*saved_match(), *form_manager()->preferred_match());
}
// Test that even in the presence of blacklisted matches, the non-blacklisted
@@ -1122,7 +1096,7 @@ TEST_F(PasswordFormManagerTest, PSLMatchedCredentialsMetadataUpdated) {
EXPECT_CALL(
*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(_, false, expected_available_field_types, _, true));
- EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, _, nullptr))
+ EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, _))
.WillOnce(SaveArg<0>(&actual_saved_form));
form_manager()->Save();
@@ -1538,7 +1512,7 @@ TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernames) {
credentials, PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES);
PasswordForm saved_result;
- EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, _, nullptr))
+ EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, _))
.WillOnce(SaveArg<0>(&saved_result));
form_manager()->Save();
@@ -1574,7 +1548,7 @@ TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernamesDuplicates) {
credentials, PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES);
PasswordForm saved_result;
- EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, _, nullptr))
+ EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, _))
.WillOnce(SaveArg<0>(&saved_result));
form_manager()->Save();
@@ -2097,7 +2071,7 @@ TEST_F(PasswordFormManagerTest, CorrectlySavePasswordWithoutUsernameFields) {
EXPECT_TRUE(form_manager()->IsNewLogin());
PasswordForm saved_result;
- EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, _, nullptr))
+ EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, _))
.WillOnce(SaveArg<0>(&saved_result));
form_manager()->Save();
@@ -2356,101 +2330,296 @@ TEST_F(PasswordFormManagerTest, TestUpdateNoUsernameTextfieldPresent) {
EXPECT_EQ(saved_match()->submit_element, new_credentials.submit_element);
}
-// Test that when user updates username, the pending credentials is updated
-// accordingly.
-TEST_F(PasswordFormManagerTest, TestUpdateUsernameMethod) {
- fake_form_fetcher()->SetNonFederated(std::vector<const PasswordForm*>(), 0u);
+// Test the case when a user changes the username to the value of another field
+// from the form.
+TEST_F(PasswordFormManagerTest, UpdateUsername_ValueOfAnotherField) {
+ for (bool captured_username_is_empty : {false, true}) {
+ SCOPED_TRACE(testing::Message() << "captured_username_is_empty="
+ << captured_username_is_empty);
+ PasswordForm observed(*observed_form());
+ // Set |FormData| to upload a username vote.
+ autofill::FormFieldData field;
+ field.name = ASCIIToUTF16("full_name");
+ field.form_control_type = "text";
+ observed.form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("correct_username_element");
+ field.form_control_type = "text";
+ observed.form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("Passwd");
+ field.form_control_type = "password";
+ observed.form_data.fields.push_back(field);
- // User enters credential in the form.
- PasswordForm credential(*observed_form());
- credential.username_value = ASCIIToUTF16("oldusername");
- credential.password_value = ASCIIToUTF16("password");
- form_manager()->ProvisionallySave(
- credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
- // User edits username in a prompt.
- form_manager()->UpdateUsername(ASCIIToUTF16("newusername"));
- EXPECT_EQ(form_manager()->pending_credentials().username_value,
- ASCIIToUTF16("newusername"));
- EXPECT_EQ(form_manager()->pending_credentials().password_value,
- ASCIIToUTF16("password"));
- EXPECT_EQ(form_manager()->IsNewLogin(), true);
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), observed,
+ std::make_unique<NiceMock<MockFormSaver>>(), fake_form_fetcher());
+ form_manager.Init(nullptr);
+ fake_form_fetcher()->SetNonFederated(std::vector<const PasswordForm*>(),
+ 0u);
+
+ // User enters credential in the form.
+ PasswordForm credential(observed);
+ credential.username_value = captured_username_is_empty
+ ? base::string16()
+ : ASCIIToUTF16("typed_username");
+ credential.password_value = ASCIIToUTF16("password");
+ credential.other_possible_usernames.push_back(
+ PossibleUsernamePair(ASCIIToUTF16("edited_username"),
+ ASCIIToUTF16("correct_username_element")));
+ form_manager.ProvisionallySave(
+ credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+
+ // User edits username in a prompt.
+ form_manager.UpdateUsername(ASCIIToUTF16("edited_username"));
+ EXPECT_EQ(form_manager.pending_credentials().username_value,
+ ASCIIToUTF16("edited_username"));
+ EXPECT_EQ(form_manager.pending_credentials().username_element,
+ ASCIIToUTF16("correct_username_element"));
+ EXPECT_EQ(form_manager.pending_credentials().password_value,
+ ASCIIToUTF16("password"));
+ EXPECT_TRUE(form_manager.IsNewLogin());
- // User clicks save, edited username is saved.
- PasswordForm saved_result;
- EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, IsEmpty(), nullptr))
- .WillOnce(SaveArg<0>(&saved_result));
- form_manager()->Save();
- EXPECT_EQ(ASCIIToUTF16("newusername"), saved_result.username_value);
- EXPECT_EQ(ASCIIToUTF16("password"), saved_result.password_value);
+ // User clicks save, the edited username is saved.
+ PasswordForm saved_result;
+ EXPECT_CALL(MockFormSaver::Get(&form_manager), Save(_, IsEmpty()))
+ .WillOnce(SaveArg<0>(&saved_result));
+ // Expect a username edited vote.
+ FieldTypeMap expected_types;
+ expected_types[ASCIIToUTF16("full_name")] = autofill::UNKNOWN_TYPE;
+ expected_types[ASCIIToUTF16("correct_username_element")] =
+ autofill::USERNAME;
+ expected_types[ASCIIToUTF16("Passwd")] = autofill::PASSWORD;
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ CheckUploadedAutofillTypesAndSignature(
+ autofill::FormStructure(observed.form_data)
+ .FormSignatureAsStr(),
+ expected_types, false /* expect_generation_vote */,
+ autofill::AutofillUploadContents::Field::USERNAME_EDITED),
+ _, Contains(autofill::USERNAME), _, _));
+ form_manager.Save();
+
+ // Check what is saved.
+ EXPECT_EQ(ASCIIToUTF16("edited_username"), saved_result.username_value);
+ EXPECT_EQ(ASCIIToUTF16("correct_username_element"),
+ saved_result.username_element);
+ EXPECT_EQ(ASCIIToUTF16("password"), saved_result.password_value);
+ if (captured_username_is_empty) {
+ EXPECT_TRUE(saved_result.other_possible_usernames.empty());
+ } else {
+ EXPECT_THAT(
+ saved_result.other_possible_usernames,
+ ElementsAre(PossibleUsernamePair(ASCIIToUTF16("typed_username"),
+ observed_form()->username_element)));
+ }
+ }
}
-// Test that when user updates username to an already existing one, is_new_login
-// status is false.
-TEST_F(PasswordFormManagerTest, TestUpdateUsernameToExisting) {
- // We have an already existing credential.
- fake_form_fetcher()->SetNonFederated({saved_match()}, 0u);
+// Test the case when a user updates the username to an already existing one.
+TEST_F(PasswordFormManagerTest, UpdateUsername_ValueSavedInStore) {
+ for (bool captured_username_is_empty : {false, true}) {
+ SCOPED_TRACE(testing::Message() << "captured_username_is_empty="
+ << captured_username_is_empty);
+ // We have an already existing credential.
+ fake_form_fetcher()->SetNonFederated({saved_match()}, 0u);
- // User enters credential in the form.
- PasswordForm credential(*observed_form());
- credential.username_value = ASCIIToUTF16("different_username");
- credential.password_value = ASCIIToUTF16("different_pass");
- credential.preferred = true;
- form_manager()->ProvisionallySave(
- credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ // User enters credential in the form.
+ PasswordForm credential(*observed_form());
+ credential.username_value = captured_username_is_empty
+ ? base::string16()
+ : ASCIIToUTF16("different_username");
+ credential.password_value = ASCIIToUTF16("different_pass");
+ credential.preferred = true;
+ form_manager()->ProvisionallySave(
+ credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+
+ // User edits username in a prompt to one already existing.
+ form_manager()->UpdateUsername(saved_match()->username_value);
+
+ // The username in credentials is expected to be updated.
+ EXPECT_EQ(saved_match()->username_value,
+ form_manager()->pending_credentials().username_value);
+ EXPECT_EQ(saved_match()->username_element,
+ form_manager()->pending_credentials().username_element);
+ EXPECT_EQ(ASCIIToUTF16("different_pass"),
+ form_manager()->pending_credentials().password_value);
+ EXPECT_FALSE(form_manager()->IsNewLogin());
+
+ // Create the expected credential to be saved.
+ PasswordForm expected_pending(credential);
+ expected_pending.origin = saved_match()->origin;
+ expected_pending.form_data = saved_match()->form_data;
+ expected_pending.times_used = 1;
+ expected_pending.username_value = saved_match()->username_value;
+
+ // User clicks save, edited username is saved, password updated.
+ EXPECT_CALL(MockFormSaver::Get(form_manager()),
+ Update(expected_pending,
+ ElementsAre(Pair(saved_match()->username_value,
+ Pointee(*saved_match()))),
+ Pointee(IsEmpty()), nullptr));
+ // Expect a username reusing vote.
+ FieldTypeMap expected_types;
+ expected_types[ASCIIToUTF16("full_name")] = autofill::UNKNOWN_TYPE;
+ expected_types[expected_pending.username_element] = autofill::USERNAME;
+ expected_types[expected_pending.password_element] =
+ autofill::ACCOUNT_CREATION_PASSWORD;
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ CheckUploadedAutofillTypesAndSignature(
+ autofill::FormStructure(expected_pending.form_data)
+ .FormSignatureAsStr(),
+ expected_types, false /* expect_generation_vote */,
+ autofill::AutofillUploadContents::Field::CREDENTIALS_REUSED),
+ _, Contains(autofill::USERNAME), _, _));
+ form_manager()->Save();
+ }
+}
- // User edits username in a prompt to one already existing.
- form_manager()->UpdateUsername(saved_match()->username_value);
+// Tests the case when the username value edited in prompt doesn't coincides
+// neither with other values on the form nor with saved usernames.
+TEST_F(PasswordFormManagerTest, UpdateUsername_NoMatchNeitherOnFormNorInStore) {
+ for (bool captured_username_is_empty : {false, true}) {
+ SCOPED_TRACE(testing::Message() << "captured_username_is_empty="
+ << captured_username_is_empty);
+ PasswordForm observed(*observed_form());
+ // Assign any |FormData| to allow crowdsourcing of this form.
+ observed.form_data = saved_match()->form_data;
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), observed,
+ std::make_unique<NiceMock<MockFormSaver>>(), fake_form_fetcher());
+ form_manager.Init(nullptr);
+ // We have an already existing credential.
+ fake_form_fetcher()->SetNonFederated({saved_match()}, 0u);
- // The username in credentials is expected to be updated.
- EXPECT_EQ(saved_match()->username_value,
- form_manager()->pending_credentials().username_value);
- EXPECT_EQ(ASCIIToUTF16("different_pass"),
- form_manager()->pending_credentials().password_value);
- EXPECT_EQ(form_manager()->IsNewLogin(), false);
+ // A user enters a credential in the form.
+ PasswordForm credential(observed);
+ credential.username_value = captured_username_is_empty
+ ? base::string16()
+ : ASCIIToUTF16("captured_username");
+ credential.password_value = ASCIIToUTF16("different_pass");
+ credential.preferred = true;
+ form_manager.ProvisionallySave(
+ credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
- // Create the expected variables for the test.
- PasswordForm expected_pending(credential);
- expected_pending.times_used = 1;
- expected_pending.username_value = saved_match()->username_value;
+ // User edits username. The username doesn't exist neither in the store nor
+ // on the form.
+ form_manager.UpdateUsername(ASCIIToUTF16("new_username"));
- // User clicks save, edited username is saved, password updated.
+ // As there is no match on the form, |username_element| is empty.
+ EXPECT_TRUE(form_manager.pending_credentials().username_element.empty());
+ EXPECT_EQ(ASCIIToUTF16("new_username"),
+ form_manager.pending_credentials().username_value);
+ EXPECT_EQ(ASCIIToUTF16("different_pass"),
+ form_manager.pending_credentials().password_value);
+ EXPECT_TRUE(form_manager.IsNewLogin());
+
+ PasswordForm expected_pending(credential);
+ expected_pending.username_value = ASCIIToUTF16("new_username");
+ expected_pending.username_element = base::string16();
+ if (!captured_username_is_empty) {
+ // A non-empty captured username value should be saved to recover later if
+ // a user makes a mistake in username editing.
+ expected_pending.other_possible_usernames.push_back(PossibleUsernamePair(
+ ASCIIToUTF16("captured_username"), ASCIIToUTF16("Email")));
+ }
+
+ // User clicks save, the edited username is saved, the password is updated,
+ // no username vote is uploaded.
+ PasswordForm actual_saved_form;
+ EXPECT_CALL(MockFormSaver::Get(&form_manager),
+ Save(_, ElementsAre(Pair(saved_match()->username_value,
+ Pointee(*saved_match())))))
+ .WillOnce(SaveArg<0>(&actual_saved_form));
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(_, _, Not(Contains(autofill::USERNAME)), _, _));
+ form_manager.Save();
+
+ // Can't verify |date_created |, so ignore it in form comparison.
+ actual_saved_form.date_created = expected_pending.date_created;
+ EXPECT_EQ(expected_pending, actual_saved_form);
+ }
+}
+
+// Tests the case when a user clears the username value in a prompt.
+TEST_F(PasswordFormManagerTest, UpdateUsername_UserRemovedUsername) {
+ PasswordForm observed(*observed_form());
+ // Assign any |FormData| to allow crowdsourcing of this form.
+ observed.form_data = saved_match()->form_data;
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), observed,
+ std::make_unique<NiceMock<MockFormSaver>>(), fake_form_fetcher());
+ form_manager.Init(nullptr);
+ fake_form_fetcher()->SetNonFederated(std::vector<const PasswordForm*>(), 0u);
+
+ // The user enters credential in the form.
+ PasswordForm credential(observed);
+ credential.username_value = ASCIIToUTF16("pin_code");
+ credential.password_value = ASCIIToUTF16("password");
+ credential.other_possible_usernames.push_back(
+ PossibleUsernamePair(base::string16(), ASCIIToUTF16("empty_field")));
+ form_manager.ProvisionallySave(
+ credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+
+ // The user clears the username value in the prompt.
+ form_manager.UpdateUsername(base::string16());
+ EXPECT_TRUE(form_manager.pending_credentials().username_value.empty());
+ EXPECT_TRUE(form_manager.pending_credentials().username_element.empty());
+ EXPECT_EQ(form_manager.pending_credentials().password_value,
+ ASCIIToUTF16("password"));
+ EXPECT_TRUE(form_manager.IsNewLogin());
+
+ // The user clicks save, empty username is saved.
PasswordForm saved_result;
- EXPECT_CALL(MockFormSaver::Get(form_manager()),
- Update(expected_pending,
- ElementsAre(Pair(saved_match()->username_value,
- Pointee(*saved_match()))),
- Pointee(IsEmpty()), nullptr));
- form_manager()->Save();
+ EXPECT_CALL(MockFormSaver::Get(&form_manager), Save(_, IsEmpty()))
+ .WillOnce(SaveArg<0>(&saved_result));
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(_, _, Not(Contains(autofill::USERNAME)), _, _));
+ form_manager.Save();
+
+ EXPECT_TRUE(saved_result.username_value.empty());
+ EXPECT_TRUE(saved_result.username_element.empty());
+ EXPECT_EQ(ASCIIToUTF16("password"), saved_result.password_value);
+ EXPECT_THAT(
+ saved_result.other_possible_usernames,
+ ElementsAre(PossibleUsernamePair(ASCIIToUTF16("pin_code"),
+ observed_form()->username_element)));
}
// Test that when user updates username to a PSL matching credential, we should
// handle it as a new login.
-TEST_F(PasswordFormManagerTest, TestUpdatePSLUsername) {
+TEST_F(PasswordFormManagerTest, UpdateUsername_PslMatch) {
fake_form_fetcher()->SetNonFederated({psl_saved_match()}, 0u);
- // User submits credential to the observed form.
+ // The user submits a credential of the observed form.
PasswordForm credential(*observed_form());
credential.username_value = ASCIIToUTF16("some_username");
credential.password_value = ASCIIToUTF16("some_pass");
form_manager()->ProvisionallySave(
credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
- // User edits username to match the PSL.
+ // The user edits the username to match the PSL entry.
form_manager()->UpdateUsername(psl_saved_match()->username_value);
EXPECT_EQ(psl_saved_match()->username_value,
form_manager()->pending_credentials().username_value);
- EXPECT_EQ(true, form_manager()->IsNewLogin());
+ EXPECT_TRUE(form_manager()->IsNewLogin());
EXPECT_EQ(ASCIIToUTF16("some_pass"),
form_manager()->pending_credentials().password_value);
- // User clicks save, edited username is saved.
+ // The user clicks save, the edited username is saved.
PasswordForm saved_result;
EXPECT_CALL(MockFormSaver::Get(form_manager()),
- Save(_,
- ElementsAre(Pair(psl_saved_match()->username_value,
- Pointee(*psl_saved_match()))),
- nullptr))
+ Save(_, ElementsAre(Pair(psl_saved_match()->username_value,
+ Pointee(*psl_saved_match())))))
.WillOnce(SaveArg<0>(&saved_result));
+ // As the credential is re-used successfully, expect a username vote.
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(_, _, Contains(autofill::USERNAME), _, _));
form_manager()->Save();
+
+ // Check what is saved.
EXPECT_EQ(psl_saved_match()->username_value, saved_result.username_value);
EXPECT_EQ(ASCIIToUTF16("some_pass"), saved_result.password_value);
}
@@ -2472,11 +2641,11 @@ TEST_F(PasswordFormManagerTest, TestSelectPasswordMethod) {
ASCIIToUTF16("username"));
EXPECT_EQ(form_manager()->pending_credentials().password_value,
ASCIIToUTF16("newpassword"));
- EXPECT_EQ(form_manager()->IsNewLogin(), true);
+ EXPECT_TRUE(form_manager()->IsNewLogin());
// User clicks save, selected password is saved.
PasswordForm saved_result;
- EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, IsEmpty(), nullptr))
+ EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, IsEmpty()))
.WillOnce(SaveArg<0>(&saved_result));
form_manager()->Save();
EXPECT_EQ(ASCIIToUTF16("username"), saved_result.username_value);
@@ -2772,7 +2941,7 @@ TEST_F(PasswordFormManagerTest,
EXPECT_EQ(saved_match()->origin, new_credentials.origin);
}
-TEST_F(PasswordFormManagerTest, TestNotUpdateWhenOnlyPSLMatched) {
+TEST_F(PasswordFormManagerTest, TestNotUpdateWhenOnlyPslMatched) {
FakeFormFetcher fetcher;
fetcher.Fetch();
PasswordFormManager form_manager(password_manager(), client(),
@@ -2794,9 +2963,11 @@ TEST_F(PasswordFormManagerTest, TestNotUpdateWhenOnlyPSLMatched) {
// PSL matched credential should not be updated, since we are not sure that
// this is the same credential as submitted one.
PasswordForm new_credentials;
- EXPECT_CALL(MockFormSaver::Get(&form_manager), Save(_, _, nullptr))
+ EXPECT_CALL(MockFormSaver::Get(&form_manager), Save(_, _))
.WillOnce(testing::SaveArg<0>(&new_credentials));
-
+ // As the username is re-used, expect a username vote.
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(_, _, Contains(autofill::USERNAME), _, _));
form_manager.Save();
EXPECT_EQ(credentials.password_value, new_credentials.password_value);
@@ -3140,7 +3311,7 @@ TEST_F(PasswordFormManagerTest, TestSavingAPIFormsWithSamePassword) {
EXPECT_TRUE(form_manager.IsNewLogin());
PasswordForm new_credentials;
- EXPECT_CALL(MockFormSaver::Get(&form_manager), Save(_, _, nullptr))
+ EXPECT_CALL(MockFormSaver::Get(&form_manager), Save(_, _))
.WillOnce(SaveArg<0>(&new_credentials));
form_manager.Save();
@@ -3205,7 +3376,7 @@ TEST_F(PasswordFormManagerTest, ProbablyAccountCreationUpload) {
// A user submits a form and edits the username in the prompt.
form_manager.ProvisionallySave(
form_to_save, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
- form_manager.UpdateUsername(ASCIIToUTF16(" test2@gmail.com"));
+ form_manager.UpdateUsername(ASCIIToUTF16("test2@gmail.com"));
autofill::FormStructure pending_structure(form_to_save.form_data);
autofill::ServerFieldTypeSet expected_available_field_types;
@@ -3263,8 +3434,7 @@ TEST_F(PasswordFormManagerTest, ReportProcessingUpdate) {
// Sanity check for calling ProcessMatches with empty vector. Should not crash
// or make sanitizers scream.
TEST_F(PasswordFormManagerTest, ProcessMatches_Empty) {
- static_cast<FormFetcher::Consumer*>(form_manager())
- ->ProcessMatches(std::vector<const PasswordForm*>(), 0u);
+ fake_form_fetcher()->SetNonFederated({}, 0u);
}
// For all combinations of PasswordForm schemes, test that ProcessMatches
@@ -3300,16 +3470,14 @@ TEST_F(PasswordFormManagerTest, RemoveResultsWithWrongScheme_ObservingHTML) {
non_match.scheme = kWrongScheme;
// First try putting the correct scheme first in returned matches.
- static_cast<FormFetcher::Consumer*>(&form_manager)
- ->ProcessMatches({&match, &non_match}, 0u);
+ fetcher.SetNonFederated({&match, &non_match}, 0);
EXPECT_EQ(1u, form_manager.best_matches().size());
EXPECT_EQ(kCorrectScheme,
form_manager.best_matches().begin()->second->scheme);
// Now try putting the correct scheme last in returned matches.
- static_cast<FormFetcher::Consumer*>(&form_manager)
- ->ProcessMatches({&non_match, &match}, 0u);
+ fetcher.SetNonFederated({&non_match, &match}, 0);
EXPECT_EQ(1u, form_manager.best_matches().size());
EXPECT_EQ(kCorrectScheme,
@@ -3354,101 +3522,109 @@ TEST_F(PasswordFormManagerTest, UploadUsernameCorrectionVote) {
// relaxed.
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(kAutofillEnforceMinRequiredFieldsForUpload);
- for (bool is_form_with_2_fields : {false, true}) {
- SCOPED_TRACE(testing::Message()
- << "is_form_with_2_fields=" << is_form_with_2_fields);
- // Observed and saved forms have the same password, but different usernames.
- PasswordForm new_login(*observed_form());
- autofill::FormFieldData field;
- if (!is_form_with_2_fields) {
- field.label = ASCIIToUTF16("Full name");
- field.name = ASCIIToUTF16("full_name");
+ for (bool is_pending_credential_psl_match : {false, true}) {
+ for (bool is_form_with_2_fields : {false, true}) {
+ SCOPED_TRACE(testing::Message()
+ << "is_form_with_2_fields=" << is_form_with_2_fields);
+ // Observed and saved forms have the same password, but different
+ // usernames.
+ PasswordForm new_login(*observed_form());
+ autofill::FormFieldData field;
+ if (!is_form_with_2_fields) {
+ field.label = ASCIIToUTF16("Full name");
+ field.name = ASCIIToUTF16("full_name");
+ field.form_control_type = "text";
+ new_login.form_data.fields.push_back(field);
+ new_login.does_look_like_signup_form = true;
+ }
+ field.label = ASCIIToUTF16("Email");
+ field.name = ASCIIToUTF16("observed-username-field");
field.form_control_type = "text";
new_login.form_data.fields.push_back(field);
- new_login.does_look_like_signup_form = true;
- }
- field.label = ASCIIToUTF16("Email");
- field.name = ASCIIToUTF16("observed-username-field");
- field.form_control_type = "text";
- new_login.form_data.fields.push_back(field);
-
- field.label = ASCIIToUTF16("Password");
- field.name = ASCIIToUTF16("Passwd");
- field.form_control_type = "password";
- new_login.form_data.fields.push_back(field);
-
- new_login.username_value = saved_match()->other_possible_usernames[0].first;
- new_login.password_value = saved_match()->password_value;
- PasswordFormManager form_manager(
- password_manager(), client(), client()->driver(), new_login,
- std::make_unique<NiceMock<MockFormSaver>>(), fake_form_fetcher());
- form_manager.Init(nullptr);
-
- base::HistogramTester histogram_tester;
- fake_form_fetcher()->SetNonFederated({saved_match()}, 0u);
- form_manager.ProvisionallySave(
- new_login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
- histogram_tester.ExpectUniqueSample(
- "PasswordManager.UsernameCorrectionFound", 1, 1);
- // No match found (because usernames are different).
- EXPECT_TRUE(form_manager.IsNewLogin());
-
- // Checks the username correction vote is saved.
- PasswordForm expected_username_vote(*saved_match());
- expected_username_vote.username_element =
- saved_match()->other_possible_usernames[0].second;
+ field.label = ASCIIToUTF16("Password");
+ field.name = ASCIIToUTF16("Passwd");
+ field.form_control_type = "password";
+ new_login.form_data.fields.push_back(field);
- // Checks the username vote type is saved.
- autofill::AutofillUploadContents::Field::UsernameVoteType
- expected_username_vote_type =
- autofill::AutofillUploadContents::Field::USERNAME_OVERWRITTEN;
+ const PasswordForm* saved_credential =
+ is_pending_credential_psl_match ? psl_saved_match() : saved_match();
- // Checks the upload.
- autofill::ServerFieldTypeSet expected_available_field_types;
- expected_available_field_types.insert(autofill::USERNAME);
- expected_available_field_types.insert(autofill::ACCOUNT_CREATION_PASSWORD);
+ new_login.username_value =
+ saved_credential->other_possible_usernames[0].first;
+ new_login.password_value = saved_credential->password_value;
- FormStructure expected_upload(expected_username_vote.form_data);
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), new_login,
+ std::make_unique<NiceMock<MockFormSaver>>(), fake_form_fetcher());
+ form_manager.Init(nullptr);
- std::string expected_login_signature =
- FormStructure(form_manager.observed_form().form_data)
- .FormSignatureAsStr();
+ base::HistogramTester histogram_tester;
+ fake_form_fetcher()->SetNonFederated({saved_credential}, 0u);
+ form_manager.ProvisionallySave(
+ new_login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.UsernameCorrectionFound", 1, 1);
+ // No match found (because usernames are different).
+ EXPECT_TRUE(form_manager.IsNewLogin());
+
+ // Checks the username correction vote is saved.
+ PasswordForm expected_username_vote(*saved_credential);
+ expected_username_vote.username_element =
+ saved_credential->other_possible_usernames[0].second;
+
+ // Checks the type of the username vote is saved.
+ autofill::AutofillUploadContents::Field::UsernameVoteType
+ expected_username_vote_type =
+ autofill::AutofillUploadContents::Field::USERNAME_OVERWRITTEN;
+
+ // Checks the upload.
+ autofill::ServerFieldTypeSet expected_available_field_types;
+ expected_available_field_types.insert(autofill::USERNAME);
+ expected_available_field_types.insert(
+ autofill::ACCOUNT_CREATION_PASSWORD);
+
+ FormStructure expected_upload(expected_username_vote.form_data);
+
+ std::string expected_login_signature =
+ FormStructure(form_manager.observed_form().form_data)
+ .FormSignatureAsStr();
+
+ std::map<base::string16, autofill::ServerFieldType> expected_types;
+ expected_types[expected_username_vote.username_element] =
+ autofill::USERNAME;
+ expected_types[expected_username_vote.password_element] =
+ autofill::ACCOUNT_CREATION_PASSWORD;
+ expected_types[ASCIIToUTF16("Email")] = autofill::UNKNOWN_TYPE;
+
+ InSequence s;
+ std::unique_ptr<FormStructure> signin_vote_form_structure;
+ if (is_form_with_2_fields) {
+ // Make signin vote upload synchronous and free |FormStructure| passed
+ // for upload.
+ auto* mock_autofill_manager =
+ client()->mock_driver()->mock_autofill_manager();
+ EXPECT_CALL(*mock_autofill_manager, StartUploadProcessPtr(_, _, true))
+ .WillOnce(WithArg<0>(SaveToUniquePtr(&signin_vote_form_structure)));
+ } else {
+ // The observed form has 2 text fields and 1 password field,
+ // PROBABLY_ACCOUNT_CREATION_PASSWORD should be uploaded.
+ autofill::ServerFieldTypeSet field_types;
+ field_types.insert(autofill::PROBABLY_ACCOUNT_CREATION_PASSWORD);
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(_, false, field_types, std::string(), true));
+ }
- std::map<base::string16, autofill::ServerFieldType> expected_types;
- expected_types[expected_username_vote.username_element] =
- autofill::USERNAME;
- expected_types[expected_username_vote.password_element] =
- autofill::ACCOUNT_CREATION_PASSWORD;
- expected_types[ASCIIToUTF16("Email")] = autofill::UNKNOWN_TYPE;
-
- InSequence s;
- std::unique_ptr<FormStructure> signin_vote_form_structure;
- if (is_form_with_2_fields) {
- // Make signin vote upload synchronous and free |FormStructure| passed for
- // upload.
- auto* mock_autofill_manager =
- client()->mock_driver()->mock_autofill_manager();
- EXPECT_CALL(*mock_autofill_manager, StartUploadProcessPtr(_, _, true))
- .WillOnce(WithArg<0>(SaveToUniquePtr(&signin_vote_form_structure)));
- } else {
- // The observed form has 2 text fields and 1 password field,
- // PROBABLY_ACCOUNT_CREATION_PASSWORD should be uploaded.
- autofill::ServerFieldTypeSet field_types;
- field_types.insert(autofill::PROBABLY_ACCOUNT_CREATION_PASSWORD);
- EXPECT_CALL(
- *client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(_, false, field_types, std::string(), true));
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ CheckUploadedAutofillTypesAndSignature(
+ expected_upload.FormSignatureAsStr(), expected_types,
+ false, expected_username_vote_type),
+ false, expected_available_field_types,
+ expected_login_signature, true));
+ form_manager.Save();
}
-
- EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(
- CheckUploadedAutofillTypesAndSignature(
- expected_upload.FormSignatureAsStr(), expected_types,
- false, expected_username_vote_type),
- false, expected_available_field_types,
- expected_login_signature, true));
- form_manager.Save();
}
}
@@ -3474,6 +3650,52 @@ TEST_F(PasswordFormManagerTest, NoUsernameCorrectionVote) {
form_manager()->Save();
}
+TEST_F(PasswordFormManagerTest,
+ UsernameCorrectionVote_PasswordReusedWithoutUsername) {
+ for (bool saved_username_is_empty : {false, true}) {
+ SCOPED_TRACE(testing::Message()
+ << "saved_username_is_empty=" << saved_username_is_empty);
+
+ if (saved_username_is_empty) {
+ saved_match()->username_value.clear();
+ // |username_element| must be empty as well, but it may be non-empty in
+ // credentials saved in past versions. Let's test there will be not vote
+ // for this element even if |username_element| has a non-empty value.
+ }
+
+ saved_match()->other_possible_usernames.push_back(
+ PossibleUsernamePair(base::string16(), ASCIIToUTF16("empty_field")));
+ fake_form_fetcher()->SetNonFederated({saved_match()}, 0u);
+
+ // A user enters the password in the form. The username is absent or not
+ // captured, but the user doesn't enter the username in a prompt.
+ PasswordForm credential(*saved_match());
+ credential.username_value.clear();
+ credential.preferred = true;
+ form_manager()->ProvisionallySave(
+ credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ EXPECT_FALSE(form_manager()->IsNewLogin());
+
+ // Create the expected credential to be saved.
+ PasswordForm expected_pending(*saved_match());
+ expected_pending.times_used = 1;
+ // As a credential is reused, |other_possible_usernames| will be cleared.
+ // In fact, the username wasn't reused, only password, but for the sake of
+ // simplicity |other_possible_usernames| is cleared even in this case.
+ expected_pending.other_possible_usernames.clear();
+
+ EXPECT_CALL(MockFormSaver::Get(form_manager()),
+ Update(expected_pending,
+ ElementsAre(Pair(saved_match()->username_value,
+ Pointee(*saved_match()))),
+ Pointee(IsEmpty()), nullptr));
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(_, _, Not(Contains(autofill::USERNAME)), _, _));
+ form_manager()->Save();
+ }
+}
+
// Test that ResetStoredMatches removes references to previously fetched store
// results.
TEST_F(PasswordFormManagerTest, ResetStoredMatches) {
@@ -3834,11 +4056,6 @@ TEST_F(PasswordFormManagerTest, SuppressedFormsHistograms) {
form_data->password_value, form_data->manual_or_generated));
}
- // Bind the UKM SourceId to any URL, it does not matter. The SourceId
- // needs to be bound, though, for reporting to happen.
- client()->GetUkmRecorder()->UpdateSourceURL(client()->GetUkmSourceId(),
- GURL("https://example.com/"));
-
std::vector<const PasswordForm*> suppressed_forms_ptrs;
for (const auto& form : suppressed_forms)
suppressed_forms_ptrs.push_back(&form);
@@ -3955,7 +4172,7 @@ TEST_F(PasswordFormManagerTest, Clone_OnSave) {
std::unique_ptr<PasswordFormManager> clone = form_manager->Clone();
PasswordForm passed;
- EXPECT_CALL(MockFormSaver::Get(clone.get()), Save(_, IsEmpty(), nullptr))
+ EXPECT_CALL(MockFormSaver::Get(clone.get()), Save(_, IsEmpty()))
.WillOnce(SaveArg<0>(&passed));
clone->Save();
// The date is expected to be different. Reset it so that we can easily
@@ -4008,7 +4225,7 @@ TEST_F(PasswordFormManagerTest, Clone_SurvivesOriginal) {
form_manager.reset();
PasswordForm passed;
- EXPECT_CALL(MockFormSaver::Get(clone.get()), Save(_, IsEmpty(), nullptr))
+ EXPECT_CALL(MockFormSaver::Get(clone.get()), Save(_, IsEmpty()))
.WillOnce(SaveArg<0>(&passed));
clone->Save();
// The date is expected to be different. Reset it so that we can easily
@@ -4053,8 +4270,8 @@ TEST_F(PasswordFormManagerTest, TestUkmForFilling) {
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
{
auto metrics_recorder = base::MakeRefCounted<PasswordFormMetricsRecorder>(
- form_to_fill.origin.SchemeIsCryptographic(), &test_ukm_recorder,
- test_ukm_recorder.GetNewSourceID(), form_to_fill.origin);
+ form_to_fill.origin.SchemeIsCryptographic(),
+ client()->GetUkmSourceId());
FakeFormFetcher fetcher;
PasswordFormManager form_manager(
password_manager(), client(),
@@ -4068,7 +4285,7 @@ TEST_F(PasswordFormManagerTest, TestUkmForFilling) {
ukm::builders::PasswordForm::kEntryName);
EXPECT_EQ(1u, entries.size());
for (const auto* const entry : entries) {
- test_ukm_recorder.ExpectEntrySourceHasUrl(entry, form_to_fill.origin);
+ EXPECT_EQ(client()->GetUkmSourceId(), entry->source_id);
test_ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::PasswordForm::kManagerFill_ActionName,
test.expected_event);
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 d69da19cf24..843c05c3091 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
@@ -61,13 +61,9 @@ PasswordFormMetricsRecorder::BubbleDismissalReason GetBubbleDismissalReason(
PasswordFormMetricsRecorder::PasswordFormMetricsRecorder(
bool is_main_frame_secure,
- ukm::UkmRecorder* ukm_recorder,
- ukm::SourceId source_id,
- const GURL& main_frame_url)
+ ukm::SourceId source_id)
: is_main_frame_secure_(is_main_frame_secure),
- ukm_recorder_(ukm_recorder),
source_id_(source_id),
- main_frame_url_(main_frame_url),
ukm_entry_builder_(source_id) {}
PasswordFormMetricsRecorder::~PasswordFormMetricsRecorder() {
@@ -133,12 +129,7 @@ PasswordFormMetricsRecorder::~PasswordFormMetricsRecorder() {
}
}
- ukm_entry_builder_.Record(ukm_recorder_);
-
- // Bind |main_frame_url_| to |source_id_| directly before sending the content
- // of |ukm_recorder_| to ensure that the binding has not been purged already.
- if (ukm_recorder_)
- ukm_recorder_->UpdateSourceURL(source_id_, main_frame_url_);
+ ukm_entry_builder_.Record(ukm::UkmRecorder::Get());
}
void PasswordFormMetricsRecorder::MarkGenerationAvailable() {
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 52fab3a610d..1fbd7811a88 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
@@ -41,17 +41,9 @@ class PasswordFormMetricsRecorder
: public base::RefCounted<PasswordFormMetricsRecorder> {
public:
// Records UKM metrics and reports them on destruction. The |source_id| is
- // (re-)bound to |main_frame_url| shortly before reporting. As such it is
- // crucial that the |source_id| is never bound to a different URL by another
- // consumer. The reason for this late binding is that metrics can be
- // collected for a WebContents for a long period of time and by the time the
- // reporting happens, the binding of |source_id| to |main_frame_url| is
- // already purged. |ukm_recorder| may be a nullptr, in which case no UKM
- // metrics are recorded.
+ // the ID of the WebContents document that the forms belong to.
PasswordFormMetricsRecorder(bool is_main_frame_secure,
- ukm::UkmRecorder* ukm_recorder,
- ukm::SourceId source_id,
- const GURL& main_frame_url);
+ ukm::SourceId source_id);
// 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
@@ -307,18 +299,9 @@ class PasswordFormMetricsRecorder
// data the user has entered.
SubmittedFormType submitted_form_type_ = kSubmittedFormTypeUnspecified;
- // Recorder to which metrics are sent. Has to outlive this
- // PasswordFormMetricsRecorder.
- ukm::UkmRecorder* ukm_recorder_;
-
- // A SourceId of |ukm_recorder_|. This id gets bound to |main_frame_url_| on
- // destruction. It can be shared across multiple metrics recorders as long as
- // they all bind it to the same URL.
+ // The UKM SourceId of the document the form belongs to.
ukm::SourceId source_id_;
- // URL for which UKMs are reported.
- GURL main_frame_url_;
-
// Holds URL keyed metrics (UKMs) to be recorded on destruction.
ukm::builders::PasswordForm ukm_entry_builder_;
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 b928e2a664d..589c89f36a4 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
@@ -21,17 +21,16 @@ namespace password_manager {
namespace {
-constexpr char kTestUrl[] = "https://www.example.com/";
+constexpr ukm::SourceId kTestSourceId = 0x1234;
using UkmEntry = ukm::builders::PasswordForm;
-// Create a UkmEntryBuilder with a SourceId that is initialized for kTestUrl.
+// 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, test_ukm_recorder,
- test_ukm_recorder->GetNewSourceID(), GURL(kTestUrl));
+ return base::MakeRefCounted<PasswordFormMetricsRecorder>(is_main_frame_secure,
+ kTestSourceId);
}
// TODO(crbug.com/738921) Replace this with generalized infrastructure.
@@ -44,7 +43,7 @@ void ExpectUkmValueCount(ukm::TestUkmRecorder* test_ukm_recorder,
auto entries = test_ukm_recorder->GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(1u, entries.size());
for (const auto* const entry : entries) {
- test_ukm_recorder->ExpectEntrySourceHasUrl(entry, GURL(kTestUrl));
+ EXPECT_EQ(kTestSourceId, entry->source_id);
if (expected_count) {
test_ukm_recorder->ExpectEntryMetric(entry, metric_name, value);
} else {
@@ -467,7 +466,7 @@ TEST(PasswordFormMetricsRecorder, RecordPasswordBubbleShown) {
auto entries = test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(1u, entries.size());
for (const auto* const entry : entries) {
- test_ukm_recorder.ExpectEntrySourceHasUrl(entry, GURL(kTestUrl));
+ EXPECT_EQ(kTestSourceId, entry->source_id);
if (test.credential_source_type !=
metrics_util::CredentialSourceType::kUnknown) {
@@ -532,7 +531,7 @@ TEST(PasswordFormMetricsRecorder, RecordUIDismissalReason) {
auto entries = test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(1u, entries.size());
for (const auto* const entry : entries) {
- test_ukm_recorder.ExpectEntrySourceHasUrl(entry, GURL(kTestUrl));
+ EXPECT_EQ(kTestSourceId, entry->source_id);
test_ukm_recorder.ExpectEntryMetric(
entry, test.expected_trigger_metric,
static_cast<int64_t>(test.expected_metric_value));
@@ -566,7 +565,7 @@ TEST(PasswordFormMetricsRecorder, SequencesOfBubbles) {
auto entries = test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(1u, entries.size());
for (const auto* const entry : entries) {
- test_ukm_recorder.ExpectEntrySourceHasUrl(entry, GURL(kTestUrl));
+ EXPECT_EQ(kTestSourceId, entry->source_id);
test_ukm_recorder.ExpectEntryMetric(
entry, UkmEntry::kSaving_Prompt_InteractionName,
static_cast<int64_t>(BubbleDismissalReason::kAccepted));
@@ -603,7 +602,7 @@ TEST(PasswordFormMetricsRecorder, RecordDetailedUserAction) {
auto entries = test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(1u, entries.size());
for (const auto* const entry : entries) {
- test_ukm_recorder.ExpectEntrySourceHasUrl(entry, GURL(kTestUrl));
+ EXPECT_EQ(kTestSourceId, entry->source_id);
test_ukm_recorder.ExpectEntryMetric(
entry, UkmEntry::kUser_Action_CorrectedUsernameInFormName, 2u);
test_ukm_recorder.ExpectEntryMetric(
diff --git a/chromium/components/password_manager/core/browser/password_manager.cc b/chromium/components/password_manager/core/browser/password_manager.cc
index 8db09406bad..c4beff277c1 100644
--- a/chromium/components/password_manager/core/browser/password_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_manager.cc
@@ -32,6 +32,7 @@
#include "components/password_manager/core/browser/password_manager_metrics_recorder.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_reuse_defines.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
@@ -486,6 +487,20 @@ void PasswordManager::OnPasswordFormSubmitted(
pending_login_managers_.clear();
}
+void PasswordManager::OnPasswordFormSubmittedNoChecks(
+ password_manager::PasswordManagerDriver* driver,
+ const autofill::PasswordForm& password_form) {
+ if (password_manager_util::IsLoggingActive(client_)) {
+ BrowserSavePasswordProgressLogger logger(client_->GetLogManager());
+ logger.LogMessage(Logger::STRING_ON_IN_PAGE_NAVIGATION);
+ }
+
+ ProvisionallySavePassword(password_form, driver);
+
+ if (CanProvisionalManagerSave())
+ OnLoginSuccessful();
+}
+
void PasswordManager::OnPasswordFormForceSaveRequested(
password_manager::PasswordManagerDriver* driver,
const PasswordForm& password_form) {
@@ -567,6 +582,30 @@ void PasswordManager::CreatePendingLoginManagers(
// Record whether or not this top-level URL has at least one password field.
client_->AnnotateNavigationEntry(!forms.empty());
+ // Only report SSL error status for cases where there are potentially forms to
+ // fill or save from.
+ if (!forms.empty()) {
+ metrics_util::CertificateError cert_error =
+ metrics_util::CertificateError::NONE;
+ const net::CertStatus cert_status = client_->GetMainFrameCertStatus();
+ // The order of the if statements matters -- if the status involves multiple
+ // errors, Chrome should report the one highest up in the list below.
+ if (cert_status & net::CERT_STATUS_AUTHORITY_INVALID)
+ cert_error = metrics_util::CertificateError::AUTHORITY_INVALID;
+ else if (cert_status & net::CERT_STATUS_COMMON_NAME_INVALID)
+ cert_error = metrics_util::CertificateError::COMMON_NAME_INVALID;
+ else if (cert_status & net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM)
+ cert_error = metrics_util::CertificateError::WEAK_SIGNATURE_ALGORITHM;
+ else if (cert_status & net::CERT_STATUS_DATE_INVALID)
+ cert_error = metrics_util::CertificateError::DATE_INVALID;
+ else if (net::IsCertStatusError(cert_status))
+ cert_error = metrics_util::CertificateError::OTHER;
+
+ UMA_HISTOGRAM_ENUMERATION(
+ "PasswordManager.CertificateErrorsWhileSeeingForms", cert_error,
+ metrics_util::CertificateError::COUNT);
+ }
+
if (!client_->IsFillingEnabledForCurrentPage())
return;
@@ -785,19 +824,7 @@ void PasswordManager::OnPasswordFormsRendered(
void PasswordManager::OnInPageNavigation(
password_manager::PasswordManagerDriver* driver,
const PasswordForm& password_form) {
- std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
- if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
- logger->LogMessage(Logger::STRING_ON_IN_PAGE_NAVIGATION);
- }
-
- ProvisionallySavePassword(password_form, driver);
-
- if (!CanProvisionalManagerSave())
- return;
-
- OnLoginSuccessful();
+ OnPasswordFormSubmittedNoChecks(driver, password_form);
}
void PasswordManager::OnLoginSuccessful() {
@@ -822,8 +849,7 @@ void PasswordManager::OnLoginSuccessful() {
DCHECK(provisional_save_manager_->submitted_form());
if (!client_->GetStoreResultFilter()->ShouldSave(
*provisional_save_manager_->submitted_form())) {
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
// When |username_value| is empty, it's not clear whether the submitted
// credentials are really sync credentials. Don't save sync password hash
// in that case.
diff --git a/chromium/components/password_manager/core/browser/password_manager.h b/chromium/components/password_manager/core/browser/password_manager.h
index 7e4f02f8f66..bfafe7fcd7a 100644
--- a/chromium/components/password_manager/core/browser/password_manager.h
+++ b/chromium/components/password_manager/core/browser/password_manager.h
@@ -153,6 +153,12 @@ class PasswordManager : public LoginModel {
password_manager::PasswordManagerDriver* driver,
const autofill::PasswordForm& password_form);
+ // Handles a password form being submitted, assumes that submission is
+ // successful and does not do any checks on success of submission.
+ void OnPasswordFormSubmittedNoChecks(
+ password_manager::PasswordManagerDriver* driver,
+ const autofill::PasswordForm& password_form);
+
// Handles a manual request to save password.
void OnPasswordFormForceSaveRequested(
password_manager::PasswordManagerDriver* driver,
@@ -170,6 +176,7 @@ class PasswordManager : public LoginModel {
// Called if |password_form| was filled upon in-page navigation. This often
// means history.pushState being called from JavaScript. If this causes false
// positive in password saving, update http://crbug.com/357696.
+ // TODO(https://crbug.com/795462): find better name for this function.
void OnInPageNavigation(password_manager::PasswordManagerDriver* driver,
const autofill::PasswordForm& password_form);
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 ead9e485d92..ca18e83f821 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_client.cc
@@ -48,8 +48,8 @@ bool PasswordManagerClient::WasLastNavigationHTTPError() const {
return false;
}
-bool PasswordManagerClient::DidLastPageLoadEncounterSSLErrors() const {
- return false;
+net::CertStatus PasswordManagerClient::GetMainFrameCertStatus() const {
+ return 0;
}
bool PasswordManagerClient::IsIncognito() const {
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 7d45719bb23..7bbf998a2d0 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/password_manager_client.h
@@ -12,6 +12,7 @@
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/credentials_filter.h"
#include "components/password_manager/core/browser/password_store.h"
+#include "net/cert/cert_status_flags.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
class PrefService;
@@ -182,9 +183,8 @@ class PasswordManagerClient {
// Returns true if last navigation page had HTTP error i.e 5XX or 4XX
virtual bool WasLastNavigationHTTPError() const;
- // Returns whether any SSL certificate errors were encountered as a result of
- // the last page load.
- virtual bool DidLastPageLoadEncounterSSLErrors() const;
+ // Obtains the cert status for the main frame.
+ virtual net::CertStatus GetMainFrameCertStatus() const;
// If this browsing session should not be persisted.
virtual bool IsIncognito() const;
@@ -238,12 +238,8 @@ class PasswordManagerClient {
virtual void LogPasswordReuseDetectedEvent() = 0;
#endif
- // Gets the UKM service associated with this client (for metrics).
- virtual ukm::UkmRecorder* GetUkmRecorder() = 0;
-
// Gets a ukm::SourceId that is associated with the WebContents object
- // and its last committed main frame navigation. Note that the URL binding
- // has to happen by the caller at a later point.
+ // and its last committed main frame navigation.
virtual ukm::SourceId GetUkmSourceId() = 0;
// Gets a metrics recorder for the currently committed navigation.
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 b92e79a28c0..4ba9a27e892 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
@@ -7,6 +7,7 @@
#include "base/metrics/histogram_macros.h"
#include "components/autofill/core/common/save_password_progress_logger.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "url/gurl.h"
// Shorten the name to spare line breaks. The code provides enough context
@@ -15,34 +16,20 @@ typedef autofill::SavePasswordProgressLogger Logger;
namespace password_manager {
-// URL Keyed Metrics.
-const char kUkmUserModifiedPasswordField[] = "UserModifiedPasswordField";
-const char kUkmProvisionalSaveFailure[] = "ProvisionalSaveFailure";
-const char kUkmPageLevelUserAction[] = "PageLevelUserAction";
-
PasswordManagerMetricsRecorder::PasswordManagerMetricsRecorder(
- ukm::UkmRecorder* ukm_recorder,
ukm::SourceId source_id,
const GURL& main_frame_url)
- : ukm_recorder_(ukm_recorder),
- source_id_(source_id),
- main_frame_url_(main_frame_url),
+ : main_frame_url_(main_frame_url),
ukm_entry_builder_(
- ukm_recorder
- ? ukm_recorder->GetEntryBuilder(source_id, "PageWithPassword")
- : nullptr) {}
+ base::MakeUnique<ukm::builders::PageWithPassword>(source_id)) {}
PasswordManagerMetricsRecorder::PasswordManagerMetricsRecorder(
PasswordManagerMetricsRecorder&& that) noexcept = default;
PasswordManagerMetricsRecorder::~PasswordManagerMetricsRecorder() {
if (user_modified_password_field_)
- RecordUkmMetric(kUkmUserModifiedPasswordField, 1);
-
- // Bind |main_frame_url_| to |source_id_| directly before sending the content
- // of |ukm_recorder_| to ensure that the binding has not been purged already.
- if (ukm_recorder_)
- ukm_recorder_->UpdateSourceURL(source_id_, main_frame_url_);
+ ukm_entry_builder_->SetUserModifiedPasswordField(1);
+ ukm_entry_builder_->Record(ukm::UkmRecorder::Get());
}
PasswordManagerMetricsRecorder& PasswordManagerMetricsRecorder::operator=(
@@ -59,7 +46,7 @@ void PasswordManagerMetricsRecorder::RecordProvisionalSaveFailure(
BrowserSavePasswordProgressLogger* logger) {
UMA_HISTOGRAM_ENUMERATION("PasswordManager.ProvisionalSaveFailure", failure,
MAX_FAILURE_VALUE);
- RecordUkmMetric(kUkmProvisionalSaveFailure, static_cast<int64_t>(failure));
+ ukm_entry_builder_->SetProvisionalSaveFailure(static_cast<int64_t>(failure));
if (logger) {
switch (failure) {
@@ -99,13 +86,7 @@ void PasswordManagerMetricsRecorder::RecordProvisionalSaveFailure(
void PasswordManagerMetricsRecorder::RecordPageLevelUserAction(
PasswordManagerMetricsRecorder::PageLevelUserAction action) {
- RecordUkmMetric(kUkmPageLevelUserAction, static_cast<int64_t>(action));
-}
-
-void PasswordManagerMetricsRecorder::RecordUkmMetric(const char* metric_name,
- int64_t value) {
- if (ukm_entry_builder_)
- ukm_entry_builder_->AddMetric(metric_name, value);
+ ukm_entry_builder_->SetPageLevelUserAction(static_cast<int64_t>(action));
}
} // namespace password_manager
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 551f4ebbdf7..1f348f5a0b6 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
@@ -10,26 +10,18 @@
#include <memory>
#include "base/macros.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
#include "url/gurl.h"
class GURL;
-namespace password_manager {
-
-// URL Keyed Metrics.
-
-// Records a 1 for every page on which a user has modified the content of a
-// password field - regardless of how many password fields a page contains or
-// the user modifies.
-extern const char kUkmUserModifiedPasswordField[];
-
-// UKM that records a ProvisionalSaveFailure in case the password manager cannot
-// offer to save a credential.
-extern const char kUkmProvisionalSaveFailure[];
+namespace ukm {
+namespace builders {
+class PageWithPassword;
+}
+} // namespace ukm
-// UKM that records a PasswordManagerMetricsRecorder::PageLevelUserAction.
-extern const char kUkmPageLevelUserAction[];
+namespace password_manager {
class BrowserSavePasswordProgressLogger;
@@ -75,16 +67,8 @@ class PasswordManagerMetricsRecorder {
kShowAllPasswordsWhileNoneAreSuggested,
};
- // Records UKM metrics and reports them on destruction. The |source_id| is
- // (re-)bound to |main_frame_url| shortly before reporting. As such it is
- // crucial that the |source_id| is never bound to a different URL by another
- // consumer. The reason for this late binding is that metrics can be
- // collected for a WebContents for a long period of time and by the time the
- // reporting happens, the binding of |source_id| to |main_frame_url| is
- // already purged. |ukm_recorder| may be a nullptr, in which case no UKM
- // metrics are recorded.
- PasswordManagerMetricsRecorder(ukm::UkmRecorder* ukm_recorder,
- ukm::SourceId source_id,
+ // Records UKM metrics and reports them on destruction.
+ PasswordManagerMetricsRecorder(ukm::SourceId source_id,
const GURL& main_frame_url);
PasswordManagerMetricsRecorder(
@@ -109,24 +93,11 @@ class PasswordManagerMetricsRecorder {
void RecordPageLevelUserAction(PageLevelUserAction action);
private:
- // Records a metric into |ukm_entry_builder_| if it is not nullptr.
- void RecordUkmMetric(const char* metric_name, int64_t value);
-
- // Recorder to which metrics are sent. Has to outlive this
- // PasswordManagerMetircsRecorder.
- ukm::UkmRecorder* ukm_recorder_;
-
- // A SourceId of |ukm_recorder_|. This id gets bound to |main_frame_url_| on
- // destruction. It can be shared across multiple metrics recorders as long as
- // they all bind it to the same URL.
- ukm::SourceId source_id_;
-
// URL for which UKMs are reported.
GURL main_frame_url_;
- // Records URL keyed metrics (UKMs) and submits them on its destruction. May
- // be a nullptr in which case no recording is expected.
- std::unique_ptr<ukm::UkmEntryBuilder> ukm_entry_builder_;
+ // Records URL keyed metrics (UKMs) and submits them on its destruction.
+ std::unique_ptr<ukm::builders::PageWithPassword> ukm_entry_builder_;
bool user_modified_password_field_ = false;
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 c0be3964a91..ace6340facc 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
@@ -10,7 +10,7 @@
#include "base/test/scoped_task_environment.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/ukm/ukm_source.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,12 +22,13 @@ 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(
- ukm::UkmRecorder* ukm_recorder) {
- return PasswordManagerMetricsRecorder(
- ukm_recorder, ukm_recorder->GetNewSourceID(), GURL(kTestUrl));
+PasswordManagerMetricsRecorder CreateMetricsRecorder() {
+ return PasswordManagerMetricsRecorder(kTestSourceId, GURL(kTestUrl));
}
} // namespace
@@ -36,17 +37,17 @@ TEST(PasswordManagerMetricsRecorder, UserModifiedPasswordField) {
base::test::ScopedTaskEnvironment scoped_task_environment_;
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
{
- PasswordManagerMetricsRecorder recorder(
- CreateMetricsRecorder(&test_ukm_recorder));
+ PasswordManagerMetricsRecorder recorder(CreateMetricsRecorder());
recorder.RecordUserModifiedPasswordField();
}
- const auto& entries = test_ukm_recorder.GetEntriesByName("PageWithPassword");
+ const auto& entries =
+ test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(1u, entries.size());
for (const auto* entry : entries) {
- test_ukm_recorder.ExpectEntrySourceHasUrl(entry, GURL(kTestUrl));
- test_ukm_recorder.ExpectEntryMetric(entry, kUkmUserModifiedPasswordField,
- 1);
+ EXPECT_EQ(kTestSourceId, entry->source_id);
+ test_ukm_recorder.ExpectEntryMetric(
+ entry, UkmEntry::kUserModifiedPasswordFieldName, 1);
}
}
@@ -54,34 +55,32 @@ TEST(PasswordManagerMetricsRecorder, UserModifiedPasswordFieldMultipleTimes) {
base::test::ScopedTaskEnvironment scoped_task_environment_;
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
{
- PasswordManagerMetricsRecorder recorder(
- CreateMetricsRecorder(&test_ukm_recorder));
+ PasswordManagerMetricsRecorder recorder(CreateMetricsRecorder());
// Multiple calls should not create more than one entry.
recorder.RecordUserModifiedPasswordField();
recorder.RecordUserModifiedPasswordField();
}
- const auto& entries = test_ukm_recorder.GetEntriesByName("PageWithPassword");
+ const auto& entries =
+ test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(1u, entries.size());
for (const auto* entry : entries) {
- test_ukm_recorder.ExpectEntrySourceHasUrl(entry, GURL(kTestUrl));
- test_ukm_recorder.ExpectEntryMetric(entry, kUkmUserModifiedPasswordField,
- 1);
+ EXPECT_EQ(kTestSourceId, entry->source_id);
+ test_ukm_recorder.ExpectEntryMetric(
+ entry, UkmEntry::kUserModifiedPasswordFieldName, 1);
}
}
TEST(PasswordManagerMetricsRecorder, UserModifiedPasswordFieldNotCalled) {
base::test::ScopedTaskEnvironment scoped_task_environment_;
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
- {
- PasswordManagerMetricsRecorder recorder(
- CreateMetricsRecorder(&test_ukm_recorder));
- }
- const auto& entries = test_ukm_recorder.GetEntriesByName("PageWithPassword");
+ { PasswordManagerMetricsRecorder recorder(CreateMetricsRecorder()); }
+ const auto& entries =
+ test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
EXPECT_EQ(1u, entries.size());
for (const auto* entry : entries) {
- test_ukm_recorder.ExpectEntrySourceHasUrl(entry, GURL(kTestUrl));
- EXPECT_FALSE(
- test_ukm_recorder.EntryHasMetric(entry, kUkmUserModifiedPasswordField));
+ EXPECT_EQ(kTestSourceId, entry->source_id);
+ EXPECT_FALSE(test_ukm_recorder.EntryHasMetric(
+ entry, UkmEntry::kUserModifiedPasswordFieldName));
}
}
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 8ddf90ccd11..9a2eda5cc9e 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
@@ -212,8 +212,7 @@ void LogSubmittedFormFrame(SubmittedFormFrame frame) {
SubmittedFormFrame::SUBMITTED_FORM_FRAME_COUNT);
}
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
void LogSyncPasswordHashChange(SyncPasswordHashChange event) {
UMA_HISTOGRAM_ENUMERATION(
"PasswordManager.SyncPasswordHashChange", event,
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 1155dcb5fdd..73d7876608a 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
@@ -10,6 +10,7 @@
#include <string>
#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/password_reuse_defines.h"
#include "components/password_manager/core/common/credential_manager_types.h"
namespace password_manager {
@@ -227,8 +228,7 @@ enum class CredentialSourceType {
kCredentialManagementAPI
};
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
enum class SyncPasswordHashChange {
SAVED_ON_CHROME_SIGNIN,
SAVED_IN_CONTENT_AREA,
@@ -263,6 +263,17 @@ enum ShowAllSavedPasswordsContext {
SHOW_ALL_SAVED_PASSWORDS_CONTEXT_COUNT
};
+// Metrics: "PasswordManager.CertificateErrorsWhileSeeingForms"
+enum class CertificateError {
+ NONE = 0,
+ OTHER = 1,
+ AUTHORITY_INVALID = 2,
+ DATE_INVALID = 3,
+ COMMON_NAME_INVALID = 4,
+ WEAK_SIGNATURE_ALGORITHM = 5,
+ COUNT
+};
+
// A version of the UMA_HISTOGRAM_BOOLEAN macro that allows the |name|
// to vary over the program's runtime.
void LogUMAHistogramBoolean(const std::string& name, bool sample);
@@ -361,8 +372,7 @@ void LogPasswordAcceptedSaveUpdateSubmissionIndicatorEvent(
// Log a frame of a submitted password form.
void LogSubmittedFormFrame(SubmittedFormFrame frame);
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
// Log a save sync password change event.
void LogSyncPasswordHashChange(SyncPasswordHashChange event);
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 b2d6c5bc488..ac1a60eaab9 100644
--- a/chromium/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
@@ -21,6 +21,7 @@
#include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/password_autofill_manager.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
+#include "components/password_manager/core/browser/password_reuse_defines.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/statistics_table.h"
#include "components/password_manager/core/browser/stub_credentials_filter.h"
@@ -28,6 +29,7 @@
#include "components/password_manager/core/browser/stub_password_manager_driver.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "net/cert/cert_status_flags.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -61,7 +63,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
}
MOCK_CONST_METHOD0(IsSavingAndFillingEnabledForCurrentPage, bool());
- MOCK_CONST_METHOD0(DidLastPageLoadEncounterSSLErrors, bool());
+ MOCK_CONST_METHOD0(GetMainFrameCertStatus, net::CertStatus());
MOCK_CONST_METHOD0(GetPasswordStore, PasswordStore*());
// The code inside EXPECT_CALL for PromptUserToSaveOrUpdatePasswordPtr and
// ShowManualFallbackForSavingPtr owns the PasswordFormManager* argument.
@@ -154,8 +156,7 @@ class PasswordManagerTest : public testing::Test {
.WillRepeatedly(Return(manager_.get()));
EXPECT_CALL(driver_, GetPasswordAutofillManager())
.WillRepeatedly(Return(password_autofill_manager_.get()));
- EXPECT_CALL(client_, DidLastPageLoadEncounterSSLErrors())
- .WillRepeatedly(Return(false));
+ EXPECT_CALL(client_, GetMainFrameCertStatus()).WillRepeatedly(Return(0));
ON_CALL(client_, GetMainFrameURL()).WillByDefault(ReturnRef(test_url_));
}
@@ -757,8 +758,7 @@ TEST_F(PasswordManagerTest, SyncCredentialsNotSaved) {
// User should not be prompted and password should not be saved.
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
EXPECT_CALL(*store_, AddLogin(_)).Times(0);
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
EXPECT_CALL(*store_, SaveSyncPasswordHash(form.password_value));
#endif
// Prefs are needed for failure logging about sync credentials.
@@ -836,8 +836,7 @@ TEST_F(PasswordManagerTest, SyncCredentialsNotDroppedIfUpToDate) {
EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
.WillRepeatedly(Return(true));
EXPECT_CALL(client_, GetPrefs()).WillRepeatedly(Return(nullptr));
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
EXPECT_CALL(*store_, SaveSyncPasswordHash(form.password_value));
#endif
manager()->ProvisionallySavePassword(form, nullptr);
@@ -873,8 +872,7 @@ TEST_F(PasswordManagerTest, SyncCredentialsDroppedWhenObsolete) {
EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
.WillRepeatedly(Return(true));
EXPECT_CALL(client_, GetPrefs()).WillRepeatedly(Return(nullptr));
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
EXPECT_CALL(*store_, SaveSyncPasswordHash(ASCIIToUTF16("n3w passw0rd")));
#endif
manager()->ProvisionallySavePassword(updated_form, nullptr);
@@ -1712,10 +1710,10 @@ TEST_F(PasswordManagerTest,
}
TEST_F(PasswordManagerTest, ForceSavingPasswords) {
- // Add the enable-password-force-saving feature.
+ // Add the PasswordForceSaving feature.
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
- features::kEnablePasswordForceSaving);
+ features::kPasswordForceSaving);
PasswordForm form(MakeSimpleForm());
std::vector<PasswordForm> observed;
@@ -1739,10 +1737,10 @@ TEST_F(PasswordManagerTest, ForceSavingPasswords) {
// Forcing Chrome to save an empty passwords should fail without a crash.
TEST_F(PasswordManagerTest, ForceSavingPasswords_Empty) {
- // Add the enable-password-force-saving feature.
+ // Add the PasswordForceSaving feature.
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
- features::kEnablePasswordForceSaving);
+ features::kPasswordForceSaving);
PasswordForm empty_password_form;
std::vector<PasswordForm> observed;
@@ -1928,8 +1926,7 @@ TEST_F(PasswordManagerTest, ClearedFieldsSuccessCriteria) {
manager()->OnPasswordFormsRendered(&driver_, observed, true);
}
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
// 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.
@@ -2202,8 +2199,7 @@ TEST_F(PasswordManagerTest, SaveSyncPasswordHashOnChangePasswordPage) {
EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
.WillRepeatedly(Return(true));
EXPECT_CALL(client_, GetPrefs()).WillRepeatedly(Return(nullptr));
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
EXPECT_CALL(*store_, SaveSyncPasswordHash(form.new_password_value));
#endif
client_.FilterAllResultsForSaving();
@@ -2214,4 +2210,60 @@ TEST_F(PasswordManagerTest, SaveSyncPasswordHashOnChangePasswordPage) {
manager()->OnPasswordFormsRendered(&driver_, observed, true);
}
+// If there are no forms to parse, certificate errors should not be reported.
+TEST_F(PasswordManagerTest, CertErrorReported_NoForms) {
+ const std::vector<PasswordForm> observed;
+ EXPECT_CALL(client_, GetMainFrameCertStatus())
+ .WillRepeatedly(Return(net::CERT_STATUS_AUTHORITY_INVALID));
+ EXPECT_CALL(*store_, GetLogins(_, _))
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+
+ base::HistogramTester histogram_tester;
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.CertificateErrorsWhileSeeingForms", 0);
+}
+
+TEST_F(PasswordManagerTest, CertErrorReported) {
+ constexpr struct {
+ net::CertStatus cert_status;
+ metrics_util::CertificateError expected_error;
+ } kCases[] = {
+ {0, metrics_util::CertificateError::NONE},
+ {net::CERT_STATUS_SHA1_SIGNATURE_PRESENT, // not an error
+ metrics_util::CertificateError::NONE},
+ {net::CERT_STATUS_COMMON_NAME_INVALID,
+ metrics_util::CertificateError::COMMON_NAME_INVALID},
+ {net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM,
+ metrics_util::CertificateError::WEAK_SIGNATURE_ALGORITHM},
+ {net::CERT_STATUS_DATE_INVALID,
+ metrics_util::CertificateError::DATE_INVALID},
+ {net::CERT_STATUS_AUTHORITY_INVALID,
+ metrics_util::CertificateError::AUTHORITY_INVALID},
+ {net::CERT_STATUS_WEAK_KEY, metrics_util::CertificateError::OTHER},
+ {net::CERT_STATUS_DATE_INVALID | net::CERT_STATUS_WEAK_KEY,
+ metrics_util::CertificateError::DATE_INVALID},
+ {net::CERT_STATUS_DATE_INVALID | net::CERT_STATUS_AUTHORITY_INVALID,
+ metrics_util::CertificateError::AUTHORITY_INVALID},
+ {net::CERT_STATUS_DATE_INVALID | net::CERT_STATUS_AUTHORITY_INVALID |
+ net::CERT_STATUS_WEAK_KEY,
+ metrics_util::CertificateError::AUTHORITY_INVALID},
+ };
+
+ const std::vector<PasswordForm> observed = {PasswordForm()};
+
+ for (const auto& test_case : kCases) {
+ SCOPED_TRACE(testing::Message("index of test_case = ")
+ << (&test_case - kCases));
+ EXPECT_CALL(client_, GetMainFrameCertStatus())
+ .WillRepeatedly(Return(test_case.cert_status));
+ base::HistogramTester histogram_tester;
+ EXPECT_CALL(*store_, GetLogins(_, _));
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.CertificateErrorsWhileSeeingForms",
+ test_case.expected_error, 1);
+ }
+}
+
} // 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 837afe8f4e0..3cccd72398c 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_util.cc
@@ -16,8 +16,6 @@
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/sync/driver/sync_service.h"
-#include "crypto/openssl_util.h"
-#include "third_party/boringssl/src/include/openssl/evp.h"
namespace password_manager_util {
@@ -90,40 +88,6 @@ bool IsLoggingActive(const password_manager::PasswordManagerClient* client) {
return log_manager && log_manager->IsLoggingActive();
}
-uint64_t CalculateSyncPasswordHash(const base::StringPiece16& text,
- const std::string& salt) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- constexpr size_t kBytesFromHash = 8;
- constexpr uint64_t kScryptCost = 32; // It must be power of 2.
- constexpr uint64_t kScryptBlockSize = 8;
- constexpr uint64_t kScryptParallelization = 1;
- constexpr size_t kScryptMaxMemory = 1024 * 1024;
-
- uint8_t hash[kBytesFromHash];
- base::StringPiece text_8bits(reinterpret_cast<const char*>(text.data()),
- text.size() * 2);
- const uint8_t* salt_ptr = reinterpret_cast<const uint8_t*>(salt.c_str());
-
- int scrypt_ok = EVP_PBE_scrypt(text_8bits.data(), text_8bits.size(), salt_ptr,
- salt.size(), kScryptCost, kScryptBlockSize,
- kScryptParallelization, kScryptMaxMemory, hash,
- kBytesFromHash);
-
- // EVP_PBE_scrypt can only fail due to memory allocation error (which aborts
- // Chromium) or invalid parameters. In case of a failure a hash could leak
- // information from the stack, so using CHECK is better than DCHECK.
- CHECK(scrypt_ok);
-
- // Take 37 bits of |hash|.
- uint64_t hash37 = ((static_cast<uint64_t>(hash[0]))) |
- ((static_cast<uint64_t>(hash[1])) << 8) |
- ((static_cast<uint64_t>(hash[2])) << 16) |
- ((static_cast<uint64_t>(hash[3])) << 24) |
- (((static_cast<uint64_t>(hash[4])) & 0x1F) << 32);
-
- return hash37;
-}
-
bool ManualPasswordGenerationEnabled(syncer::SyncService* sync_service) {
if (!(base::FeatureList::IsEnabled(
password_manager::features::kEnableManualPasswordGeneration) &&
diff --git a/chromium/components/password_manager/core/browser/password_manager_util.h b/chromium/components/password_manager/core/browser/password_manager_util.h
index 2e0a1e3c2cd..1fa020d1e30 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util.h
+++ b/chromium/components/password_manager/core/browser/password_manager_util.h
@@ -54,11 +54,6 @@ void TrimUsernameOnlyCredentials(
// and required to always return non-null.
bool IsLoggingActive(const password_manager::PasswordManagerClient* client);
-// Calculates 37 bits hash for a sync password. The calculation is based on a
-// slow hash function. The running time is ~10^{-4} seconds on Desktop.
-uint64_t CalculateSyncPasswordHash(const base::StringPiece16& text,
- const std::string& salt);
-
// True iff the manual password generation is enabled and the user is sync user
// without custom passphrase.
bool ManualPasswordGenerationEnabled(syncer::SyncService* sync_service);
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 481284bc361..838270074a6 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
@@ -59,25 +59,3 @@ TEST(PasswordManagerUtil, TrimUsernameOnlyCredentials) {
EXPECT_THAT(forms, UnorderedPasswordFormElementsAre(&expected_forms));
}
-
-TEST(PasswordManagerUtil, CalculateSyncPasswordHash) {
- const char* kPlainText[] = {"", "password", "password", "secret"};
- const char* kSalt[] = {"", "salt", "123", "456"};
-
- constexpr uint64_t kExpectedHash[] = {
- UINT64_C(0x1c610a7950), UINT64_C(0x1927dc525e), UINT64_C(0xf72f81aa6),
- UINT64_C(0x3645af77f),
- };
-
- static_assert(arraysize(kPlainText) == arraysize(kSalt),
- "Arrays must have the same size");
- static_assert(arraysize(kPlainText) == arraysize(kExpectedHash),
- "Arrays must have the same size");
-
- for (size_t i = 0; i < arraysize(kPlainText); ++i) {
- SCOPED_TRACE(i);
- base::string16 text = base::UTF8ToUTF16(kPlainText[i]);
- EXPECT_EQ(kExpectedHash[i],
- password_manager_util::CalculateSyncPasswordHash(text, kSalt[i]));
- }
-}
diff --git a/chromium/components/password_manager/core/browser/password_reuse_defines.h b/chromium/components/password_manager/core/browser/password_reuse_defines.h
index 99c8f73a742..a45e9ff6825 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_defines.h
+++ b/chromium/components/password_manager/core/browser/password_reuse_defines.h
@@ -6,7 +6,7 @@
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_REUSE_DEFINES_H_
#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+ defined(OS_LINUX) || defined(OS_CHROMEOS)
// Enable the detection when the sync password is typed not on the sync domain.
#define SYNC_PASSWORD_REUSE_DETECTION_ENABLED
#endif
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detector.cc b/chromium/components/password_manager/core/browser/password_reuse_detector.cc
index cd7b8f8f81d..cf8cbb9fbe8 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detector.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detector.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/browser/password_manager_util.h"
+#include "components/password_manager/core/browser/hash_password_manager.h"
#include "components/password_manager/core/browser/password_reuse_detector_consumer.h"
#include "components/password_manager/core/browser/psl_matching_helper.h"
#include "google_apis/gaia/gaia_auth_util.h"
@@ -103,7 +103,7 @@ size_t PasswordReuseDetector::CheckSyncPasswordReuse(
size_t offset = input.size() - sync_password_data_->length;
base::string16 reuse_candidate = input.substr(offset);
- if (password_manager_util::CalculateSyncPasswordHash(
+ if (HashPasswordManager::CalculateSyncPasswordHash(
reuse_candidate, sync_password_data_->salt) ==
sync_password_data_->hash) {
return reuse_candidate.size();
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc b/chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc
index 93bb2454197..760f35a38c9 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc
@@ -13,7 +13,6 @@
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/hash_password_manager.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
-#include "components/password_manager/core/browser/password_manager_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -80,7 +79,7 @@ SyncPasswordData GetSyncPasswordData(const std::string& sync_password) {
SyncPasswordData sync_password_data;
sync_password_data.salt = "1234567890123456";
sync_password_data.length = sync_password.size();
- sync_password_data.hash = password_manager_util::CalculateSyncPasswordHash(
+ sync_password_data.hash = HashPasswordManager::CalculateSyncPasswordHash(
base::ASCIIToUTF16(sync_password), sync_password_data.salt);
return sync_password_data;
}
diff --git a/chromium/components/password_manager/core/browser/password_store.cc b/chromium/components/password_manager/core/browser/password_store.cc
index 9432109a686..a04fb42a544 100644
--- a/chromium/components/password_manager/core/browser/password_store.cc
+++ b/chromium/components/password_manager/core/browser/password_store.cc
@@ -19,12 +19,14 @@
#include "build/build_config.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.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_reuse_defines.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
#include "components/password_manager/core/browser/password_syncable_service.h"
#include "components/password_manager/core/browser/statistics_table.h"
-#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
#include "components/password_manager/core/browser/password_store_signin_notifier.h"
#endif
@@ -63,7 +65,7 @@ void PasswordStore::GetLoginsRequest::NotifyWithSiteStatistics(
}
// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
PasswordStore::CheckReuseRequest::CheckReuseRequest(
PasswordReuseDetectorConsumer* consumer)
: origin_task_runner_(base::SequencedTaskRunnerHandle::Get()),
@@ -273,10 +275,14 @@ void PasswordStore::ReportMetrics(const std::string& sync_username,
base::TimeDelta::FromSeconds(30));
}
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
- if (!sync_username.empty())
- hash_password_manager_.ReportIsSyncPasswordHashSavedMetric();
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
+ if (!sync_username.empty()) {
+ auto hash_password_state =
+ hash_password_manager_.HasPasswordHash()
+ ? metrics_util::IsSyncPasswordHashSaved::SAVED
+ : metrics_util::IsSyncPasswordHashSaved::NOT_SAVED;
+ metrics_util::LogIsSyncPasswordHashSaved(hash_password_state);
+ }
#endif
}
@@ -335,7 +341,7 @@ PasswordStore::GetPasswordSyncableService() {
}
// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
void PasswordStore::CheckReuse(const base::string16& input,
const std::string& domain,
PasswordReuseDetectorConsumer* consumer) {
@@ -355,6 +361,13 @@ void PasswordStore::SaveSyncPasswordHash(const base::string16& password) {
std::move(sync_password_data)));
}
+void PasswordStore::SaveSyncPasswordHash(
+ const SyncPasswordData& sync_password_data) {
+ hash_password_manager_.SavePasswordHash(sync_password_data);
+ ScheduleTask(base::BindRepeating(&PasswordStore::SaveSyncPasswordHashImpl,
+ this, sync_password_data));
+}
+
void PasswordStore::ClearSyncPasswordHash() {
hash_password_manager_.ClearSavedPasswordHash();
ScheduleTask(base::Bind(&PasswordStore::ClearSyncPasswordHashImpl, this));
@@ -386,7 +399,7 @@ void PasswordStore::InitOnBackgroundSequence(
syncable_service_.reset(new PasswordSyncableService(this));
syncable_service_->InjectStartSyncFlare(flare);
// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
reuse_detector_ = new PasswordReuseDetector;
GetAutofillableLoginsImpl(
std::make_unique<GetLoginsRequest>(reuse_detector_));
@@ -449,7 +462,7 @@ void PasswordStore::NotifyLoginsChanged(
if (syncable_service_)
syncable_service_->ActOnPasswordStoreChanges(changes);
// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
if (reuse_detector_)
reuse_detector_->OnLoginsChanged(changes);
#endif
@@ -457,7 +470,7 @@ void PasswordStore::NotifyLoginsChanged(
}
// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
void PasswordStore::CheckReuseImpl(std::unique_ptr<CheckReuseRequest> request,
const base::string16& input,
const std::string& domain) {
@@ -789,7 +802,7 @@ void PasswordStore::DestroyOnBackgroundSequence() {
DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
syncable_service_.reset();
// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
delete reuse_detector_;
reuse_detector_ = nullptr;
#endif
diff --git a/chromium/components/password_manager/core/browser/password_store.h b/chromium/components/password_manager/core/browser/password_store.h
index be44ebadefb..859c03ca859 100644
--- a/chromium/components/password_manager/core/browser/password_store.h
+++ b/chromium/components/password_manager/core/browser/password_store.h
@@ -24,7 +24,7 @@
#include "components/sync/model/syncable_service.h"
// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
#include "components/password_manager/core/browser/hash_password_manager.h"
#include "components/password_manager/core/browser/password_reuse_detector.h"
#include "components/password_manager/core/browser/password_reuse_detector_consumer.h"
@@ -248,7 +248,7 @@ class PasswordStore : protected PasswordStoreSync,
base::WeakPtr<syncer::SyncableService> GetPasswordSyncableService();
// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
// Checks that some suffix of |input| equals to a password saved on another
// registry controlled domain than |domain|.
// If such suffix is found, |consumer|->OnReuseFound() is called on the same
@@ -258,10 +258,12 @@ class PasswordStore : protected PasswordStoreSync,
const std::string& domain,
PasswordReuseDetectorConsumer* consumer);
-#if !defined(OS_CHROMEOS)
// Saves a hash of |password| for password reuse checking.
virtual void SaveSyncPasswordHash(const base::string16& password);
+ // Saves |sync_password_data| for password reuse checking.
+ virtual void SaveSyncPasswordHash(const SyncPasswordData& sync_password_data);
+
// Clears the saved sync password hash.
virtual void ClearSyncPasswordHash();
@@ -269,7 +271,6 @@ class PasswordStore : protected PasswordStoreSync,
void SetPasswordStoreSigninNotifier(
std::unique_ptr<PasswordStoreSigninNotifier> notifier);
#endif
-#endif
protected:
friend class base::RefCountedThreadSafe<PasswordStore>;
@@ -307,7 +308,7 @@ class PasswordStore : protected PasswordStoreSync,
};
// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
// Represents a single CheckReuse() request. Implements functionality to
// listen to reuse events and propagate them to |consumer| on the sequence on
// which CheckReuseRequest is created.
@@ -434,7 +435,7 @@ class PasswordStore : protected PasswordStoreSync,
void NotifyLoginsChanged(const PasswordStoreChangeList& changes) override;
// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
// Synchronous implementation of CheckReuse().
void CheckReuseImpl(std::unique_ptr<CheckReuseRequest> request,
const base::string16& input,
@@ -601,13 +602,11 @@ class PasswordStore : protected PasswordStoreSync,
std::unique_ptr<PasswordSyncableService> syncable_service_;
std::unique_ptr<AffiliatedMatchHelper> affiliated_match_helper_;
// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
// PasswordReuseDetector can be only destroyed on the background sequence. It
// can't be owned by PasswordStore because PasswordStore can be destroyed on
// the UI thread and DestroyOnBackgroundThread isn't guaranteed to be called.
PasswordReuseDetector* reuse_detector_ = nullptr;
-#endif
-#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
std::unique_ptr<PasswordStoreSigninNotifier> notifier_;
HashPasswordManager hash_password_manager_;
#endif
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 1614515b93c..b241c016b65 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
@@ -207,7 +207,6 @@ TEST(PasswordStoreDefaultTest, Notifications) {
// Adding a login should trigger a notification.
store->AddLogin(*form);
- delegate.FinishAsyncProcessing();
// Change the password.
form->password_value = base::ASCIIToUTF16("a different password");
@@ -221,7 +220,6 @@ TEST(PasswordStoreDefaultTest, Notifications) {
// Updating the login with the new password should trigger a notification.
store->UpdateLogin(*form);
- delegate.FinishAsyncProcessing();
const PasswordStoreChange expected_delete_changes[] = {
PasswordStoreChange(PasswordStoreChange::REMOVE, *form),
@@ -232,6 +230,7 @@ TEST(PasswordStoreDefaultTest, Notifications) {
// Deleting the login should trigger a notification.
store->RemoveLogin(*form);
+ // Run the tasks to allow all the above expected calls to take place.
delegate.FinishAsyncProcessing();
store->RemoveObserver(&observer);
diff --git a/chromium/components/password_manager/core/browser/password_store_factory_util.cc b/chromium/components/password_manager/core/browser/password_store_factory_util.cc
index f7a98244596..4e8cdb8db09 100644
--- a/chromium/components/password_manager/core/browser/password_store_factory_util.cc
+++ b/chromium/components/password_manager/core/browser/password_store_factory_util.cc
@@ -30,16 +30,21 @@ void ActivateAffiliationBasedMatching(
PasswordStore* password_store,
net::URLRequestContextGetter* request_context_getter,
const base::FilePath& db_path) {
- // The PasswordStore is so far the only consumer of the AffiliationService,
- // therefore the service is owned by the AffiliatedMatchHelper, which in
- // turn is owned by the PasswordStore.
+ // Subsequent instances of the AffiliationService must use the same sequenced
+ // task runner for their backends. This guarantees that the backend of the
+ // first instance will have closed the affiliation database before the second
+ // instance attempts to open it again. See: https://crbug.com/786157.
+ //
// Task priority is USER_VISIBLE, because AffiliationService-related tasks
- // block obtaining credentials from PasswordStore, which matches the
- // USER_VISIBLE example: "Loading data that might be shown in the UI after a
- // future user interaction."
+ // block obtaining credentials from PasswordStore, hence password autofill.
+ static auto backend_task_runner = base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
+
+ // The PasswordStore is so far the only consumer of the AffiliationService,
+ // therefore the service is owned by the AffiliatedMatchHelper, which in turn
+ // is owned by the PasswordStore.
std::unique_ptr<AffiliationService> affiliation_service(
- new AffiliationService(base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::USER_VISIBLE})));
+ new AffiliationService(backend_task_runner));
affiliation_service->Initialize(request_context_getter, db_path);
std::unique_ptr<AffiliatedMatchHelper> affiliated_match_helper(
new AffiliatedMatchHelper(password_store,
diff --git a/chromium/components/password_manager/core/browser/stub_form_saver.h b/chromium/components/password_manager/core/browser/stub_form_saver.h
index 769fe436f3e..af31ff8766d 100644
--- a/chromium/components/password_manager/core/browser/stub_form_saver.h
+++ b/chromium/components/password_manager/core/browser/stub_form_saver.h
@@ -21,8 +21,7 @@ class StubFormSaver : public FormSaver {
void PermanentlyBlacklist(autofill::PasswordForm* observed) override {}
void Save(const autofill::PasswordForm& pending,
const std::map<base::string16, const autofill::PasswordForm*>&
- best_matches,
- const autofill::PasswordForm* old_primary_key) override {}
+ best_matches) override {}
void Update(const autofill::PasswordForm& pending,
const std::map<base::string16, const autofill::PasswordForm*>&
best_matches,
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 b24baff278b..7654e2bc971 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
@@ -12,9 +12,7 @@
namespace password_manager {
StubPasswordManagerClient::StubPasswordManagerClient()
- : ukm_source_id_(ukm::UkmRecorder::Get()
- ? ukm::UkmRecorder::Get()->GetNewSourceID()
- : 0) {}
+ : ukm_source_id_(ukm::UkmRecorder::GetNewSourceID()) {}
StubPasswordManagerClient::~StubPasswordManagerClient() {}
@@ -92,10 +90,6 @@ void StubPasswordManagerClient::CheckProtectedPasswordEntry(
void StubPasswordManagerClient::LogPasswordReuseDetectedEvent() {}
#endif
-ukm::UkmRecorder* StubPasswordManagerClient::GetUkmRecorder() {
- return ukm::UkmRecorder::Get();
-}
-
ukm::SourceId StubPasswordManagerClient::GetUkmSourceId() {
return ukm_source_id_;
}
@@ -103,8 +97,7 @@ ukm::SourceId StubPasswordManagerClient::GetUkmSourceId() {
PasswordManagerMetricsRecorder&
StubPasswordManagerClient::GetMetricsRecorder() {
if (!metrics_recorder_) {
- metrics_recorder_.emplace(GetUkmRecorder(), GetUkmSourceId(),
- GetMainFrameURL());
+ metrics_recorder_.emplace(GetUkmSourceId(), GetMainFrameURL());
}
return metrics_recorder_.value();
}
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 1578d649981..cee51f056b9 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
@@ -61,7 +61,6 @@ class StubPasswordManagerClient : public PasswordManagerClient {
bool password_field_exists) override;
void LogPasswordReuseDetectedEvent() override;
#endif
- ukm::UkmRecorder* GetUkmRecorder() override;
ukm::SourceId GetUkmSourceId() override;
PasswordManagerMetricsRecorder& GetMetricsRecorder() override;
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 876b44790d1..cc2a6d50bc4 100644
--- a/chromium/components/password_manager/core/common/credential_manager_types.h
+++ b/chromium/components/password_manager/core/common/credential_manager_types.h
@@ -35,8 +35,7 @@ enum class CredentialType {
enum class CredentialManagerError {
SUCCESS,
- DISABLED,
- PENDINGREQUEST,
+ PENDING_REQUEST,
PASSWORDSTOREUNAVAILABLE,
UNKNOWN,
};
diff --git a/chromium/components/password_manager/core/common/experiments.cc b/chromium/components/password_manager/core/common/experiments.cc
index c2329b1cdd0..7ff43cecca0 100644
--- a/chromium/components/password_manager/core/common/experiments.cc
+++ b/chromium/components/password_manager/core/common/experiments.cc
@@ -10,7 +10,7 @@ namespace password_manager {
bool ForceSavingExperimentEnabled() {
return base::FeatureList::IsEnabled(
- password_manager::features::kEnablePasswordForceSaving);
+ password_manager::features::kPasswordForceSaving);
}
} // 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 b0dcae4184b..b7d2818cbf3 100644
--- a/chromium/components/password_manager/core/common/password_manager_features.cc
+++ b/chromium/components/password_manager/core/common/password_manager_features.cc
@@ -14,11 +14,11 @@ namespace features {
// application will also be considered matches for, and be filled into
// corresponding Web applications.
const base::Feature kAffiliationBasedMatching = {
- "affiliation-based-matching", base::FEATURE_ENABLED_BY_DEFAULT};
+ "AffiliationBasedMatching", base::FEATURE_ENABLED_BY_DEFAULT};
// Use HTML based username detector.
const base::Feature kEnableHtmlBasedUsernameDetector = {
- "EnableHtmlBaseUsernameDetector", base::FEATURE_DISABLED_BY_DEFAULT};
+ "EnableHtmlBaseUsernameDetector", base::FEATURE_ENABLED_BY_DEFAULT};
// Enable additional elements in the form popup UI, which will allow the user to
// view all saved passwords.
@@ -44,21 +44,13 @@ const base::Feature kEnableManualSaving = {"EnableManualSaving",
// Enable a context menu item in the password field that allows the user
// to manually enforce saving of their password.
-const base::Feature kEnablePasswordForceSaving = {
- "enable-password-force-saving", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kPasswordForceSaving = {
+ "PasswordForceSaving", base::FEATURE_DISABLED_BY_DEFAULT};
// Enable the user to trigger password generation manually.
const base::Feature kEnableManualPasswordGeneration = {
"enable-manual-password-generation", base::FEATURE_ENABLED_BY_DEFAULT};
-// Enables username correction while saving username and password details.
-const base::Feature kEnableUsernameCorrection{"EnableUsernameCorrection",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Enables password selection while saving username and password details.
-const base::Feature kEnablePasswordSelection{"EnablePasswordSelection",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
// Enables the "Show all saved passwords" option in Context Menu.
const base::Feature kEnableShowAllSavedPasswordsContextMenu{
"kEnableShowAllSavedPasswordsContextMenu",
@@ -71,20 +63,20 @@ const base::Feature kProtectSyncCredential = {
// Disallow autofilling of the sync credential only for transactional reauth
// pages.
const base::Feature kProtectSyncCredentialOnReauth = {
- "protect-sync-credential-on-reauth", base::FEATURE_DISABLED_BY_DEFAULT};
+ "ProtectSyncCredentialOnReauth", base::FEATURE_DISABLED_BY_DEFAULT};
// Controls the ability to export passwords from Chrome's settings page.
-const base::Feature kPasswordExport = {"password-export",
+const base::Feature kPasswordExport = {"PasswordExport",
base::FEATURE_DISABLED_BY_DEFAULT};
// Controls the ability to import passwords from Chrome's settings page.
-const base::Feature kPasswordImport = {"password-import",
+const base::Feature kPasswordImport = {"PasswordImport",
base::FEATURE_DISABLED_BY_DEFAULT};
// Control whether users can view and copy passwords. This is only used for
// mobile, the desktop version of Chrome always allows users to view
// passwords.
-const base::Feature kViewPasswords = {"view-passwords",
+const base::Feature kViewPasswords = {"ViewPasswords",
base::FEATURE_ENABLED_BY_DEFAULT};
// Enables the experiment for the password manager to only fill on account
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 2c10d4ccc47..cd495b9fd9e 100644
--- a/chromium/components/password_manager/core/common/password_manager_features.h
+++ b/chromium/components/password_manager/core/common/password_manager_features.h
@@ -24,10 +24,8 @@ extern const base::Feature kEnableManualFallbacksFillingStandalone;
extern const base::Feature kEnableManualFallbacksGeneration;
extern const base::Feature kEnableManualPasswordGeneration;
extern const base::Feature kEnableManualSaving;
-extern const base::Feature kEnablePasswordForceSaving;
-extern const base::Feature kEnablePasswordSelection;
+extern const base::Feature kPasswordForceSaving;
extern const base::Feature kEnableShowAllSavedPasswordsContextMenu;
-extern const base::Feature kEnableUsernameCorrection;
extern const base::Feature kFillOnAccountSelect;
extern const base::Feature kPasswordExport;
extern const base::Feature kPasswordImport;