| 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 e1fee32d2f5026223f4f6b335123d8e0fe6c17c4..846cca42e1a08d2bbe67e2ab54c421b49f8fe2e4 100644
|
| --- a/components/password_manager/core/browser/password_form_manager.cc
|
| +++ b/components/password_manager/core/browser/password_form_manager.cc
|
| @@ -418,108 +418,50 @@ void PasswordFormManager::OnRequestDone(
|
| }
|
| }
|
| logins_result.erase(begin_blacklisted, logins_result.end());
|
| + if (logins_result.empty())
|
| + return;
|
|
|
| // Now compute scores for the remaining credentials in |login_result|.
|
| std::vector<uint32_t> credential_scores;
|
| credential_scores.reserve(logins_result.size());
|
| uint32_t best_score = 0;
|
| + std::map<base::string16, uint32_t> best_scores;
|
| for (const PasswordForm* login : logins_result) {
|
| uint32_t current_score = ScoreResult(*login);
|
| - if (current_score > best_score)
|
| - best_score = current_score;
|
| + best_score = std::max(best_score, current_score);
|
| + best_scores[login->username_value] =
|
| + std::max(best_scores[login->username_value], current_score);
|
| credential_scores.push_back(current_score);
|
| }
|
|
|
| - if (best_score == 0) {
|
| - if (logger) {
|
| - logger->LogNumber(Logger::STRING_BEST_SCORE,
|
| - static_cast<size_t>(best_score));
|
| - }
|
| - return;
|
| - }
|
| -
|
| - // Start the |best_matches_| with the best-scoring normal credentials and save
|
| - // the worse-scoring "protected" ones for later.
|
| - ScopedVector<PasswordForm> protected_credentials;
|
| + // Fill |best_matches_| with the best-scoring credentials for each username.
|
| for (size_t i = 0; i < logins_result.size(); ++i) {
|
| // Take ownership of the PasswordForm from the ScopedVector.
|
| scoped_ptr<PasswordForm> login(logins_result[i]);
|
| logins_result[i] = nullptr;
|
| DCHECK(!login->blacklisted_by_user);
|
| + const base::string16& username = login->username_value;
|
|
|
| - if (credential_scores[i] < best_score) {
|
| - // Empty path matches are most commonly imports from Firefox, and
|
| - // generally useful to autofill. Blacklisted entries are only meaningful
|
| - // in the absence of non-blacklisted entries, in which case they need no
|
| - // protection to become |best_matches_|. TODO(timsteele): Bug 1269400. We
|
| - // probably should do something more elegant for any shorter-path match
|
| - // instead of explicitly handling empty path matches.
|
| - bool is_credential_protected =
|
| - observed_form_.scheme == PasswordForm::SCHEME_HTML &&
|
| - base::StartsWith("/", login->origin.path(),
|
| - base::CompareCase::SENSITIVE) &&
|
| - credential_scores[i] > 0;
|
| - // Passwords generated on a signup form must show on a login form even if
|
| - // there are better-matching saved credentials. TODO(gcasto): We don't
|
| - // want to cut credentials that were saved on signup forms even if they
|
| - // weren't generated, but currently it's hard to distinguish between those
|
| - // forms and two different login forms on the same domain. Filed
|
| - // http://crbug.com/294468 to look into this.
|
| - is_credential_protected |= login->type == PasswordForm::TYPE_GENERATED;
|
| -
|
| - // Websites that participate in affiliation-based matching will normally
|
| - // have a single authentication system per domain, therefore affiliation
|
| - // based matches are desired to be offered on any login form on the site.
|
| - // However, for Android credentials, most meta-data attributes are empty,
|
| - // so they will have a very low score, hence need to be protected against
|
| - // the high-scoring logins saved from the website.
|
| - is_credential_protected |= IsValidAndroidFacetURI(login->signon_realm);
|
| -
|
| - if (is_credential_protected)
|
| - protected_credentials.push_back(std::move(login));
|
| - else
|
| - not_best_matches_.push_back(std::move(login));
|
| + if (credential_scores[i] < best_scores[username]) {
|
| + not_best_matches_.push_back(std::move(login));
|
| continue;
|
| }
|
|
|
| + if (!preferred_match_ && credential_scores[i] == best_score)
|
| + preferred_match_ = login.get();
|
| +
|
| // If there is another best-score match for the same username then leave it
|
| // and add the current form to |not_best_matches_|.
|
| - const base::string16& username = login->username_value;
|
| auto best_match_username = best_matches_.find(username);
|
| if (best_match_username == best_matches_.end()) {
|
| - if (login->preferred)
|
| - preferred_match_ = login.get();
|
| best_matches_.insert(std::make_pair(username, std::move(login)));
|
| } else {
|
| not_best_matches_.push_back(std::move(login));
|
| }
|
| }
|
|
|
| - // Add the protected results if we don't already have a result with the same
|
| - // username.
|
| - for (ScopedVector<PasswordForm>::iterator it = protected_credentials.begin();
|
| - it != protected_credentials.end(); ++it) {
|
| - // Take ownership of the PasswordForm from the ScopedVector.
|
| - scoped_ptr<PasswordForm> protege(*it);
|
| - *it = nullptr;
|
| - const base::string16& username = protege->username_value;
|
| - if (best_matches_.find(username) == best_matches_.end())
|
| - best_matches_.insert(std::make_pair(username, std::move(protege)));
|
| - else
|
| - not_best_matches_.push_back(std::move(protege));
|
| - }
|
| -
|
| UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsNotShown",
|
| logins_result_size - best_matches_.size());
|
| -
|
| - if (!best_matches_.empty()) {
|
| - // It is possible we have at least one match but have no preferred_match_,
|
| - // because a user may have chosen to 'Forget' the preferred match. So we
|
| - // just pick the first one and whichever the user selects for submit will
|
| - // be saved as preferred.
|
| - if (!preferred_match_)
|
| - preferred_match_ = best_matches_.begin()->second.get();
|
| - }
|
| }
|
|
|
| void PasswordFormManager::ProcessFrame(
|
| @@ -686,7 +628,7 @@ void PasswordFormManager::UpdatePreferredLoginState(
|
| PasswordFormMap::const_iterator iter;
|
| for (iter = best_matches_.begin(); iter != best_matches_.end(); iter++) {
|
| if (iter->second->username_value != pending_credentials_.username_value &&
|
| - iter->second->preferred) {
|
| + iter->second->preferred && !iter->second->is_public_suffix_match) {
|
| // This wasn't the selected login but it used to be preferred.
|
| iter->second->preferred = false;
|
| if (user_action_ == kUserActionNone)
|
| @@ -1146,8 +1088,12 @@ uint32_t PasswordFormManager::ScoreResult(const PasswordForm& candidate) const {
|
|
|
| uint32_t score = 0u;
|
| if (!candidate.is_public_suffix_match) {
|
| - score += 1u << 7;
|
| + score += 1u << 8;
|
| }
|
| +
|
| + if (candidate.preferred)
|
| + score += 1u << 7;
|
| +
|
| if (candidate.origin == observed_form_.origin) {
|
| // This check is here for the most common case which
|
| // is we have a single match in the db for the given host,
|
|
|