1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_FORM_MANAGER_H_
6#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_FORM_MANAGER_H_
7#pragma once
8
9#include <string>
10#include <vector>
11
12#include "build/build_config.h"
13
14#include "base/stl_util-inl.h"
15#include "chrome/browser/password_manager/password_store_consumer.h"
16#include "webkit/glue/password_form.h"
17
18class PasswordManager;
19class PasswordStore;
20class Profile;
21
22// Per-password-form-{on-page, dialog} class responsible for interactions
23// between a given form, the per-tab PasswordManager, and the PasswordStore.
24class PasswordFormManager : public PasswordStoreConsumer {
25 public:
26  // profile contains the link to the PasswordStore and whether we're off
27  //           the record
28  // password_manager owns this object
29  // form_on_page is the form that may be submitted and could need login data.
30  // ssl_valid represents the security of the page containing observed_form,
31  //           used to filter login results from database.
32  PasswordFormManager(Profile* profile,
33                      PasswordManager* password_manager,
34                      const webkit_glue::PasswordForm& observed_form,
35                      bool ssl_valid);
36  virtual ~PasswordFormManager();
37
38  // Compare basic data of observed_form_ with argument.
39  bool DoesManage(const webkit_glue::PasswordForm& form) const;
40
41  // Retrieves potential matching logins from the database.
42  void FetchMatchingLoginsFromPasswordStore();
43
44  // Simple state-check to verify whether this object as received a callback
45  // from the PasswordStore and completed its matching phase. Note that the
46  // callback in question occurs on the same (and only) main thread from which
47  // instances of this class are ever used, but it is required since it is
48  // conceivable that a user (or ui test) could attempt to submit a login
49  // prompt before the callback has occured, which would InvokeLater a call to
50  // PasswordManager::ProvisionallySave, which would interact with this object
51  // before the db has had time to answer with matching password entries.
52  // This is intended to be a one-time check; if the return value is false the
53  // expectation is caller will give up. This clearly won't work if you put it
54  // in a loop and wait for matching to complete; you're (supposed to be) on
55  // the same thread!
56  bool HasCompletedMatching();
57
58  // Determines if the user opted to 'never remember' passwords for this form.
59  bool IsBlacklisted();
60
61  // Used by PasswordManager to determine whether or not to display
62  // a SavePasswordBar when given the green light to save the PasswordForm
63  // managed by this.
64  bool IsNewLogin();
65
66  // Checks if the form is a valid password form. Forms which lack either
67  // login or password field are not considered valid.
68  bool HasValidPasswordForm();
69
70  // Determines if we need to autofill given the results of the query.
71  void OnRequestDone(
72      int handle, const std::vector<webkit_glue::PasswordForm*>& result);
73
74  // PasswordStoreConsumer implementation.
75  virtual void OnPasswordStoreRequestDone(
76      CancelableRequestProvider::Handle handle,
77      const std::vector<webkit_glue::PasswordForm*>& result);
78
79  // A user opted to 'never remember' passwords for this form.
80  // Blacklist it so that from now on when it is seen we ignore it.
81  void PermanentlyBlacklist();
82
83  // If the user has submitted observed_form_, provisionally hold on to
84  // the submitted credentials until we are told by PasswordManager whether
85  // or not the login was successful.
86  void ProvisionallySave(const webkit_glue::PasswordForm& credentials);
87
88  // Handles save-as-new or update of the form managed by this manager.
89  // Note the basic data of updated_credentials must match that of
90  // observed_form_ (e.g DoesManage(pending_credentials_) == true).
91  void Save();
92
93  // Call these if/when we know the form submission worked or failed.
94  // These routines are used to update internal statistics ("ActionsTaken").
95  void SubmitPassed();
96  void SubmitFailed();
97
98 private:
99  friend class PasswordFormManagerTest;
100
101  // ManagerAction - What does the manager do with this form? Either it
102  // fills it, or it doesn't. If it doesn't fill it, that's either
103  // because it has no match, or it is blacklisted, or it is disabled
104  // via the AUTOCOMPLETE=off attribute. Note that if we don't have
105  // an exact match, we still provide candidates that the user may
106  // end up choosing.
107  enum ManagerAction {
108    kManagerActionNone = 0,
109    kManagerActionAutofilled,
110    kManagerActionBlacklisted,
111    kManagerActionDisabled,
112    kManagerActionMax
113  };
114
115  // UserAction - What does the user do with this form? If he or she
116  // does nothing (either by accepting what the password manager did, or
117  // by simply (not typing anything at all), you get None. If there were
118  // multiple choices and the user selects one other than the default,
119  // you get Choose, and if the user types in a new value, you get
120  // Override.
121  enum UserAction {
122    kUserActionNone = 0,
123    kUserActionChoose,
124    kUserActionOverride,
125    kUserActionMax
126  };
127
128  // Result - What happens to the form?
129  enum SubmitResult {
130    kSubmitResultNotSubmitted = 0,
131    kSubmitResultFailed,
132    kSubmitResultPassed,
133    kSubmitResultMax
134  };
135
136  // The maximum number of combinations of the three preceding enums.
137  // This is used when recording the actions taken by the form in UMA.
138  static const int kMaxNumActionsTaken = kManagerActionMax * kUserActionMax *
139                                         kSubmitResultMax;
140
141  // Helper for OnPasswordStoreRequestDone to determine whether or not
142  // the given result form is worth scoring.
143  bool IgnoreResult(const webkit_glue::PasswordForm& form) const;
144
145  // Helper for Save in the case that best_matches.size() == 0, meaning
146  // we have no prior record of this form/username/password and the user
147  // has opted to 'Save Password'. If |reset_preferred_login| is set,
148  // the previously preferred login from |best_matches_| will be reset.
149  void SaveAsNewLogin(bool reset_preferred_login);
150
151  // Helper for OnPasswordStoreRequestDone to score an individual result
152  // against the observed_form_.
153  int ScoreResult(const webkit_glue::PasswordForm& form) const;
154
155  // Helper for Save in the case that best_matches.size() > 0, meaning
156  // we have at least one match for this form/username/password. This
157  // Updates the form managed by this object, as well as any matching forms
158  // that now need to have preferred bit changed, since updated_credentials
159  // is now implicitly 'preferred'.
160  void UpdateLogin();
161
162  // Update all login matches to reflect new preferred state - preferred flag
163  // will be reset on all matched logins that different than the current
164  // |pending_credentials_|.
165  void UpdatePreferredLoginState(PasswordStore* password_store);
166
167  // Converts the "ActionsTaken" fields into an int so they can be logged to
168  // UMA.
169  int GetActionsTaken();
170
171  // Set of PasswordForms from the DB that best match the form
172  // being managed by this. Use a map instead of vector, because we most
173  // frequently require lookups by username value in IsNewLogin.
174  webkit_glue::PasswordFormMap best_matches_;
175
176  // Cleans up when best_matches_ goes out of scope.
177  STLValueDeleter<webkit_glue::PasswordFormMap> best_matches_deleter_;
178
179  // The PasswordForm from the page or dialog managed by this.
180  webkit_glue::PasswordForm observed_form_;
181
182  // The origin url path of observed_form_ tokenized, for convenience when
183  // scoring.
184  std::vector<std::string> form_path_tokens_;
185
186  // Stores updated credentials when the form was submitted but success is
187  // still unknown.
188  webkit_glue::PasswordForm pending_credentials_;
189
190  // Whether pending_credentials_ stores a new login or is an update
191  // to an existing one.
192  bool is_new_login_;
193
194  // PasswordManager owning this.
195  const PasswordManager* const password_manager_;
196
197  // Handle to any pending PasswordStore::GetLogins query.
198  CancelableRequestProvider::Handle pending_login_query_;
199
200  // Convenience pointer to entry in best_matches_ that is marked
201  // as preferred. This is only allowed to be null if there are no best matches
202  // at all, since there will always be one preferred login when there are
203  // multiple matches (when first saved, a login is marked preferred).
204  const webkit_glue::PasswordForm* preferred_match_;
205
206  typedef enum {
207    PRE_MATCHING_PHASE,      // Have not yet invoked a GetLogins query to find
208                             // matching login information from password store.
209    MATCHING_PHASE,          // We've made a GetLogins request, but
210                             // haven't received or finished processing result.
211    POST_MATCHING_PHASE      // We've queried the DB and processed matching
212                             // login results.
213  } PasswordFormManagerState;
214
215  // State of matching process, used to verify that we don't call methods
216  // assuming we've already processed the request for matching logins,
217  // when we actually haven't.
218  PasswordFormManagerState state_;
219
220  // The profile from which we get the PasswordStore.
221  Profile* profile_;
222
223  // These three fields record the "ActionsTaken" by the browser and
224  // the user with this form, and the result. They are combined and
225  // recorded in UMA when the manager is destroyed.
226  ManagerAction manager_action_;
227  UserAction user_action_;
228  SubmitResult submit_result_;
229
230  DISALLOW_COPY_AND_ASSIGN(PasswordFormManager);
231};
232#endif  // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_FORM_MANAGER_H_
233