Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(437)

Unified Diff: components/password_manager/core/browser/password_form_manager.cc

Issue 2252283005: Introduce password_manager::FormFetcher (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@621355_const_best_matches
Patch Set: Keep updating PasswordStore for blacklisting Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/password_manager/core/browser/password_form_manager.cc
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index e7a1ccda88dbcb6391debcf9860a3e91a33f78f6..d1f35e2b919dfc50bf189b55899d35c27e75c08a 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -10,10 +10,8 @@
#include <map>
#include <utility>
-#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
-#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/string16.h"
@@ -24,11 +22,9 @@
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/proto/server.pb.h"
#include "components/autofill/core/browser/validation.h"
-#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/affiliation_utils.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
-#include "components/password_manager/core/browser/credentials_filter.h"
#include "components/password_manager/core/browser/form_saver.h"
#include "components/password_manager/core/browser/log_manager.h"
#include "components/password_manager/core/browser/password_manager.h"
@@ -90,23 +86,6 @@ bool IsProbablyNotUsername(const base::string16& s) {
return !s.empty() && DoesStringContainOnlyDigits(s) && s.size() < 3;
}
-// Splits federated matches from |store_results| into a separate vector and
-// returns that.
-std::vector<std::unique_ptr<PasswordForm>> SplitFederatedMatches(
- std::vector<std::unique_ptr<PasswordForm>>* store_results) {
- auto first_federated =
- std::partition(store_results->begin(), store_results->end(),
- [](const std::unique_ptr<PasswordForm>& form) {
- return form->federation_origin.unique();
- });
-
- std::vector<std::unique_ptr<PasswordForm>> federated_matches(
- store_results->end() - first_federated);
- std::move(first_federated, store_results->end(), federated_matches.begin());
- store_results->erase(first_federated, store_results->end());
- return federated_matches;
-}
-
bool ShouldShowInitialPasswordAccountSuggestions() {
return base::FeatureList::IsEnabled(
password_manager::features::kFillOnAccountSelect);
@@ -198,19 +177,21 @@ PasswordFormManager::PasswordFormManager(
is_ignorable_change_password_form_(false),
is_possible_change_password_form_without_username_(
observed_form.IsPossibleChangePasswordFormWithoutUsername()),
- state_(State::NOT_WAITING),
client_(client),
manager_action_(kManagerActionNone),
user_action_(kUserActionNone),
submit_result_(kSubmitResultNotSubmitted),
form_type_(kFormTypeUnspecified),
need_to_refetch_(false),
- form_saver_(std::move(form_saver)) {
+ form_saver_(std::move(form_saver)),
+ form_fetcher_impl_(client),
+ form_fetcher_(&form_fetcher_impl_) {
DCHECK_EQ(observed_form.scheme == PasswordForm::SCHEME_HTML,
driver != nullptr);
if (driver)
drivers_.push_back(driver);
FetchDataFromPasswordStore();
+ form_fetcher_->AddConsumer(this);
}
PasswordFormManager::~PasswordFormManager() {
@@ -302,22 +283,23 @@ PasswordFormManager::MatchResultMask PasswordFormManager::DoesManage(
}
bool PasswordFormManager::IsBlacklisted() const {
- DCHECK_EQ(State::NOT_WAITING, state_);
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
return !blacklisted_matches_.empty();
}
void PasswordFormManager::PermanentlyBlacklist() {
- DCHECK_EQ(State::NOT_WAITING, state_);
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
DCHECK(!client_->IsOffTheRecord());
- blacklisted_matches_owned_.push_back(
- base::MakeUnique<PasswordForm>(observed_form_));
- blacklisted_matches_.push_back(blacklisted_matches_owned_.back().get());
- form_saver_->PermanentlyBlacklist(blacklisted_matches_owned_.back().get());
+ if (!new_blacklisted_) {
+ new_blacklisted_ = base::MakeUnique<PasswordForm>(observed_form_);
+ blacklisted_matches_.push_back(new_blacklisted_.get());
+ }
+ form_saver_->PermanentlyBlacklist(new_blacklisted_.get());
}
bool PasswordFormManager::IsNewLogin() const {
- DCHECK_EQ(State::NOT_WAITING, state_);
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
return is_new_login_;
}
@@ -348,7 +330,7 @@ void PasswordFormManager::ProvisionallySave(
}
void PasswordFormManager::Save() {
- DCHECK_EQ(State::NOT_WAITING, state_);
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
DCHECK(!client_->IsOffTheRecord());
if ((user_action_ == kUserActionNone) &&
@@ -405,7 +387,7 @@ void PasswordFormManager::Update(
}
void PasswordFormManager::FetchDataFromPasswordStore() {
- if (state_ == State::WAITING) {
+ if (form_fetcher_->GetState() == FormFetcher::State::WAITING) {
// There is currently a password store query in progress, need to re-fetch
// store results later.
need_to_refetch_ = true;
@@ -418,11 +400,11 @@ void PasswordFormManager::FetchDataFromPasswordStore() {
new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
logger->LogMessage(Logger::STRING_FETCH_LOGINS_METHOD);
logger->LogNumber(Logger::STRING_FORM_MANAGER_STATE,
- static_cast<int>(state_));
+ static_cast<int>(form_fetcher_->GetState()));
}
provisionally_saved_form_.reset();
- state_ = State::WAITING;
+ form_fetcher_impl_.set_state(FormFetcher::State::WAITING);
PasswordStore* password_store = client_->GetPasswordStore();
if (!password_store) {
@@ -444,7 +426,7 @@ void PasswordFormManager::FetchDataFromPasswordStore() {
}
bool PasswordFormManager::HasCompletedMatching() const {
- return state_ == State::NOT_WAITING;
+ return form_fetcher_->GetState() == FormFetcher::State::NOT_WAITING;
}
void PasswordFormManager::SetSubmittedForm(const autofill::PasswordForm& form) {
@@ -480,92 +462,102 @@ void PasswordFormManager::SetSubmittedForm(const autofill::PasswordForm& form) {
}
}
-void PasswordFormManager::OnRequestDone(
- std::vector<std::unique_ptr<PasswordForm>> logins_result) {
+void PasswordFormManager::ProcessMatches(
+ const std::vector<const PasswordForm*>& non_federated,
+ size_t filtered_count) {
preferred_match_ = nullptr;
best_matches_.clear();
- best_matches_owned_.clear();
not_best_matches_.clear();
- not_best_matches_owned_.clear();
blacklisted_matches_.clear();
- blacklisted_matches_owned_.clear();
- const size_t logins_result_size = logins_result.size();
+ new_blacklisted_.reset();
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
logger.reset(
new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
- logger->LogMessage(Logger::STRING_ON_REQUEST_DONE_METHOD);
+ logger->LogMessage(Logger::STRING_PROCESS_MATCHES_METHOD);
}
- // Remove credentials which need to be ignored from |logins_result|.
- logins_result =
- client_->GetStoreResultFilter()->FilterResults(std::move(logins_result));
-
- // Deal with blacklisted forms.
- auto begin_blacklisted =
- std::partition(logins_result.begin(), logins_result.end(),
- [](const std::unique_ptr<PasswordForm>& form) {
- return !form->blacklisted_by_user;
- });
- for (auto it = begin_blacklisted; it != logins_result.end(); ++it) {
- if (IsBlacklistMatch(**it)) {
- blacklisted_matches_.push_back(it->get());
- blacklisted_matches_owned_.push_back(std::move(*it));
- }
- }
- logins_result.erase(begin_blacklisted, logins_result.end());
- if (logins_result.empty())
- return;
+ // Create a copy of |non_federated| which we can reorder and prune.
+ std::vector<const PasswordForm*> all_matches(non_federated);
+
+ // The next step is to reorder |all_matches| into three consequent blocks:
+ // (A) relevant blacklist entries
+ // (B) non-relevant blacklist entries
+ // (C) non-blacklisted matches
+
+ auto begin_nonblacklisted = // start of block (C)
+ std::partition(
+ all_matches.begin(), all_matches.end(),
+ [](const PasswordForm* form) { return form->blacklisted_by_user; });
- // Now compute scores for the remaining credentials in |login_result|.
- std::vector<uint32_t> credential_scores;
- credential_scores.reserve(logins_result.size());
+ auto begin_nonrelevant = // start of block (B)
+ std::partition(
+ all_matches.begin(), begin_nonblacklisted,
+ [this](const PasswordForm* form) { return IsBlacklistMatch(*form); });
+
+ // Now compute scores for forms in block (C).
+ const size_t non_blacklist_count = all_matches.end() - begin_nonblacklisted;
+ std::vector<uint32_t> credential_scores; // scores for forms from (C)
+ credential_scores.reserve(non_blacklist_count);
uint32_t best_score = 0;
- std::map<base::string16, uint32_t> best_scores;
- for (const auto& login : logins_result) {
- uint32_t current_score = ScoreResult(*login);
+ std::map<base::string16, uint32_t> best_scores; // best scores for usernames
+ for (auto it = begin_nonblacklisted; it != all_matches.end(); ++it) {
+ const PasswordForm& login = **it;
+ uint32_t current_score = ScoreResult(login);
best_score = std::max(best_score, current_score);
- best_scores[login->username_value] =
- std::max(best_scores[login->username_value], current_score);
+ best_scores[login.username_value] =
+ std::max(best_scores[login.username_value], current_score);
credential_scores.push_back(current_score);
}
+ not_best_matches_.reserve(non_blacklist_count - best_scores.size());
// Fill |best_matches_| with the best-scoring credentials for each username.
- for (size_t i = 0; i < logins_result.size(); ++i) {
- auto login = std::move(logins_result[i]);
+ for (size_t i = 0; i < non_blacklist_count; ++i) {
+ const PasswordForm* login = *(begin_nonblacklisted + i);
DCHECK(!login->blacklisted_by_user);
const base::string16& username = login->username_value;
if (credential_scores[i] < best_scores[username]) {
- not_best_matches_.push_back(login.get());
- not_best_matches_owned_.push_back(std::move(login));
+ not_best_matches_.push_back(login);
continue;
}
if (!preferred_match_ && credential_scores[i] == best_score)
- preferred_match_ = login.get();
+ preferred_match_ = login;
// If there is another best-score match for the same username then leave it
// and add the current form to |not_best_matches_|.
auto best_match_username = best_matches_.find(username);
if (best_match_username == best_matches_.end()) {
- best_matches_.insert(std::make_pair(username, login.get()));
- best_matches_owned_.push_back(std::move(login));
+ best_matches_.insert(std::make_pair(username, login));
} else {
- not_best_matches_.push_back(login.get());
- not_best_matches_owned_.push_back(std::move(login));
+ not_best_matches_.push_back(login);
}
}
- UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsNotShown",
- logins_result_size - best_matches_.size());
+ all_matches.erase(begin_nonrelevant, all_matches.end());
+ blacklisted_matches_ = std::move(all_matches);
+
+ UMA_HISTOGRAM_COUNTS(
+ "PasswordManager.NumPasswordsNotShown",
+ non_federated.size() + filtered_count - best_matches_.size());
+
+ // If password store was slow and provisionally saved form is already here
+ // then create pending credentials (see http://crbug.com/470322).
+ if (provisionally_saved_form_)
+ CreatePendingCredentials();
+
+ for (auto const& driver : drivers_)
+ ProcessFrameInternal(driver);
+ if (observed_form_.scheme != PasswordForm::SCHEME_HTML)
+ ProcessLoginPrompt();
}
void PasswordFormManager::ProcessFrame(
const base::WeakPtr<PasswordManagerDriver>& driver) {
DCHECK_EQ(PasswordForm::SCHEME_HTML, observed_form_.scheme);
- if (state_ == State::NOT_WAITING)
+ if (form_fetcher_->GetState() == FormFetcher::State::NOT_WAITING)
ProcessFrameInternal(driver);
for (auto const& old_driver : drivers_) {
@@ -622,8 +614,8 @@ void PasswordFormManager::ProcessFrameInternal(
// If fill-on-account-select is not enabled, continue with autofilling any
// password forms as traditionally has been done.
password_manager_->Autofill(driver.get(), observed_form_, best_matches_,
- federated_matches_, *preferred_match_,
- wait_for_username);
+ form_fetcher_->GetFederatedMatches(),
+ *preferred_match_, wait_for_username);
}
}
@@ -638,11 +630,11 @@ void PasswordFormManager::ProcessLoginPrompt() {
void PasswordFormManager::OnGetPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
- DCHECK_EQ(State::WAITING, state_);
+ DCHECK_EQ(FormFetcher::State::WAITING, form_fetcher_->GetState());
if (need_to_refetch_) {
// The received results are no longer up to date, need to re-request.
- state_ = State::NOT_WAITING;
+ form_fetcher_impl_.set_state(FormFetcher::State::NOT_WAITING);
FetchDataFromPasswordStore();
need_to_refetch_ = false;
return;
@@ -656,43 +648,18 @@ void PasswordFormManager::OnGetPasswordStoreResults(
logger->LogNumber(Logger::STRING_NUMBER_RESULTS, results.size());
}
- federated_matches_owned_ = SplitFederatedMatches(&results);
- federated_matches_.resize(federated_matches_owned_.size());
- std::transform(
- federated_matches_owned_.begin(), federated_matches_owned_.end(),
- federated_matches_.begin(),
- [](const std::unique_ptr<PasswordForm>& form) { return form.get(); });
-
- if (!results.empty())
- OnRequestDone(std::move(results));
- state_ = State::NOT_WAITING;
-
- // If password store was slow and provisionally saved form is already here
- // then create pending credentials (see http://crbug.com/470322).
- if (provisionally_saved_form_)
- CreatePendingCredentials();
-
- for (auto const& driver : drivers_)
- ProcessFrameInternal(driver);
- if (observed_form_.scheme != PasswordForm::SCHEME_HTML)
- ProcessLoginPrompt();
+ form_fetcher_impl_.SetResults(std::move(results));
}
void PasswordFormManager::OnGetSiteStatistics(
std::vector<std::unique_ptr<InteractionsStats>> stats) {
// On Windows the password request may be resolved after the statistics due to
// importing from IE.
- interactions_stats_owned_.swap(stats);
- interactions_stats_.resize(interactions_stats_owned_.size());
- std::transform(interactions_stats_owned_.begin(),
- interactions_stats_owned_.end(), interactions_stats_.begin(),
- [](const std::unique_ptr<InteractionsStats>& stat) {
- return stat.get();
- });
+ form_fetcher_impl_.SetStats(std::move(stats));
}
void PasswordFormManager::ProcessUpdate() {
- DCHECK_EQ(State::NOT_WAITING, state_);
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
DCHECK(preferred_match_ || !pending_credentials_.federation_origin.unique());
// If we're doing an Update, we either autofilled correctly and need to
// update the stats, or the user typed in a new password for autofilled
@@ -1133,7 +1100,6 @@ void PasswordFormManager::CreatePendingCredentials() {
}
uint32_t PasswordFormManager::ScoreResult(const PasswordForm& candidate) const {
- DCHECK_EQ(State::WAITING, state_);
DCHECK(!candidate.blacklisted_by_user);
// For scoring of candidate login data:
// The most important element that should match is the signon_realm followed
@@ -1229,9 +1195,9 @@ const PasswordForm* PasswordFormManager::FindBestMatchForUpdatePassword(
if (password.empty())
return nullptr;
- for (auto it = best_matches_.begin(); it != best_matches_.end(); ++it) {
- if (it->second->password_value == password)
- return it->second;
+ for (const auto& key_value : best_matches_) {
+ if (key_value.second->password_value == password)
+ return key_value.second;
}
return nullptr;
}

Powered by Google App Engine
This is Rietveld 408576698