15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/password_manager/core/browser/password_form_manager.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <set>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/metrics/user_metrics.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/strings/utf_string_conversions.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/autofill/core/browser/autofill_manager.h"
16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "components/autofill/core/browser/form_structure.h"
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "components/autofill/core/browser/validation.h"
1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "components/autofill/core/common/password_form.h"
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/password_manager/core/browser/password_manager.h"
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/password_manager/core/browser/password_manager_client.h"
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/password_manager/core/browser/password_manager_driver.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/password_manager/core/browser/password_store.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using autofill::FormStructure;
2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using autofill::PasswordForm;
2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using autofill::PasswordFormMap;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochnamespace password_manager {
30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
3123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)namespace {
3223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)enum PasswordGenerationSubmissionEvent {
3423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Generated password was submitted and saved.
3523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  PASSWORD_SUBMITTED,
3623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Generated password submission failed. These passwords aren't saved.
3823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  PASSWORD_SUBMISSION_FAILED,
3923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
4023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Generated password was not submitted before navigation. Currently these
4123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // passwords are not saved.
4223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  PASSWORD_NOT_SUBMITTED,
4323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
4423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Generated password was overridden by a non-generated one. This generally
4523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // signals that the user was unhappy with the generated password for some
4623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // reason.
4723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  PASSWORD_OVERRIDDEN,
4823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
4923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Number of enum entries, used for UMA histogram reporting macros.
5023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  SUBMISSION_EVENT_ENUM_COUNT
5123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)};
5223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void LogPasswordGenerationSubmissionEvent(
5423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    PasswordGenerationSubmissionEvent event) {
5523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("PasswordGeneration.SubmissionEvent",
5623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            event, SUBMISSION_EVENT_ENUM_COUNT);
5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
5823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
59116680a4aac90f2aa7413d9095a592090648e557Ben MurdochPasswordForm CopyAndModifySSLValidity(const PasswordForm& orig,
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      bool ssl_valid) {
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  PasswordForm result(orig);
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  result.ssl_valid = ssl_valid;
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return result;
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
6623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}  // namespace
6723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PasswordFormManager::PasswordFormManager(PasswordManager* password_manager,
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         PasswordManagerClient* client,
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         PasswordManagerDriver* driver,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const PasswordForm& observed_form,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         bool ssl_valid)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : best_matches_deleter_(&best_matches_),
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      observed_form_(CopyAndModifySSLValidity(observed_form, ssl_valid)),
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_new_login_(true),
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_generated_password_(false),
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password_manager_(password_manager),
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      preferred_match_(NULL),
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_(PRE_MATCHING_PHASE),
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      client_(client),
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      driver_(driver),
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      manager_action_(kManagerActionNone),
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      user_action_(kUserActionNone),
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      submit_result_(kSubmitResultNotSubmitted) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observed_form_.origin.is_valid())
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SplitString(observed_form_.origin.path(), '/', &form_path_tokens_);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PasswordFormManager::~PasswordFormManager() {
90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  UMA_HISTOGRAM_ENUMERATION(
91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      "PasswordManager.ActionsTakenV3", GetActionsTaken(), kMaxNumActionsTaken);
9223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (has_generated_password_ && submit_result_ == kSubmitResultNotSubmitted)
9323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    LogPasswordGenerationSubmissionEvent(PASSWORD_NOT_SUBMITTED);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int PasswordFormManager::GetActionsTaken() {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return user_action_ + kUserActionMax * (manager_action_ +
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kManagerActionMax * submit_result_);
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(timsteele): use a hash of some sort in the future?
102116680a4aac90f2aa7413d9095a592090648e557Ben MurdochPasswordFormManager::MatchResultMask PasswordFormManager::DoesManage(
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const PasswordForm& form) const {
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Non-HTML form case.
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (observed_form_.scheme != PasswordForm::SCHEME_HTML ||
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      form.scheme != PasswordForm::SCHEME_HTML) {
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const bool forms_match = observed_form_.signon_realm == form.signon_realm &&
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             observed_form_.scheme == form.scheme;
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return forms_match ? RESULT_COMPLETE_MATCH : RESULT_NO_MATCH;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // HTML form case.
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  MatchResultMask result = RESULT_NO_MATCH;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Easiest case of matching origins.
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool origins_match = form.origin == observed_form_.origin;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If this is a replay of the same form in the case a user entered an invalid
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // password, the origin of the new form may equal the action of the "first"
119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // form instead.
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  origins_match = origins_match || (form.origin == observed_form_.action);
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Otherwise, if action hosts are the same, the old URL scheme is HTTP while
122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // the new one is HTTPS, and the new path equals to or extends the old path,
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // we also consider the actions a match. This is to accommodate cases where
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // the original login form is on an HTTP page, but a failed login attempt
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // redirects to HTTPS (as in http://example.org -> https://example.org/auth).
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!origins_match && !observed_form_.origin.SchemeIsSecure() &&
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      form.origin.SchemeIsSecure()) {
128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::string& old_path = observed_form_.origin.path();
129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::string& new_path = form.origin.path();
130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    origins_match =
131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        observed_form_.origin.host() == form.origin.host() &&
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        observed_form_.origin.port() == form.origin.port() &&
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        StartsWithASCII(new_path, old_path, /*case_sensitive=*/true);
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (form.username_element == observed_form_.username_element &&
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      form.password_element == observed_form_.password_element &&
138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      origins_match) {
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    result |= RESULT_MANDATORY_ATTRIBUTES_MATCH;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Note: although saved password forms might actually have an empty action
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // URL if they were imported (see bug 1107719), the |form| we see here comes
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // never from the password store, and should have an exactly matching action.
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (form.action == observed_form_.action)
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    result |= RESULT_ACTION_MATCH;
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return result;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordFormManager::IsBlacklisted() {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, POST_MATCHING_PHASE);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (preferred_match_ && preferred_match_->blacklisted_by_user)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordFormManager::PermanentlyBlacklist() {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, POST_MATCHING_PHASE);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Configure the form about to be saved for blacklist status.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_credentials_.preferred = true;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_credentials_.blacklisted_by_user = true;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_credentials_.username_value.clear();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_credentials_.password_value.clear();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Retroactively forget existing matches for this form, so we NEVER prompt or
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // autofill it again.
1694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  int num_passwords_deleted = 0;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!best_matches_.empty()) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordFormMap::const_iterator iter;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PasswordStore* password_store = client_->GetPasswordStore();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!password_store) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (iter = best_matches_.begin(); iter != best_matches_.end(); ++iter) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We want to remove existing matches for this form so that the exact
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // origin match with |blackisted_by_user == true| is the only result that
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // shows up in the future for this origin URL. However, we don't want to
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // delete logins that were actually saved on a different page (hence with
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // different origin URL) and just happened to match this form because of
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the scoring algorithm. See bug 1204493.
1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (iter->second->origin == observed_form_.origin) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        password_store->RemoveLogin(*iter->second);
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        ++num_passwords_deleted;
1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedWhenBlacklisting",
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                       num_passwords_deleted);
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save the pending_credentials_ entry marked as blacklisted.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveAsNewLogin(false);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PasswordFormManager::SetUseAdditionalPasswordAuthentication(
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool use_additional_authentication) {
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pending_credentials_.use_additional_authentication =
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      use_additional_authentication;
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordFormManager::IsNewLogin() {
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, POST_MATCHING_PHASE);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_new_login_;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool PasswordFormManager::IsPendingCredentialsPublicSuffixMatch() {
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return pending_credentials_.IsPublicSuffixMatch();
211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordFormManager::SetHasGeneratedPassword() {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  has_generated_password_ = true;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordFormManager::HasGeneratedPassword() {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This check is permissive, as the user may have generated a password and
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // then edited it in the form itself. However, even in this case the user
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // has already given consent, so we treat these cases the same.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return has_generated_password_;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordFormManager::HasValidPasswordForm() {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, POST_MATCHING_PHASE);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Non-HTML password forms (primarily HTTP and FTP autentication)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // do not contain username_element and password_element values.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observed_form_.scheme != PasswordForm::SCHEME_HTML)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return !observed_form_.password_element.empty() ||
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         !observed_form_.new_password_element.empty();
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void PasswordFormManager::ProvisionallySave(
235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const PasswordForm& credentials,
236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    OtherPossibleUsernamesAction action) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, POST_MATCHING_PHASE);
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_NE(RESULT_NO_MATCH, DoesManage(credentials));
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // If this was a sign-up or change password form, we want to persist the new
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // password; if this was a login form, then the current password (which might
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // still be "new" in the sense that we see these credentials for the first
243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // time, or that the user manually entered his actual password to overwrite an
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // obsolete password we had in the store).
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::string16 password_to_save(credentials.new_password_element.empty() ?
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      credentials.password_value : credentials.new_password_value);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure the important fields stay the same as the initially observed or
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // autofilled ones, as they may have changed if the user experienced a login
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // failure.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Look for these credentials in the list containing auto-fill entries.
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PasswordFormMap::const_iterator it =
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_matches_.find(credentials.username_value);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != best_matches_.end()) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The user signed in with a login we autofilled.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_credentials_ = *it->second;
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool password_changed =
2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        pending_credentials_.password_value != password_to_save;
2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (IsPendingCredentialsPublicSuffixMatch()) {
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // If the autofilled credentials were only a PSL match, store a copy with
2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // the current origin and signon realm. This ensures that on the next
2625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // visit, a precise match is found.
2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      is_new_login_ = true;
2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      user_action_ = password_changed ? kUserActionChoosePslMatch
2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                      : kUserActionOverridePassword;
2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Normally, the copy of the PSL matched credentials, adapted for the
2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // current domain, is saved automatically without asking the user, because
2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // the copy likely represents the same account, i.e., the one for which
2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // the user already agreed to store a password.
2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      //
2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // However, if the user changes the suggested password, it might indicate
2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // that the autofilled credentials and |credentials| actually correspond
2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // to two different accounts (see http://crbug.com/385619). In that case
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // the user should be asked again before saving the password. This is
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // ensured by clearing |original_signon_realm| on |pending_credentials_|,
2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // which unmarks it as a PSL match.
2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      //
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // There is still the edge case when the autofilled credentials represent
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // the same account as |credentials| but the stored password was out of
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // date. In that case, the user just had to manually enter the new
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // password, which is now in |credentials|. The best thing would be to
2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // save automatically, and also update the original credentials. However,
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // we have no way to tell if this is the case. This will likely happen
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // infrequently, and the inconvenience put on the user by asking them is
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // not significant, so we are fine with asking here again.
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (password_changed) {
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        pending_credentials_.original_signon_realm.clear();
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        DCHECK(!IsPendingCredentialsPublicSuffixMatch());
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {  // Not a PSL match.
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      is_new_login_ = false;
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (password_changed)
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        user_action_ = kUserActionOverridePassword;
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (action == ALLOW_OTHER_POSSIBLE_USERNAMES &&
296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)             UpdatePendingCredentialsIfOtherPossibleUsername(
297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 credentials.username_value)) {
298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // |pending_credentials_| is now set. Note we don't update
299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // |pending_credentials_.username_value| to |credentials.username_value|
300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // yet because we need to keep the original username to modify the stored
301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // credential.
302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    selected_username_ = credentials.username_value;
303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    is_new_login_ = false;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // User typed in a new, unknown username.
306effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    user_action_ = kUserActionOverrideUsernameAndPassword;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_credentials_ = observed_form_;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_credentials_.username_value = credentials.username_value;
309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    pending_credentials_.other_possible_usernames =
310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        credentials.other_possible_usernames;
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // The password value will be filled in later, remove any garbage for now.
313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    pending_credentials_.password_value.clear();
314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    pending_credentials_.new_password_value.clear();
315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // If this was a sign-up or change password form, the names of the elements
317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // are likely different than those on a login form, so do not bother saving
318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // them. We will fill them with meaningful values in UpdateLogin() when the
319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // user goes onto a real login form for the first time.
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!credentials.new_password_element.empty()) {
321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      pending_credentials_.password_element.clear();
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      pending_credentials_.new_password_element.clear();
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_credentials_.action = credentials.action;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user selected credentials we autofilled from a PasswordForm
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that contained no action URL (IE6/7 imported passwords, for example),
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bless it with the action URL from the observed form. See bug 1107719.
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pending_credentials_.action.is_empty())
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_credentials_.action = observed_form_.action;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  pending_credentials_.password_value = password_to_save;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_credentials_.preferred = credentials.preferred;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
336effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (user_action_ == kUserActionOverridePassword &&
33723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      pending_credentials_.type == PasswordForm::TYPE_GENERATED &&
33823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      !has_generated_password_) {
33923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    LogPasswordGenerationSubmissionEvent(PASSWORD_OVERRIDDEN);
34023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
34123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (has_generated_password_)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_credentials_.type = PasswordForm::TYPE_GENERATED;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordFormManager::Save() {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, POST_MATCHING_PHASE);
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!driver_->IsOffTheRecord());
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsNewLogin())
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveAsNewLogin(true);
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateLogin();
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PasswordFormManager::FetchMatchingLoginsFromPasswordStore(
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PasswordStore::AuthorizationPromptPolicy prompt_policy) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, PRE_MATCHING_PHASE);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = MATCHING_PHASE;
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PasswordStore* password_store = client_->GetPasswordStore();
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!password_store) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  password_store->GetLogins(observed_form_, prompt_policy, this);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordFormManager::HasCompletedMatching() {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return state_ == POST_MATCHING_PHASE;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PasswordFormManager::OnRequestDone(
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<PasswordForm*>& logins_result) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that the result gets deleted after this call completes, but we own
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the PasswordForm objects pointed to by the result vector, thus we keep
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // copies to a minimum here.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int best_score = 0;
37968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // These credentials will be in the final result regardless of score.
38068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::vector<PasswordForm> credentials_to_keep;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < logins_result.size(); i++) {
3826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (ShouldIgnoreResult(*logins_result[i])) {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete logins_result[i];
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Score and update best matches.
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int current_score = ScoreResult(*logins_result[i]);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This check is here so we can append empty path matches in the event
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // they don't score as high as others and aren't added to best_matches_.
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This is most commonly imported firefox logins. We skip blacklisted
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ones because clearly we don't want to autofill them, and secondly
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // because they only mean something when we have no other matches already
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // saved in Chrome - in which case they'll make it through the regular
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // scoring flow below by design. Note signon_realm == origin implies empty
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // path logins_result, since signon_realm is a prefix of origin for HTML
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // password forms.
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(timsteele): Bug 1269400. We probably should do something more
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // elegant for any shorter-path match instead of explicitly handling empty
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // path matches.
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((observed_form_.scheme == PasswordForm::SCHEME_HTML) &&
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (observed_form_.signon_realm == logins_result[i]->origin.spec()) &&
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (current_score > 0) && (!logins_result[i]->blacklisted_by_user)) {
40368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      credentials_to_keep.push_back(*logins_result[i]);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Always keep generated passwords as part of the result set. If a user
40768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // generates a password on a signup form, it should show on a login form
40868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // even if they have a previous login saved.
40968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // TODO(gcasto): We don't want to cut credentials that were saved on signup
41068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // forms even if they weren't generated, but currently it's hard to
41168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // distinguish between those forms and two different login forms on the
41268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // same domain. Filed http://crbug.com/294468 to look into this.
41368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (logins_result[i]->type == PasswordForm::TYPE_GENERATED)
41468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      credentials_to_keep.push_back(*logins_result[i]);
41568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (current_score < best_score) {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete logins_result[i];
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (current_score == best_score) {
4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      PasswordForm* old_form = best_matches_[logins_result[i]->username_value];
4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (old_form) {
4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (preferred_match_ == old_form)
4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          preferred_match_ = NULL;
4255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        delete old_form;
4265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_matches_[logins_result[i]->username_value] = logins_result[i];
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (current_score > best_score) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_score = current_score;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This new login has a better score than all those up to this point
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note 'this' owns all the PasswordForms in best_matches_.
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      STLDeleteValues(&best_matches_);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      preferred_match_ = NULL;  // Don't delete, its owned by best_matches_.
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_matches_[logins_result[i]->username_value] = logins_result[i];
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    preferred_match_ = logins_result[i]->preferred ? logins_result[i]
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   : preferred_match_;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We're done matching now.
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = POST_MATCHING_PHASE;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  client_->AutofillResultsComputed();
4436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(gcasto): Change this to check that best_matches_ is empty. This should
4451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // be equivalent for the moment, but it's less clear and may not be
4461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // equivalent in the future.
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (best_score <= 0) {
4481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // If no saved forms can be used, then it isn't blacklisted and generation
4491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // should be allowed.
4501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    driver_->AllowPasswordGenerationForForm(observed_form_);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (std::vector<PasswordForm>::const_iterator it =
45568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)           credentials_to_keep.begin();
45668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)       it != credentials_to_keep.end(); ++it) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we don't already have a result with the same username, add the
45868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // lower-scored match (if it had equal score it would already be in
45968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // best_matches_).
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (best_matches_.find(it->username_value) == best_matches_.end())
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      best_matches_[it->username_value] = new PasswordForm(*it);
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsNotShown",
4654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                       logins_result.size() - best_matches_.size());
4664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is possible we have at least one match but have no preferred_match_,
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because a user may have chosen to 'Forget' the preferred match. So we
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just pick the first one and whichever the user selects for submit will
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be saved as preferred.
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!best_matches_.empty());
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!preferred_match_)
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    preferred_match_ = best_matches_.begin()->second;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check to see if the user told us to ignore this site in the past.
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (preferred_match_->blacklisted_by_user) {
477010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    client_->PasswordAutofillWasBlocked(best_matches_);
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    manager_action_ = kManagerActionBlacklisted;
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If not blacklisted, inform the driver that password generation is allowed
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // for |observed_form_|.
484116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  driver_->AllowPasswordGenerationForForm(observed_form_);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Proceed to autofill.
487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Note that we provide the choices but don't actually prefill a value if:
488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // (1) we are in Incognito mode, (2) the ACTION paths don't match,
489eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // or (3) if it matched using public suffix domain matching.
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool wait_for_username =
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      driver_->IsOffTheRecord() ||
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      observed_form_.action.GetWithEmptyPath() !=
493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          preferred_match_->action.GetWithEmptyPath() ||
494eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          preferred_match_->IsPublicSuffixMatch();
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (wait_for_username)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    manager_action_ = kManagerActionNone;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    manager_action_ = kManagerActionAutofilled;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  password_manager_->Autofill(observed_form_, best_matches_,
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              *preferred_match_, wait_for_username);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PasswordFormManager::OnGetPasswordStoreResults(
50458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      const std::vector<autofill::PasswordForm*>& results) {
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, MATCHING_PHASE);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (results.empty()) {
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = POST_MATCHING_PHASE;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No result means that we visit this site the first time so we don't need
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to check whether this site is blacklisted or not. Just send a message
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to allow password generation.
512116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    driver_->AllowPasswordGenerationForForm(observed_form_);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnRequestDone(results);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool PasswordFormManager::ShouldIgnoreResult(const PasswordForm& form) const {
519116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Do not autofill on sign-up or change password forms (until we have some
520116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // working change password functionality).
521116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!observed_form_.new_password_element.empty())
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
523116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Don't match an invalid SSL form with one saved under secure circumstances.
524116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (form.ssl_valid && !observed_form_.ssl_valid)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (client_->ShouldFilterAutofillResult(form))
5286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return true;
5296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordFormManager::SaveAsNewLogin(bool reset_preferred_login) {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, POST_MATCHING_PHASE);
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsNewLogin());
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The new_form is being used to sign in, so it is preferred.
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(pending_credentials_.preferred);
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // new_form contains the same basic data as observed_form_ (because its the
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // same form), but with the newly added credentials.
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!driver_->IsOffTheRecord());
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PasswordStore* password_store = client_->GetPasswordStore();
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!password_store) {
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Upload credentials the first time they are saved. This data is used
5501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // by password generation to help determine account creation sites.
5511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Blacklisted credentials will never be used, so don't upload a vote for
5521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // them.
5531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!pending_credentials_.blacklisted_by_user)
5541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UploadPasswordForm(pending_credentials_.form_data, autofill::PASSWORD);
5551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_credentials_.date_created = Time::Now();
557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SanitizePossibleUsernames(&pending_credentials_);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  password_store->AddLogin(pending_credentials_);
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reset_preferred_login) {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdatePreferredLoginState(password_store);
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void PasswordFormManager::SanitizePossibleUsernames(PasswordForm* form) {
566c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove any possible usernames that could be credit cards or SSN for privacy
567868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // reasons. Also remove duplicates, both in other_possible_usernames and
568868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // between other_possible_usernames and username_value.
5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::set<base::string16> set;
5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (std::vector<base::string16>::iterator it =
571868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           form->other_possible_usernames.begin();
572868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       it != form->other_possible_usernames.end(); ++it) {
573c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!autofill::IsValidCreditCardNumber(*it) && !autofill::IsSSN(*it))
574c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      set.insert(*it);
575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  set.erase(form->username_value);
5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<base::string16> temp(set.begin(), set.end());
578868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  form->other_possible_usernames.swap(temp);
579c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
580c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordFormManager::UpdatePreferredLoginState(
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordStore* password_store) {
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(password_store);
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PasswordFormMap::iterator iter;
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = best_matches_.begin(); iter != best_matches_.end(); iter++) {
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (iter->second->username_value != pending_credentials_.username_value &&
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        iter->second->preferred) {
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This wasn't the selected login but it used to be preferred.
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iter->second->preferred = false;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (user_action_ == kUserActionNone)
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        user_action_ = kUserActionChoose;
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password_store->UpdateLogin(*iter->second);
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordFormManager::UpdateLogin() {
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, POST_MATCHING_PHASE);
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(preferred_match_);
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're doing an Update, we either autofilled correctly and need to
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // update the stats, or the user typed in a new password for autofilled
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // username, or the user selected one of the non-preferred matches,
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thus requiring a swap of preferred bits.
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!IsNewLogin() && pending_credentials_.preferred);
6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!driver_->IsOffTheRecord());
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PasswordStore* password_store = client_->GetPasswordStore();
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!password_store) {
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
61390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Update metadata.
61490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ++pending_credentials_.times_used;
61590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
616116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (client_->IsSyncAccountCredential(
617116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          base::UTF16ToUTF8(pending_credentials_.username_value),
618116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          pending_credentials_.signon_realm)) {
619116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    base::RecordAction(
620116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        base::UserMetricsAction("PasswordManager_SyncCredentialUsed"));
621116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
622116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
623d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Check to see if this form is a candidate for password generation.
624d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  CheckForAccountCreationForm(pending_credentials_, observed_form_);
625d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatePreferredLoginState(password_store);
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
628868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Remove alternate usernames. At this point we assume that we have found
629868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // the right username.
630868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  pending_credentials_.other_possible_usernames.clear();
631868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the new preferred login.
633868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!selected_username_.empty()) {
634868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // An other possible username is selected. We set this selected username
635868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // as the real username. The PasswordStore API isn't designed to update
636868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // username, so we delete the old credentials and add a new one instead.
637868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    password_store->RemoveLogin(pending_credentials_);
638868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    pending_credentials_.username_value = selected_username_;
639868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    password_store->AddLogin(pending_credentials_);
640868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if ((observed_form_.scheme == PasswordForm::SCHEME_HTML) &&
641868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)             (observed_form_.origin.spec().length() >
642868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              observed_form_.signon_realm.length()) &&
643868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)             (observed_form_.signon_realm ==
644868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              pending_credentials_.origin.spec())) {
645868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Note origin.spec().length > signon_realm.length implies the origin has a
646868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // path, since signon_realm is a prefix of origin for HTML password forms.
647868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    //
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The user logged in successfully with one of our autofilled logins on a
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // page with non-empty path, but the autofilled entry was initially saved/
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // imported with an empty path. Rather than just mark this entry preferred,
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we create a more specific copy for this exact page and leave the "master"
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // unchanged. This is to prevent the case where that master login is used
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // on several sites (e.g site.com/a and site.com/b) but the user actually
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // has a different preference on each site. For example, on /a, he wants the
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // general empty-path login so it is flagged as preferred, but on /b he logs
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // in with a different saved entry - we don't want to remove the preferred
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // status of the former because upon return to /a it won't be the default-
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // fill match.
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(timsteele): Bug 1188626 - expire the master copies.
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm copy(pending_credentials_);
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    copy.origin = observed_form_.origin;
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    copy.action = observed_form_.action;
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    password_store->AddLogin(copy);
664116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else if (observed_form_.new_password_element.empty() &&
665116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch             (pending_credentials_.password_element.empty() ||
666116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              pending_credentials_.username_element.empty() ||
667116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              pending_credentials_.submit_element.empty())) {
668116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // If |observed_form_| was a sign-up or change password form, there is no
669116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // point in trying to update element names: they are likely going to be
670116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // different than those on a login form.
671116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Otherwise, given that |password_element| and |username_element| can't be
672116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // updated because they are part of Sync and PasswordStore primary key, we
673116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // must delete the old credentials altogether and then add the new ones.
674cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    password_store->RemoveLogin(pending_credentials_);
675cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    pending_credentials_.password_element = observed_form_.password_element;
676cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    pending_credentials_.username_element = observed_form_.username_element;
677cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    pending_credentials_.submit_element = observed_form_.submit_element;
678cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    password_store->AddLogin(pending_credentials_);
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    password_store->UpdateLogin(pending_credentials_);
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
684868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool PasswordFormManager::UpdatePendingCredentialsIfOtherPossibleUsername(
685a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& username) {
686868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (PasswordFormMap::const_iterator it = best_matches_.begin();
687868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       it != best_matches_.end(); ++it) {
688868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (size_t i = 0; i < it->second->other_possible_usernames.size(); ++i) {
689868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (it->second->other_possible_usernames[i] == username) {
690868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        pending_credentials_ = *it->second;
691868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return true;
692868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
693868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
694868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
695868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return false;
696868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
697868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
698d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void PasswordFormManager::CheckForAccountCreationForm(
699d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const PasswordForm& pending, const PasswordForm& observed) {
700d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // We check to see if the saved form_data is the same as the observed
701d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // form_data, which should never be true for passwords saved on account
702d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // creation forms. This check is only made the first time a password is used
703d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // to cut down on false positives. Specifically a site may have multiple login
704d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // forms with different markup, which might look similar to a signup form.
705d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (pending.times_used == 1) {
706d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    FormStructure pending_structure(pending.form_data);
707d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    FormStructure observed_structure(observed.form_data);
7084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Ignore |pending_structure| if its FormData has no fields. This is to
7094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // weed out those credentials that were saved before FormData was added
7104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // to PasswordForm. Even without this check, these FormStructure's won't
7114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // be uploaded, but it makes it hard to see if we are encountering
7124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // unexpected errors.
7134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (!pending.form_data.fields.empty() &&
7144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        pending_structure.FormSignature() !=
715d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            observed_structure.FormSignature()) {
7161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      UploadPasswordForm(pending.form_data,
7171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         autofill::ACCOUNT_CREATION_PASSWORD);
718d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
719d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
720d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
721d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
7221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid PasswordFormManager::UploadPasswordForm(
7231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const autofill::FormData& form_data,
7241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const autofill::ServerFieldType& password_type) {
7251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  autofill::AutofillManager* autofill_manager =
7261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      driver_->GetAutofillManager();
7271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!autofill_manager)
7281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
7291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
7301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Note that this doesn't guarantee that the upload succeeded, only that
7311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // |form_data| is considered uploadable.
7321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool success =
73334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)      autofill_manager->UploadPasswordForm(form_data, password_type);
7341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  UMA_HISTOGRAM_BOOLEAN("PasswordGeneration.UploadStarted", success);
7351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
7361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int PasswordFormManager::ScoreResult(const PasswordForm& candidate) const {
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, MATCHING_PHASE);
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For scoring of candidate login data:
740010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The most important element that should match is the signon_realm followed
741010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // by the origin, the action, the password name, the submit button name, and
742010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // finally the username input field name.
743010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // If public suffix origin match was not used, it gives an addition of
744010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // 128 (1 << 7).
745eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Exact origin match gives an addition of 64 (1 << 6) + # of matching url
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dirs.
747eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Partial match gives an addition of 32 (1 << 5) + # matching url dirs
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // That way, a partial match cannot trump an exact match even if
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the partial one matches all other attributes (action, elements) (and
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // regardless of the matching depth in the URL path).
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int score = 0;
752010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!candidate.IsPublicSuffixMatch()) {
753010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    score += 1 << 7;
754010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (candidate.origin == observed_form_.origin) {
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This check is here for the most common case which
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is we have a single match in the db for the given host,
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // so we don't generally need to walk the entire URL path (the else
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // clause).
760eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    score += (1 << 6) + static_cast<int>(form_path_tokens_.size());
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Walk the origin URL paths one directory at a time to see how
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // deep the two match.
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string> candidate_path_tokens;
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SplitString(candidate.origin.path(), '/', &candidate_path_tokens);
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t depth = 0;
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t max_dirs = std::min(form_path_tokens_.size(),
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               candidate_path_tokens.size());
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while ((depth < max_dirs) && (form_path_tokens_[depth] ==
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  candidate_path_tokens[depth])) {
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      depth++;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      score++;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // do we have a partial match?
775eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    score += (depth > 0) ? 1 << 5 : 0;
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observed_form_.scheme == PasswordForm::SCHEME_HTML) {
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (candidate.action == observed_form_.action)
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      score += 1 << 3;
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (candidate.password_element == observed_form_.password_element)
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      score += 1 << 2;
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (candidate.submit_element == observed_form_.submit_element)
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      score += 1 << 1;
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (candidate.username_element == observed_form_.username_element)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      score += 1 << 0;
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return score;
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordFormManager::SubmitPassed() {
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  submit_result_ = kSubmitResultPassed;
79323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (has_generated_password_)
79423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMITTED);
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordFormManager::SubmitFailed() {
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  submit_result_ = kSubmitResultFailed;
79923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (has_generated_password_)
80023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMISSION_FAILED);
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
802c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
803c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}  // namespace password_manager
804