Commit f92938c9 authored by Irina Fedorova's avatar Irina Fedorova Committed by Commit Bot

Add GetWeakCredentials and OnWeakCredentialsChanged

This CL adds GetWeakCredentials, OnWeakCredentialsChanged,
addWeakCredentialsListener and removeWeakCredentialsListener functions
to provide the ability to use weak credentials in the UI. This CL
updates the StartPasswordCheck in password_check_delegate to also check
credentials for weakness.

Bug: 1119752
Change-Id: I4bfee58ddebda551e41e3833792051527a41beb9
Tbr: rdevlin.cronin@chromium.org
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2414271
Commit-Queue: Irina Fedorova <irfedorova@google.com>
Reviewed-by: default avatarKaran Bhatia <karandeepb@chromium.org>
Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808811}
parent 459b1e93
...@@ -265,51 +265,9 @@ PasswordCheckDelegate::GetCompromisedCredentials() { ...@@ -265,51 +265,9 @@ PasswordCheckDelegate::GetCompromisedCredentials() {
ordered_compromised_credential_and_types.size()); ordered_compromised_credential_and_types.size());
for (const auto& credential_and_type : for (const auto& credential_and_type :
ordered_compromised_credential_and_types) { ordered_compromised_credential_and_types) {
const auto& credential = credential_and_type.credential; const CredentialWithPassword& credential = credential_and_type.credential;
api::passwords_private::InsecureCredential api_credential; api::passwords_private::InsecureCredential api_credential =
auto facet = password_manager::FacetURI::FromPotentiallyInvalidSpec( ConstructInsecureCredential(credential);
credential.signon_realm);
if (facet.IsValidAndroidFacetURI()) {
api_credential.is_android_credential = true;
// |formatted_orgin|, |detailed_origin| and |change_password_url| need
// special handling for Android. Here we use affiliation information
// instead of the origin.
const PasswordForm& android_form =
insecure_credentials_manager_.GetSavedPasswordsFor(credential)[0];
if (!android_form.app_display_name.empty()) {
api_credential.formatted_origin = android_form.app_display_name;
api_credential.detailed_origin = android_form.app_display_name;
api_credential.change_password_url =
GetChangePasswordUrl(GURL(android_form.affiliated_web_realm));
} else {
// In case no affiliation information could be obtained show the
// formatted package name to the user. An empty change_password_url will
// be handled by the frontend, by not including a link in this case.
api_credential.formatted_origin = l10n_util::GetStringFUTF8(
IDS_SETTINGS_PASSWORDS_ANDROID_APP,
base::UTF8ToUTF16(facet.android_package_name()));
api_credential.detailed_origin = facet.android_package_name();
}
} else {
api_credential.is_android_credential = false;
api_credential.formatted_origin =
base::UTF16ToUTF8(url_formatter::FormatUrl(
credential.url.GetOrigin(),
url_formatter::kFormatUrlOmitDefaults |
url_formatter::kFormatUrlOmitHTTPS |
url_formatter::kFormatUrlOmitTrivialSubdomains |
url_formatter::kFormatUrlTrimAfterHost,
net::UnescapeRule::SPACES, nullptr, nullptr, nullptr));
api_credential.detailed_origin =
base::UTF16ToUTF8(url_formatter::FormatUrlForSecurityDisplay(
credential.url.GetOrigin()));
api_credential.change_password_url = GetChangePasswordUrl(credential.url);
}
api_credential.id =
insecure_credential_id_generator_.GenerateId(credential);
api_credential.signon_realm = credential.signon_realm;
api_credential.username = base::UTF16ToUTF8(credential.username);
api_credential.compromised_info = api_credential.compromised_info =
std::make_unique<api::passwords_private::CompromisedInfo>(); std::make_unique<api::passwords_private::CompromisedInfo>();
api_credential.compromised_info->compromise_time = api_credential.compromised_info->compromise_time =
...@@ -323,6 +281,20 @@ PasswordCheckDelegate::GetCompromisedCredentials() { ...@@ -323,6 +281,20 @@ PasswordCheckDelegate::GetCompromisedCredentials() {
return compromised_credentials; return compromised_credentials;
} }
std::vector<api::passwords_private::InsecureCredential>
PasswordCheckDelegate::GetWeakCredentials() {
std::vector<CredentialWithPassword> weak_credentials =
insecure_credentials_manager_.GetWeakCredentials();
std::vector<api::passwords_private::InsecureCredential> api_credentials;
api_credentials.reserve(weak_credentials.size());
for (const auto& weak_credential : weak_credentials) {
api_credentials.push_back(ConstructInsecureCredential(weak_credential));
}
return api_credentials;
}
base::Optional<api::passwords_private::InsecureCredential> base::Optional<api::passwords_private::InsecureCredential>
PasswordCheckDelegate::GetPlaintextInsecurePassword( PasswordCheckDelegate::GetPlaintextInsecurePassword(
api::passwords_private::InsecureCredential credential) const { api::passwords_private::InsecureCredential credential) const {
...@@ -376,6 +348,11 @@ void PasswordCheckDelegate::StartPasswordCheck( ...@@ -376,6 +348,11 @@ void PasswordCheckDelegate::StartPasswordCheck(
return; return;
} }
if (base::FeatureList::IsEnabled(
password_manager::features::kPasswordsWeaknessCheck)) {
insecure_credentials_manager_.StartWeakCheck();
}
auto progress = base::MakeRefCounted<PasswordCheckProgress>(); auto progress = base::MakeRefCounted<PasswordCheckProgress>();
for (const auto& password : saved_passwords_presenter_.GetSavedPasswords()) for (const auto& password : saved_passwords_presenter_.GetSavedPasswords())
progress->IncrementCounts(password); progress->IncrementCounts(password);
...@@ -464,11 +441,11 @@ void PasswordCheckDelegate::OnCompromisedCredentialsChanged( ...@@ -464,11 +441,11 @@ void PasswordCheckDelegate::OnCompromisedCredentialsChanged(
} }
} }
void PasswordCheckDelegate::OnWeakCredentialsChanged( void PasswordCheckDelegate::OnWeakCredentialsChanged() {
InsecureCredentialsView credentials) { if (auto* event_router =
// TODO(crbug.com/1119752): Implement this method after adding PasswordsPrivateEventRouterFactory::GetForProfile(profile_)) {
// OnWeakCredentialsChanged to PasswordsPrivateEventRouter. event_router->OnWeakCredentialsChanged(GetWeakCredentials());
NOTIMPLEMENTED(); }
} }
void PasswordCheckDelegate::OnStateChanged(State state) { void PasswordCheckDelegate::OnStateChanged(State state) {
...@@ -541,4 +518,53 @@ void PasswordCheckDelegate::NotifyPasswordCheckStatusChanged() { ...@@ -541,4 +518,53 @@ void PasswordCheckDelegate::NotifyPasswordCheckStatusChanged() {
} }
} }
api::passwords_private::InsecureCredential
PasswordCheckDelegate::ConstructInsecureCredential(
const CredentialWithPassword& credential) {
api::passwords_private::InsecureCredential api_credential;
auto facet = password_manager::FacetURI::FromPotentiallyInvalidSpec(
credential.signon_realm);
if (facet.IsValidAndroidFacetURI()) {
api_credential.is_android_credential = true;
// |formatted_orgin|, |detailed_origin| and |change_password_url| need
// special handling for Android. Here we use affiliation information
// instead of the origin.
const PasswordForm& android_form =
insecure_credentials_manager_.GetSavedPasswordsFor(credential)[0];
if (!android_form.app_display_name.empty()) {
api_credential.formatted_origin = android_form.app_display_name;
api_credential.detailed_origin = android_form.app_display_name;
api_credential.change_password_url =
GetChangePasswordUrl(GURL(android_form.affiliated_web_realm));
} else {
// In case no affiliation information could be obtained show the
// formatted package name to the user. An empty change_password_url will
// be handled by the frontend, by not including a link in this case.
api_credential.formatted_origin = l10n_util::GetStringFUTF8(
IDS_SETTINGS_PASSWORDS_ANDROID_APP,
base::UTF8ToUTF16(facet.android_package_name()));
api_credential.detailed_origin = facet.android_package_name();
}
} else {
api_credential.is_android_credential = false;
api_credential.formatted_origin =
base::UTF16ToUTF8(url_formatter::FormatUrl(
credential.url.GetOrigin(),
url_formatter::kFormatUrlOmitDefaults |
url_formatter::kFormatUrlOmitHTTPS |
url_formatter::kFormatUrlOmitTrivialSubdomains |
url_formatter::kFormatUrlTrimAfterHost,
net::UnescapeRule::SPACES, nullptr, nullptr, nullptr));
api_credential.detailed_origin = base::UTF16ToUTF8(
url_formatter::FormatUrlForSecurityDisplay(credential.url.GetOrigin()));
api_credential.change_password_url = GetChangePasswordUrl(credential.url);
}
api_credential.id = insecure_credential_id_generator_.GenerateId(credential);
api_credential.signon_realm = credential.signon_realm;
api_credential.username = base::UTF16ToUTF8(credential.username);
return api_credential;
}
} // namespace extensions } // namespace extensions
...@@ -55,6 +55,9 @@ class PasswordCheckDelegate ...@@ -55,6 +55,9 @@ class PasswordCheckDelegate
std::vector<api::passwords_private::InsecureCredential> std::vector<api::passwords_private::InsecureCredential>
GetCompromisedCredentials(); GetCompromisedCredentials();
// Obtains information about weak credentials.
std::vector<api::passwords_private::InsecureCredential> GetWeakCredentials();
// Requests the plaintext password for |credential|. If successful, this // Requests the plaintext password for |credential|. If successful, this
// returns |credential| with its |password| member set. This can fail if no // returns |credential| with its |password| member set. This can fail if no
// matching insecure credential can be found in the password store. // matching insecure credential can be found in the password store.
...@@ -99,9 +102,7 @@ class PasswordCheckDelegate ...@@ -99,9 +102,7 @@ class PasswordCheckDelegate
// password_manager::InsecureCredentialsManager::Observer: // password_manager::InsecureCredentialsManager::Observer:
// Invokes PasswordsPrivateEventRouter::OnWeakCredentialsChanged if a valid // Invokes PasswordsPrivateEventRouter::OnWeakCredentialsChanged if a valid
// pointer can be obtained. // pointer can be obtained.
void OnWeakCredentialsChanged( void OnWeakCredentialsChanged() override;
password_manager::InsecureCredentialsManager::CredentialsView credentials)
override;
// password_manager::BulkLeakCheckService::Observer: // password_manager::BulkLeakCheckService::Observer:
void OnStateChanged( void OnStateChanged(
...@@ -124,6 +125,10 @@ class PasswordCheckDelegate ...@@ -124,6 +125,10 @@ class PasswordCheckDelegate
// OnStateChanged. // OnStateChanged.
void NotifyPasswordCheckStatusChanged(); void NotifyPasswordCheckStatusChanged();
// Constructs |InsecureCredential| from |CredentialWithPassword|.
api::passwords_private::InsecureCredential ConstructInsecureCredential(
const password_manager::CredentialWithPassword& credential);
// Raw pointer to the underlying profile. Needs to outlive this instance. // Raw pointer to the underlying profile. Needs to outlive this instance.
Profile* profile_ = nullptr; Profile* profile_ = nullptr;
......
...@@ -67,6 +67,8 @@ constexpr char kUsername2[] = "bob"; ...@@ -67,6 +67,8 @@ constexpr char kUsername2[] = "bob";
constexpr char kPassword1[] = "s3cre3t"; constexpr char kPassword1[] = "s3cre3t";
constexpr char kPassword2[] = "f00b4r"; constexpr char kPassword2[] = "f00b4r";
constexpr char kWeakPassword1[] = "123456";
constexpr char kWeakPassword2[] = "111111";
using api::passwords_private::CompromisedInfo; using api::passwords_private::CompromisedInfo;
using api::passwords_private::InsecureCredential; using api::passwords_private::InsecureCredential;
...@@ -177,15 +179,34 @@ PasswordForm MakeSavedAndroidPassword( ...@@ -177,15 +179,34 @@ PasswordForm MakeSavedAndroidPassword(
base::StringPiece package_name, base::StringPiece package_name,
base::StringPiece username, base::StringPiece username,
base::StringPiece app_display_name = "", base::StringPiece app_display_name = "",
base::StringPiece affiliated_web_realm = "") { base::StringPiece affiliated_web_realm = "",
base::StringPiece password = kPassword1) {
PasswordForm form; PasswordForm form;
form.signon_realm = MakeAndroidRealm(package_name); form.signon_realm = MakeAndroidRealm(package_name);
form.username_value = base::ASCIIToUTF16(username); form.username_value = base::ASCIIToUTF16(username);
form.app_display_name = std::string(app_display_name); form.app_display_name = std::string(app_display_name);
form.affiliated_web_realm = std::string(affiliated_web_realm); form.affiliated_web_realm = std::string(affiliated_web_realm);
form.password_value = base::ASCIIToUTF16(password);
return form; return form;
} }
// Creates matcher for a given insecure credential.
auto ExpectInsecureCredential(
const std::string& formatted_origin,
const std::string& detailed_origin,
const base::Optional<std::string>& change_password_url,
const std::string& username) {
auto change_password_url_field_matcher =
change_password_url.has_value()
? Field(&InsecureCredential::change_password_url,
Pointee(change_password_url.value()))
: Field(&InsecureCredential::change_password_url, IsNull());
return AllOf(Field(&InsecureCredential::formatted_origin, formatted_origin),
Field(&InsecureCredential::detailed_origin, detailed_origin),
change_password_url_field_matcher,
Field(&InsecureCredential::username, username));
}
// Creates matcher for a given compromised info. // Creates matcher for a given compromised info.
auto ExpectCompromisedInfo( auto ExpectCompromisedInfo(
base::TimeDelta elapsed_time_since_compromise, base::TimeDelta elapsed_time_since_compromise,
...@@ -208,15 +229,8 @@ auto ExpectCompromisedCredential( ...@@ -208,15 +229,8 @@ auto ExpectCompromisedCredential(
base::TimeDelta elapsed_time_since_compromise, base::TimeDelta elapsed_time_since_compromise,
const std::string& elapsed_time_since_compromise_str, const std::string& elapsed_time_since_compromise_str,
api::passwords_private::CompromiseType compromise_type) { api::passwords_private::CompromiseType compromise_type) {
auto change_password_url_field_matcher = return AllOf(ExpectInsecureCredential(formatted_origin, detailed_origin,
change_password_url.has_value() change_password_url, username),
? Field(&InsecureCredential::change_password_url,
Pointee(change_password_url.value()))
: Field(&InsecureCredential::change_password_url, IsNull());
return AllOf(Field(&InsecureCredential::formatted_origin, formatted_origin),
Field(&InsecureCredential::detailed_origin, detailed_origin),
change_password_url_field_matcher,
Field(&InsecureCredential::username, username),
Field(&InsecureCredential::compromised_info, Field(&InsecureCredential::compromised_info,
Pointee(ExpectCompromisedInfo( Pointee(ExpectCompromisedInfo(
elapsed_time_since_compromise, elapsed_time_since_compromise,
...@@ -286,6 +300,77 @@ TEST_F(PasswordCheckDelegateTest, VerifyCastingOfCompromisedCredentialTypes) { ...@@ -286,6 +300,77 @@ TEST_F(PasswordCheckDelegateTest, VerifyCastingOfCompromisedCredentialTypes) {
""); "");
} }
// Verify that weak credentials will not be found if kPasswordsWeaknessCheck is
// disabled.
TEST_F(PasswordCheckDelegateTest, DisablePasswordsWeaknessCheck) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(
password_manager::features::kPasswordsWeaknessCheck);
store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1));
RunUntilIdle();
delegate().StartPasswordCheck();
RunUntilIdle();
EXPECT_THAT(delegate().GetWeakCredentials(), IsEmpty());
}
// Verify that GetWeakCredentials() correctly represents weak credentials.
TEST_F(PasswordCheckDelegateTest, GetWeakCredentialsFillsFielsCorrectly) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
password_manager::features::kPasswordsWeaknessCheck);
store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1));
store().AddLogin(MakeSavedAndroidPassword(
kExampleApp, kUsername2, "Example App", kExampleCom, kWeakPassword2));
RunUntilIdle();
delegate().StartPasswordCheck();
RunUntilIdle();
EXPECT_THAT(
delegate().GetWeakCredentials(),
UnorderedElementsAre(
ExpectInsecureCredential("example.com", "https://example.com",
"https://example.com/", kUsername1),
ExpectInsecureCredential("Example App", "Example App",
"https://example.com/", kUsername2)));
}
// Verify that computation of weak credentials notifies observers.
TEST_F(PasswordCheckDelegateTest, WeakCheckNotifiesObservers) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
password_manager::features::kPasswordsWeaknessCheck);
const char* const kEventName =
api::passwords_private::OnWeakCredentialsChanged::kEventName;
// Verify that the event was not fired during construction.
EXPECT_FALSE(base::Contains(event_router_observer().events(), kEventName));
// Verify that the event gets fired after weak check is complete.
delegate().StartPasswordCheck();
RunUntilIdle();
EXPECT_EQ(events::PASSWORDS_PRIVATE_ON_WEAK_CREDENTIALS_CHANGED,
event_router_observer().events().at(kEventName)->histogram_value);
}
// Verifies that the weak check will be run if the user is signed out.
TEST_F(PasswordCheckDelegateTest, WeakCheckWhenUserSignedOut) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
password_manager::features::kPasswordsWeaknessCheck);
store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1));
RunUntilIdle();
delegate().StartPasswordCheck();
RunUntilIdle();
EXPECT_THAT(delegate().GetWeakCredentials(),
ElementsAre(ExpectInsecureCredential(
"example.com", "https://example.com", "https://example.com/",
kUsername1)));
EXPECT_EQ(api::passwords_private::PASSWORD_CHECK_STATE_SIGNED_OUT,
delegate().GetPasswordCheckStatus().state);
}
// Sets up the password store with a couple of passwords and compromised // Sets up the password store with a couple of passwords and compromised
// credentials. Verifies that the result is ordered in such a way that phished // credentials. Verifies that the result is ordered in such a way that phished
// credentials are before leaked credentials and that within each group // credentials are before leaked credentials and that within each group
......
...@@ -271,6 +271,16 @@ ResponseAction PasswordsPrivateGetCompromisedCredentialsFunction::Run() { ...@@ -271,6 +271,16 @@ ResponseAction PasswordsPrivateGetCompromisedCredentialsFunction::Run() {
GetDelegate(browser_context())->GetCompromisedCredentials()))); GetDelegate(browser_context())->GetCompromisedCredentials())));
} }
// PasswordsPrivateGetWeakCredentialsFunction:
PasswordsPrivateGetWeakCredentialsFunction::
~PasswordsPrivateGetWeakCredentialsFunction() = default;
ResponseAction PasswordsPrivateGetWeakCredentialsFunction::Run() {
return RespondNow(
ArgumentList(api::passwords_private::GetWeakCredentials::Results::Create(
GetDelegate(browser_context())->GetWeakCredentials())));
}
// PasswordsPrivateGetPlaintextInsecurePasswordFunction: // PasswordsPrivateGetPlaintextInsecurePasswordFunction:
PasswordsPrivateGetPlaintextInsecurePasswordFunction:: PasswordsPrivateGetPlaintextInsecurePasswordFunction::
~PasswordsPrivateGetPlaintextInsecurePasswordFunction() = default; ~PasswordsPrivateGetPlaintextInsecurePasswordFunction() = default;
......
...@@ -259,6 +259,18 @@ class PasswordsPrivateGetCompromisedCredentialsFunction ...@@ -259,6 +259,18 @@ class PasswordsPrivateGetCompromisedCredentialsFunction
ResponseAction Run() override; ResponseAction Run() override;
}; };
class PasswordsPrivateGetWeakCredentialsFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("passwordsPrivate.getWeakCredentials",
PASSWORDSPRIVATE_GETWEAKCREDENTIALS)
protected:
~PasswordsPrivateGetWeakCredentialsFunction() override;
// ExtensionFunction overrides.
ResponseAction Run() override;
};
class PasswordsPrivateGetPlaintextInsecurePasswordFunction class PasswordsPrivateGetPlaintextInsecurePasswordFunction
: public ExtensionFunction { : public ExtensionFunction {
public: public:
......
...@@ -219,6 +219,10 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, GetCompromisedCredentials) { ...@@ -219,6 +219,10 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, GetCompromisedCredentials) {
EXPECT_TRUE(RunPasswordsSubtest("getCompromisedCredentials")) << message_; EXPECT_TRUE(RunPasswordsSubtest("getCompromisedCredentials")) << message_;
} }
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, GetWeakCredentials) {
EXPECT_TRUE(RunPasswordsSubtest("getWeakCredentials")) << message_;
}
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, GetPlaintextInsecurePassword) { IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, GetPlaintextInsecurePassword) {
EXPECT_TRUE(RunPasswordsSubtest("getPlaintextInsecurePassword")) << message_; EXPECT_TRUE(RunPasswordsSubtest("getPlaintextInsecurePassword")) << message_;
} }
......
...@@ -131,6 +131,10 @@ class PasswordsPrivateDelegate : public KeyedService { ...@@ -131,6 +131,10 @@ class PasswordsPrivateDelegate : public KeyedService {
virtual std::vector<api::passwords_private::InsecureCredential> virtual std::vector<api::passwords_private::InsecureCredential>
GetCompromisedCredentials() = 0; GetCompromisedCredentials() = 0;
// Obtains information about weak credentials.
virtual std::vector<api::passwords_private::InsecureCredential>
GetWeakCredentials() = 0;
// Requests the plaintext password for |credential| due to |reason|. If // Requests the plaintext password for |credential| due to |reason|. If
// successful, |callback| gets invoked with the same |credential|, whose // successful, |callback| gets invoked with the same |credential|, whose
// |password| field will be set. // |password| field will be set.
......
...@@ -478,6 +478,11 @@ PasswordsPrivateDelegateImpl::GetCompromisedCredentials() { ...@@ -478,6 +478,11 @@ PasswordsPrivateDelegateImpl::GetCompromisedCredentials() {
return password_check_delegate_.GetCompromisedCredentials(); return password_check_delegate_.GetCompromisedCredentials();
} }
std::vector<api::passwords_private::InsecureCredential>
PasswordsPrivateDelegateImpl::GetWeakCredentials() {
return password_check_delegate_.GetWeakCredentials();
}
void PasswordsPrivateDelegateImpl::GetPlaintextInsecurePassword( void PasswordsPrivateDelegateImpl::GetPlaintextInsecurePassword(
api::passwords_private::InsecureCredential credential, api::passwords_private::InsecureCredential credential,
api::passwords_private::PlaintextReason reason, api::passwords_private::PlaintextReason reason,
......
...@@ -72,6 +72,8 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate, ...@@ -72,6 +72,8 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
content::WebContents* web_contents) override; content::WebContents* web_contents) override;
std::vector<api::passwords_private::InsecureCredential> std::vector<api::passwords_private::InsecureCredential>
GetCompromisedCredentials() override; GetCompromisedCredentials() override;
std::vector<api::passwords_private::InsecureCredential> GetWeakCredentials()
override;
void GetPlaintextInsecurePassword( void GetPlaintextInsecurePassword(
api::passwords_private::InsecureCredential credential, api::passwords_private::InsecureCredential credential,
api::passwords_private::PlaintextReason reason, api::passwords_private::PlaintextReason reason,
......
...@@ -107,6 +107,16 @@ void PasswordsPrivateEventRouter::OnCompromisedCredentialsChanged( ...@@ -107,6 +107,16 @@ void PasswordsPrivateEventRouter::OnCompromisedCredentialsChanged(
event_router_->BroadcastEvent(std::move(extension_event)); event_router_->BroadcastEvent(std::move(extension_event));
} }
void PasswordsPrivateEventRouter::OnWeakCredentialsChanged(
std::vector<api::passwords_private::InsecureCredential> weak_credentials) {
auto extension_event = std::make_unique<Event>(
events::PASSWORDS_PRIVATE_ON_WEAK_CREDENTIALS_CHANGED,
api::passwords_private::OnWeakCredentialsChanged::kEventName,
api::passwords_private::OnWeakCredentialsChanged::Create(
weak_credentials));
event_router_->BroadcastEvent(std::move(extension_event));
}
void PasswordsPrivateEventRouter::OnPasswordCheckStatusChanged( void PasswordsPrivateEventRouter::OnPasswordCheckStatusChanged(
const api::passwords_private::PasswordCheckStatus& status) { const api::passwords_private::PasswordCheckStatus& status) {
auto extension_event = std::make_unique<Event>( auto extension_event = std::make_unique<Event>(
......
...@@ -63,6 +63,11 @@ class PasswordsPrivateEventRouter : public KeyedService { ...@@ -63,6 +63,11 @@ class PasswordsPrivateEventRouter : public KeyedService {
std::vector<api::passwords_private::InsecureCredential> std::vector<api::passwords_private::InsecureCredential>
compromised_credentials); compromised_credentials);
// Notifies listeners about a change to the information about weak
// credentials.
void OnWeakCredentialsChanged(
std::vector<api::passwords_private::InsecureCredential> weak_credentials);
// Notifies listeners about a change to the status of the password check. // Notifies listeners about a change to the status of the password check.
void OnPasswordCheckStatusChanged( void OnPasswordCheckStatusChanged(
const api::passwords_private::PasswordCheckStatus& status); const api::passwords_private::PasswordCheckStatus& status);
......
...@@ -202,6 +202,20 @@ TestPasswordsPrivateDelegate::GetCompromisedCredentials() { ...@@ -202,6 +202,20 @@ TestPasswordsPrivateDelegate::GetCompromisedCredentials() {
return credentials; return credentials;
} }
std::vector<api::passwords_private::InsecureCredential>
TestPasswordsPrivateDelegate::GetWeakCredentials() {
api::passwords_private::InsecureCredential credential;
credential.username = "bob";
credential.formatted_origin = "example.com";
credential.detailed_origin = "https://example.com";
credential.is_android_credential = false;
credential.change_password_url =
std::make_unique<std::string>("https://example.com/change-password");
std::vector<api::passwords_private::InsecureCredential> credentials;
credentials.push_back(std::move(credential));
return credentials;
}
void TestPasswordsPrivateDelegate::GetPlaintextInsecurePassword( void TestPasswordsPrivateDelegate::GetPlaintextInsecurePassword(
api::passwords_private::InsecureCredential credential, api::passwords_private::InsecureCredential credential,
api::passwords_private::PlaintextReason reason, api::passwords_private::PlaintextReason reason,
......
...@@ -49,6 +49,8 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate { ...@@ -49,6 +49,8 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
content::WebContents* web_contents) override; content::WebContents* web_contents) override;
std::vector<api::passwords_private::InsecureCredential> std::vector<api::passwords_private::InsecureCredential>
GetCompromisedCredentials() override; GetCompromisedCredentials() override;
std::vector<api::passwords_private::InsecureCredential> GetWeakCredentials()
override;
void GetPlaintextInsecurePassword( void GetPlaintextInsecurePassword(
api::passwords_private::InsecureCredential credential, api::passwords_private::InsecureCredential credential,
api::passwords_private::PlaintextReason reason, api::passwords_private::PlaintextReason reason,
......
...@@ -300,6 +300,9 @@ namespace passwordsPrivate { ...@@ -300,6 +300,9 @@ namespace passwordsPrivate {
// Requests the latest compromised credentials. // Requests the latest compromised credentials.
static void getCompromisedCredentials(InsecureCredentialsCallback callback); static void getCompromisedCredentials(InsecureCredentialsCallback callback);
// Requests the latest weak credentials.
static void getWeakCredentials(InsecureCredentialsCallback callback);
// Requests the plaintext password for |credential|. |callback| gets invoked // Requests the plaintext password for |credential|. |callback| gets invoked
// with the same |credential|, whose |password| field will be set. // with the same |credential|, whose |password| field will be set.
// |credential|: The insecure credential whose password is being retrieved. // |credential|: The insecure credential whose password is being retrieved.
...@@ -357,6 +360,10 @@ namespace passwordsPrivate { ...@@ -357,6 +360,10 @@ namespace passwordsPrivate {
static void onCompromisedCredentialsChanged( static void onCompromisedCredentialsChanged(
InsecureCredential[] compromisedCredentials); InsecureCredential[] compromisedCredentials);
// Fired when the weak credentials changed.
// |weakCredentials|: The updated weak credentials.
static void onWeakCredentialsChanged(InsecureCredential[] weakCredentials);
// Fired when the status of the password check changes. // Fired when the status of the password check changes.
// |status|: The updated status of the password check. // |status|: The updated status of the password check.
static void onPasswordCheckStatusChanged(PasswordCheckStatus status); static void onPasswordCheckStatusChanged(PasswordCheckStatus status);
......
...@@ -327,6 +327,22 @@ var availableTests = [ ...@@ -327,6 +327,22 @@ var availableTests = [
}); });
}, },
function getWeakCredentials() {
chrome.passwordsPrivate.getWeakCredentials(weakCredentials => {
chrome.test.assertEq(1, weakCredentials.length);
var weakredential = weakCredentials[0];
chrome.test.assertEq('example.com', weakredential.formattedOrigin);
chrome.test.assertEq('https://example.com', weakredential.detailedOrigin);
chrome.test.assertFalse(weakredential.isAndroidCredential);
chrome.test.assertEq(
'https://example.com/change-password',
weakredential.changePasswordUrl);
chrome.test.assertEq('bob', weakredential.username);
chrome.test.succeed();
});
},
function getPlaintextInsecurePassword() { function getPlaintextInsecurePassword() {
var compromisedCredential = { var compromisedCredential = {
id: 0, id: 0,
......
...@@ -370,10 +370,8 @@ void InsecureCredentialsManager::NotifyCompromisedCredentialsChanged() { ...@@ -370,10 +370,8 @@ void InsecureCredentialsManager::NotifyCompromisedCredentialsChanged() {
} }
void InsecureCredentialsManager::NotifyWeakCredentialsChanged() { void InsecureCredentialsManager::NotifyWeakCredentialsChanged() {
std::vector<CredentialWithPassword> weak_credentials =
ExtractInsecureCredentials(credentials_to_forms_, &IsWeak);
for (auto& observer : observers_) { for (auto& observer : observers_) {
observer.OnWeakCredentialsChanged(weak_credentials); observer.OnWeakCredentialsChanged();
} }
} }
......
...@@ -150,7 +150,7 @@ class InsecureCredentialsManager ...@@ -150,7 +150,7 @@ class InsecureCredentialsManager
public: public:
virtual void OnCompromisedCredentialsChanged( virtual void OnCompromisedCredentialsChanged(
CredentialsView credentials) = 0; CredentialsView credentials) = 0;
virtual void OnWeakCredentialsChanged(CredentialsView credentials) {} virtual void OnWeakCredentialsChanged() {}
}; };
InsecureCredentialsManager( InsecureCredentialsManager(
......
...@@ -45,6 +45,7 @@ struct MockInsecureCredentialsManagerObserver ...@@ -45,6 +45,7 @@ struct MockInsecureCredentialsManagerObserver
OnCompromisedCredentialsChanged, OnCompromisedCredentialsChanged,
(InsecureCredentialsManager::CredentialsView), (InsecureCredentialsManager::CredentialsView),
(override)); (override));
MOCK_METHOD(void, OnWeakCredentialsChanged, (), (override));
}; };
using StrictMockInsecureCredentialsManagerObserver = using StrictMockInsecureCredentialsManagerObserver =
...@@ -247,23 +248,27 @@ TEST_F(InsecureCredentialsManagerTest, ...@@ -247,23 +248,27 @@ TEST_F(InsecureCredentialsManagerTest,
// Adding a saved password should notify observers. // Adding a saved password should notify observers.
EXPECT_CALL(observer, OnCompromisedCredentialsChanged); EXPECT_CALL(observer, OnCompromisedCredentialsChanged);
EXPECT_CALL(observer, OnWeakCredentialsChanged);
store().AddLogin(saved_password); store().AddLogin(saved_password);
RunUntilIdle(); RunUntilIdle();
// Updating a saved password should notify observers. // Updating a saved password should notify observers.
saved_password.password_value = base::ASCIIToUTF16(kPassword2); saved_password.password_value = base::ASCIIToUTF16(kPassword2);
EXPECT_CALL(observer, OnCompromisedCredentialsChanged); EXPECT_CALL(observer, OnCompromisedCredentialsChanged);
EXPECT_CALL(observer, OnWeakCredentialsChanged);
store().UpdateLogin(saved_password); store().UpdateLogin(saved_password);
RunUntilIdle(); RunUntilIdle();
// Removing a saved password should notify observers. // Removing a saved password should notify observers.
EXPECT_CALL(observer, OnCompromisedCredentialsChanged); EXPECT_CALL(observer, OnCompromisedCredentialsChanged);
EXPECT_CALL(observer, OnWeakCredentialsChanged);
store().RemoveLogin(saved_password); store().RemoveLogin(saved_password);
RunUntilIdle(); RunUntilIdle();
// After an observer is removed it should no longer receive notifications. // After an observer is removed it should no longer receive notifications.
provider().RemoveObserver(&observer); provider().RemoveObserver(&observer);
EXPECT_CALL(observer, OnCompromisedCredentialsChanged).Times(0); EXPECT_CALL(observer, OnCompromisedCredentialsChanged).Times(0);
EXPECT_CALL(observer, OnWeakCredentialsChanged).Times(0);
store().AddLogin(saved_password); store().AddLogin(saved_password);
RunUntilIdle(); RunUntilIdle();
} }
......
...@@ -482,6 +482,7 @@ enum HistogramValue { ...@@ -482,6 +482,7 @@ enum HistogramValue {
CERTIFICATEPROVIDER_ON_SIGNATURE_REQUESTED = 460, CERTIFICATEPROVIDER_ON_SIGNATURE_REQUESTED = 460,
WINDOWS_ON_BOUNDS_CHANGED = 461, WINDOWS_ON_BOUNDS_CHANGED = 461,
WALLPAPER_PRIVATE_ON_CLOSE_PREVIEW_WALLPAPER = 462, WALLPAPER_PRIVATE_ON_CLOSE_PREVIEW_WALLPAPER = 462,
PASSWORDS_PRIVATE_ON_WEAK_CREDENTIALS_CHANGED = 463,
// Last entry: Add new entries above, then run: // Last entry: Add new entries above, then run:
// python tools/metrics/histograms/update_extension_histograms.py // python tools/metrics/histograms/update_extension_histograms.py
ENUM_BOUNDARY ENUM_BOUNDARY
......
...@@ -1569,6 +1569,7 @@ enum HistogramValue { ...@@ -1569,6 +1569,7 @@ enum HistogramValue {
AUTOTESTPRIVATE_LAUNCHSYSTEMWEBAPP = 1506, AUTOTESTPRIVATE_LAUNCHSYSTEMWEBAPP = 1506,
ACCESSIBILITY_PRIVATE_PERFORMACCELERATORACTION = 1507, ACCESSIBILITY_PRIVATE_PERFORMACCELERATORACTION = 1507,
DECLARATIVENETREQUEST_ISREGEXSUPPORTED = 1508, DECLARATIVENETREQUEST_ISREGEXSUPPORTED = 1508,
PASSWORDSPRIVATE_GETWEAKCREDENTIALS = 1509,
// Last entry: Add new entries above, then run: // Last entry: Add new entries above, then run:
// python tools/metrics/histograms/update_extension_histograms.py // python tools/metrics/histograms/update_extension_histograms.py
ENUM_BOUNDARY ENUM_BOUNDARY
......
...@@ -273,6 +273,13 @@ chrome.passwordsPrivate.optInForAccountStorage = function(optIn) {}; ...@@ -273,6 +273,13 @@ chrome.passwordsPrivate.optInForAccountStorage = function(optIn) {};
*/ */
chrome.passwordsPrivate.getCompromisedCredentials = function(callback) {}; chrome.passwordsPrivate.getCompromisedCredentials = function(callback) {};
/**
* Requests the latest weak credentials.
* @param {function(!Array<!chrome.passwordsPrivate.InsecureCredential>): void}
* callback
*/
chrome.passwordsPrivate.getWeakCredentials = function(callback) {};
/** /**
* Requests the plaintext password for |credential|. |callback| gets invoked * Requests the plaintext password for |credential|. |callback| gets invoked
* with the same |credential|, whose |password| field will be set. * with the same |credential|, whose |password| field will be set.
...@@ -358,6 +365,12 @@ chrome.passwordsPrivate.onAccountStorageOptInStateChanged; ...@@ -358,6 +365,12 @@ chrome.passwordsPrivate.onAccountStorageOptInStateChanged;
*/ */
chrome.passwordsPrivate.onCompromisedCredentialsChanged; chrome.passwordsPrivate.onCompromisedCredentialsChanged;
/**
* Fired when the weak credentials changed.
* @type {!ChromeEvent}
*/
chrome.passwordsPrivate.onWeakCredentialsChanged;
/** /**
* Fired when the status of the password check changes. * Fired when the status of the password check changes.
* @type {!ChromeEvent} * @type {!ChromeEvent}
......
...@@ -22989,6 +22989,7 @@ Called by update_extension_histograms.py.--> ...@@ -22989,6 +22989,7 @@ Called by update_extension_histograms.py.-->
<int value="460" label="CERTIFICATEPROVIDER_ON_SIGNATURE_REQUESTED"/> <int value="460" label="CERTIFICATEPROVIDER_ON_SIGNATURE_REQUESTED"/>
<int value="461" label="WINDOWS_ON_BOUNDS_CHANGED"/> <int value="461" label="WINDOWS_ON_BOUNDS_CHANGED"/>
<int value="462" label="WALLPAPER_PRIVATE_ON_CLOSE_PREVIEW_WALLPAPER"/> <int value="462" label="WALLPAPER_PRIVATE_ON_CLOSE_PREVIEW_WALLPAPER"/>
<int value="463" label="PASSWORDS_PRIVATE_ON_WEAK_CREDENTIALS_CHANGED"/>
</enum> </enum>
<enum name="ExtensionFileWriteResult"> <enum name="ExtensionFileWriteResult">
...@@ -24570,6 +24571,7 @@ Called by update_extension_histograms.py.--> ...@@ -24570,6 +24571,7 @@ Called by update_extension_histograms.py.-->
<int value="1506" label="AUTOTESTPRIVATE_LAUNCHSYSTEMWEBAPP"/> <int value="1506" label="AUTOTESTPRIVATE_LAUNCHSYSTEMWEBAPP"/>
<int value="1507" label="ACCESSIBILITY_PRIVATE_PERFORMACCELERATORACTION"/> <int value="1507" label="ACCESSIBILITY_PRIVATE_PERFORMACCELERATORACTION"/>
<int value="1508" label="DECLARATIVENETREQUEST_ISREGEXSUPPORTED"/> <int value="1508" label="DECLARATIVENETREQUEST_ISREGEXSUPPORTED"/>
<int value="1509" label="PASSWORDSPRIVATE_GETWEAKCREDENTIALS"/>
</enum> </enum>
<enum name="ExtensionIconState"> <enum name="ExtensionIconState">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment