1// Copyright 2014 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_UI_PASSWORDS_MANAGE_PASSWORDS_UI_CONTROLLER_H_
6#define CHROME_BROWSER_UI_PASSWORDS_MANAGE_PASSWORDS_UI_CONTROLLER_H_
7
8#include "base/gtest_prod_util.h"
9#include "base/memory/scoped_vector.h"
10#include "base/timer/elapsed_timer.h"
11#include "components/autofill/core/common/password_form.h"
12#include "components/password_manager/core/browser/password_form_manager.h"
13#include "components/password_manager/core/browser/password_store.h"
14#include "components/password_manager/core/browser/password_store_change.h"
15#include "components/password_manager/core/common/password_manager_ui.h"
16#include "content/public/browser/navigation_details.h"
17#include "content/public/browser/web_contents_observer.h"
18#include "content/public/browser/web_contents_user_data.h"
19
20namespace content {
21class WebContents;
22}
23
24class ManagePasswordsIcon;
25
26// Per-tab class to control the Omnibox password icon and bubble.
27class ManagePasswordsUIController
28    : public content::WebContentsObserver,
29      public content::WebContentsUserData<ManagePasswordsUIController>,
30      public password_manager::PasswordStore::Observer {
31 public:
32  virtual ~ManagePasswordsUIController();
33
34  // Called when the user submits a form containing login information, so we
35  // can handle later requests to save or blacklist that login information.
36  // This stores the provided object in form_manager_ and triggers the UI to
37  // prompt the user about whether they would like to save the password.
38  void OnPasswordSubmitted(
39      scoped_ptr<password_manager::PasswordFormManager> form_manager);
40
41  // Called when the password will be saved automatically, but we still wish to
42  // visually inform the user that the save has occured.
43  void OnAutomaticPasswordSave(
44      scoped_ptr<password_manager::PasswordFormManager> form_manager);
45
46  // Called when a form is autofilled with login information, so we can manage
47  // password credentials for the current site which are stored in
48  // |password_form_map|. This stores a copy of |password_form_map| and shows
49  // the manage password icon.
50  void OnPasswordAutofilled(const autofill::PasswordFormMap& password_form_map);
51
52  // Called when a form is _not_ autofilled due to user blacklisting. This
53  // stores a copy of |password_form_map| so that we can offer the user the
54  // ability to reenable the manager for this form.
55  void OnBlacklistBlockedAutofill(
56      const autofill::PasswordFormMap& password_form_map);
57
58  // PasswordStore::Observer implementation.
59  virtual void OnLoginsChanged(
60      const password_manager::PasswordStoreChangeList& changes) OVERRIDE;
61
62  // Called from the model when the user chooses to save a password; passes the
63  // action off to the FormManager. The controller MUST be in a pending state,
64  // and WILL be in MANAGE_STATE after this method executes.
65  virtual void SavePassword();
66
67  // Called from the model when the user chooses to never save passwords; passes
68  // the action off to the FormManager. The controller MUST be in a pending
69  // state, and WILL be in BLACKLIST_STATE after this method executes.
70  virtual void NeverSavePassword();
71
72  // Called from the model when the user chooses to unblacklist the site. The
73  // controller MUST be in BLACKLIST_STATE, and WILL be in MANAGE_STATE after
74  // this method executes.
75  virtual void UnblacklistSite();
76
77  // Open a new tab, pointing to the password manager settings page.
78  virtual void NavigateToPasswordManagerSettingsPage();
79
80  virtual const autofill::PasswordForm& PendingCredentials() const;
81
82  // Set the state of the Omnibox icon, and possibly show the associated bubble
83  // without user interaction.
84  virtual void UpdateIconAndBubbleState(ManagePasswordsIcon* icon);
85
86  password_manager::ui::State state() const { return state_; }
87
88  // True if a password is sitting around, waiting for a user to decide whether
89  // or not to save it.
90  bool PasswordPendingUserDecision() const;
91
92  const autofill::ConstPasswordFormMap& best_matches() const {
93    return password_form_map_;
94  }
95
96  const GURL& origin() const { return origin_; }
97
98 protected:
99  explicit ManagePasswordsUIController(
100      content::WebContents* web_contents);
101
102  // The pieces of saving and blacklisting passwords that interact with
103  // FormManager, split off into internal functions for testing/mocking.
104  virtual void SavePasswordInternal();
105  virtual void NeverSavePasswordInternal();
106
107  // content::WebContentsObserver:
108  virtual void DidNavigateMainFrame(
109      const content::LoadCommittedDetails& details,
110      const content::FrameNavigateParams& params) OVERRIDE;
111  virtual void WasHidden() OVERRIDE;
112
113  // We create copies of PasswordForm objects that come in with unclear lifetime
114  // and store them in this vector as well as in |password_form_map_| to ensure
115  // that we destroy them correctly. If |new_password_forms_| gets cleared then
116  // |password_form_map_| is to be cleared too.
117  ScopedVector<autofill::PasswordForm> new_password_forms_;
118
119  // All previously stored credentials for a specific site.
120  // Protected, not private, so we can mess with the value in
121  // ManagePasswordsUIControllerMock.
122  autofill::ConstPasswordFormMap password_form_map_;
123
124  // The current state of the password manager. Protected so we can manipulate
125  // the value in tests.
126  password_manager::ui::State state_;
127
128  // Used to measure the amount of time on a page; if it's less than some
129  // reasonable limit, then don't close the bubble upon navigation. We create
130  // (and destroy) the timer in DidNavigateMainFrame.
131  scoped_ptr<base::ElapsedTimer> timer_;
132
133 private:
134  friend class content::WebContentsUserData<ManagePasswordsUIController>;
135
136  // Shows the password bubble without user interaction. The controller MUST
137  // be in PENDING_PASSWORD_AND_BUBBLE_STATE.
138  void ShowBubbleWithoutUserInteraction();
139
140  // Called when a passwordform is autofilled, when a new passwordform is
141  // submitted, or when a navigation occurs to update the visibility of the
142  // manage passwords icon and bubble.
143  void UpdateBubbleAndIconVisibility();
144
145  // content::WebContentsObserver:
146  virtual void WebContentsDestroyed() OVERRIDE;
147
148  // Set by OnPasswordSubmitted() when the user submits a form containing login
149  // information.  If the user responds to a subsequent "Do you want to save
150  // this password?" prompt, we ask this object to save or blacklist the
151  // associated login information in Chrome's password store.
152  scoped_ptr<password_manager::PasswordFormManager> form_manager_;
153
154  // Stores whether autofill was blocked due to a user's decision to blacklist
155  // the current site ("Never save passwords for this site").
156  bool autofill_blocked_;
157
158  // The origin of the form we're currently dealing with; we'll use this to
159  // determine which PasswordStore changes we should care about when updating
160  // |password_form_map_|.
161  GURL origin_;
162
163  DISALLOW_COPY_AND_ASSIGN(ManagePasswordsUIController);
164};
165
166#endif  // CHROME_BROWSER_UI_PASSWORDS_MANAGE_PASSWORDS_UI_CONTROLLER_H_
167