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 <memory>
9 #include <vector>
10 
11 #include "base/macros.h"
12 #include "base/timer/timer.h"
13 #include "chrome/browser/ui/passwords/manage_passwords_state.h"
14 #include "chrome/browser/ui/passwords/passwords_client_ui_delegate.h"
15 #include "chrome/browser/ui/passwords/passwords_leak_dialog_delegate.h"
16 #include "chrome/browser/ui/passwords/passwords_model_delegate.h"
17 #include "chrome/common/buildflags.h"
18 #include "components/password_manager/core/browser/password_manager_client.h"
19 #include "components/password_manager/core/browser/password_store.h"
20 #include "components/password_manager/core/browser/ui/post_save_compromised_helper.h"
21 #include "content/public/browser/web_contents_observer.h"
22 #include "content/public/browser/web_contents_user_data.h"
23 
24 namespace base {
25 class TimeDelta;
26 }
27 
28 namespace content {
29 class WebContents;
30 }
31 
32 namespace password_manager {
33 enum class CredentialType;
34 struct InteractionsStats;
35 class PasswordFeatureManager;
36 class PasswordFormManagerForUI;
37 class PostSaveCompromisedHelper;
38 }  // namespace password_manager
39 
40 class AccountChooserPrompt;
41 struct AccountInfo;
42 class AutoSigninFirstRunPrompt;
43 class CredentialLeakPrompt;
44 class ManagePasswordsIconView;
45 class CredentialLeakDialogController;
46 class CredentialManagerDialogController;
47 class PasswordBaseDialogController;
48 
49 // Per-tab class to control the Omnibox password icon and bubble.
50 class ManagePasswordsUIController
51     : public content::WebContentsObserver,
52       public content::WebContentsUserData<ManagePasswordsUIController>,
53       public password_manager::PasswordStore::Observer,
54       public PasswordsLeakDialogDelegate,
55       public PasswordsModelDelegate,
56       public PasswordsClientUIDelegate {
57  public:
58   ~ManagePasswordsUIController() override;
59 
60 #if defined(UNIT_TEST)
set_save_fallback_timeout_in_seconds(int timeout)61   static void set_save_fallback_timeout_in_seconds(int timeout) {
62     save_fallback_timeout_in_seconds_ = timeout;
63   }
64 #endif
65 
66   // PasswordsClientUIDelegate:
67   void OnPasswordSubmitted(
68       std::unique_ptr<password_manager::PasswordFormManagerForUI> form_manager)
69       override;
70   void OnUpdatePasswordSubmitted(
71       std::unique_ptr<password_manager::PasswordFormManagerForUI> form_manager)
72       override;
73   void OnShowManualFallbackForSaving(
74       std::unique_ptr<password_manager::PasswordFormManagerForUI> form_manager,
75       bool has_generated_password,
76       bool is_update) override;
77   void OnHideManualFallbackForSaving() override;
78   bool OnChooseCredentials(
79       std::vector<std::unique_ptr<password_manager::PasswordForm>>
80           local_credentials,
81       const url::Origin& origin,
82       ManagePasswordsState::CredentialsCallback callback) override;
83   void OnAutoSignin(
84       std::vector<std::unique_ptr<password_manager::PasswordForm>> local_forms,
85       const url::Origin& origin) override;
86   void OnPromptEnableAutoSignin() override;
87   void OnAutomaticPasswordSave(
88       std::unique_ptr<password_manager::PasswordFormManagerForUI> form_manager)
89       override;
90   void OnPasswordAutofilled(
91       const std::vector<const password_manager::PasswordForm*>& password_forms,
92       const url::Origin& origin,
93       const std::vector<const password_manager::PasswordForm*>*
94           federated_matches) override;
95   void OnCredentialLeak(password_manager::CredentialLeakType leak_dialog_type,
96                         const GURL& origin) override;
97   void OnShowMoveToAccountBubble(
98       std::unique_ptr<password_manager::PasswordFormManagerForUI> form_to_move)
99       override;
100 
101   virtual void NotifyUnsyncedCredentialsWillBeDeleted(
102       std::vector<password_manager::PasswordForm> unsynced_credentials);
103 
104   // PasswordStore::Observer:
105   void OnLoginsChanged(
106       const password_manager::PasswordStoreChangeList& changes) override;
107 
108   // Set the state of the Omnibox icon, and possibly show the associated bubble
109   // without user interaction.
110   virtual void UpdateIconAndBubbleState(ManagePasswordsIconView* icon);
111 
112   // True iff the bubble is to be opened automatically.
IsAutomaticallyOpeningBubble()113   bool IsAutomaticallyOpeningBubble() const {
114     return bubble_status_ == BubbleStatus::SHOULD_POP_UP;
115   }
116 
117   // virtual to be overridden in tests.
118   virtual base::WeakPtr<PasswordsModelDelegate> GetModelDelegateProxy();
119 
120   // PasswordsModelDelegate:
121   content::WebContents* GetWebContents() const override;
122   url::Origin GetOrigin() const override;
123   password_manager::PasswordFormMetricsRecorder*
124   GetPasswordFormMetricsRecorder() override;
125   password_manager::PasswordFeatureManager* GetPasswordFeatureManager()
126       override;
127   password_manager::ui::State GetState() const override;
128   const password_manager::PasswordForm& GetPendingPassword() const override;
129   const std::vector<password_manager::PasswordForm>& GetUnsyncedCredentials()
130       const override;
131   password_manager::metrics_util::CredentialSourceType GetCredentialSource()
132       const override;
133   const std::vector<std::unique_ptr<password_manager::PasswordForm>>&
134   GetCurrentForms() const override;
135   const password_manager::InteractionsStats* GetCurrentInteractionStats()
136       const override;
137   size_t GetTotalNumberCompromisedPasswords() const override;
138   bool DidAuthForAccountStoreOptInFail() const override;
139   bool BubbleIsManualFallbackForSaving() const override;
140   void OnBubbleShown() override;
141   void OnBubbleHidden() override;
142   void OnNoInteraction() override;
143   void OnNopeUpdateClicked() override;
144   void NeverSavePassword() override;
145   void OnPasswordsRevealed() override;
146   void SavePassword(const base::string16& username,
147                     const base::string16& password) override;
148   void SaveUnsyncedCredentialsInProfileStore(
149       const std::vector<password_manager::PasswordForm>& selected_credentials)
150       override;
151   void DiscardUnsyncedCredentials() override;
152   void MovePasswordToAccountStore() override;
153   void BlockMovingPasswordToAccountStore() override;
154   void ChooseCredential(
155       const password_manager::PasswordForm& form,
156       password_manager::CredentialType credential_type) override;
157   void NavigateToPasswordManagerAccountDashboard(
158       password_manager::ManagePasswordsReferrer referrer) override;
159   void NavigateToPasswordManagerSettingsPage(
160       password_manager::ManagePasswordsReferrer referrer) override;
161   void EnableSync(const AccountInfo& account) override;
162   void OnDialogHidden() override;
163   bool AuthenticateUser() override;
164   void AuthenticateUserForAccountStoreOptInAndSavePassword(
165       const base::string16& username,
166       const base::string16& password) override;
167   void AuthenticateUserForAccountStoreOptInAndMovePassword() override;
168   bool ArePasswordsRevealedWhenBubbleIsOpened() const override;
169 
170 #if defined(UNIT_TEST)
171   // Overwrites the client for |passwords_data_|.
set_client(password_manager::PasswordManagerClient * client)172   void set_client(password_manager::PasswordManagerClient* client) {
173     passwords_data_.set_client(client);
174   }
175 #endif  // defined(UNIT_TEST)
176 
177  protected:
178   explicit ManagePasswordsUIController(content::WebContents* web_contents);
179 
180   // Hides the bubble if opened. Mocked in the tests.
181   virtual void HidePasswordBubble();
182 
183   // Called when a PasswordForm is autofilled, when a new PasswordForm is
184   // submitted, or when a navigation occurs to update the visibility of the
185   // manage passwords icon and bubble.
186   virtual void UpdateBubbleAndIconVisibility();
187 
188   // Called to create the account chooser dialog. Mocked in tests.
189   virtual AccountChooserPrompt* CreateAccountChooser(
190       CredentialManagerDialogController* controller);
191 
192   // Called to create the account chooser dialog. Mocked in tests.
193   virtual AutoSigninFirstRunPrompt* CreateAutoSigninPrompt(
194       CredentialManagerDialogController* controller);
195 
196   // Called to create the credentials leaked dialog.
197   virtual CredentialLeakPrompt* CreateCredentialLeakPrompt(
198       CredentialLeakDialogController* controller);
199 
200   // Check if |web_contents()| is attached to some Browser. Mocked in tests.
201   virtual bool HasBrowserWindow() const;
202 
203   // True if the bubble is to be opened automatically or after re-auth.
ShouldBubblePopUp()204   bool ShouldBubblePopUp() const {
205     return IsAutomaticallyOpeningBubble() ||
206            bubble_status_ == BubbleStatus::SHOULD_POP_UP_AFTER_REAUTH;
207   }
208 
209   // Returns whether the bubble is currently open.
IsShowingBubbleForTest()210   bool IsShowingBubbleForTest() const { return IsShowingBubble(); }
211 
212   // content::WebContentsObserver:
213   void DidFinishNavigation(
214       content::NavigationHandle* navigation_handle) override;
215   void OnVisibilityChanged(content::Visibility visibility) override;
216 
217  private:
218   friend class content::WebContentsUserData<ManagePasswordsUIController>;
219 
220   // PasswordsLeakDialogDelegate:
221   void NavigateToPasswordCheckup(
222       password_manager::PasswordCheckReferrer referrer) override;
223   void OnLeakDialogHidden() override;
224 
225   enum class BubbleStatus {
226     NOT_SHOWN,
227     // The bubble is to be popped up in the next call to
228     // UpdateBubbleAndIconVisibility().
229     SHOULD_POP_UP,
230     // The bubble is to be reopened after re-authentication.
231     SHOULD_POP_UP_AFTER_REAUTH,
232     SHOWN,
233     // Same as SHOWN but the icon is to be updated when the bubble is closed.
234     SHOWN_PENDING_ICON_UPDATE,
235   };
236 
IsShowingBubble()237   bool IsShowingBubble() const {
238     return bubble_status_ == BubbleStatus::SHOWN ||
239            bubble_status_ == BubbleStatus::SHOWN_PENDING_ICON_UPDATE;
240   }
241 
242   // Returns the timeout for the manual save fallback.
243   static base::TimeDelta GetTimeoutForSaveFallback();
244 
245   // Shows the password bubble without user interaction.
246   void ShowBubbleWithoutUserInteraction();
247 
248   // Resets |bubble_status_| signalling that if the bubble was due to pop up,
249   // it shouldn't anymore.
250   void ClearPopUpFlagForBubble();
251 
252   // Closes the account chooser gracefully so the callback is called. Then sets
253   // the state to MANAGE_STATE.
254   void DestroyAccountChooser();
255 
256   // content::WebContentsObserver:
257   void WebContentsDestroyed() override;
258 
259   // Requests authentication and reopens the bubble if the controller still
260   // exists and is in a pending state.
261   void RequestAuthenticationAndReopenBubble();
262 
263   // Re-opens the bubble. The password in the reopened bubble will be revealed
264   // if the authentication was successful.
265   void ReopenBubbleAfterAuth(bool auth_is_successful);
266 
267   // Shows an authentication dialog and returns true if auth is successful.
268   virtual bool ShowAuthenticationDialog();
269 
270   // Gets invoked gaia reauth flow is finished. If the reauth was successful,
271   // and the |form_manager| is still the same, |username| and |password| are
272   // saved against the current origin. If the reauth was unsuccessful, it
273   // changes the default destination to profle store and reopens the save
274   // bubble.
275   void FinishSavingPasswordAfterAccountStoreOptInAuth(
276       const url::Origin& origin,
277       password_manager::PasswordFormManagerForUI* form_manager,
278       const base::string16& username,
279       const base::string16& password,
280       password_manager::PasswordManagerClient::ReauthSucceeded
281           reauth_succeeded);
282 
283   void OnTriggerPostSaveCompromisedBubble(
284       password_manager::PostSaveCompromisedHelper::BubbleType type,
285       size_t count_compromised_passwords_);
286 
287   // Triggered from a reauthentication flow. If |form_manager| is still valid
288   // and the reauth was successful, the password is moved to the account store.
289   void FinishMovingPasswordAfterAccountStoreOptInAuth(
290       password_manager::PasswordFormManagerForUI* form_manager,
291       password_manager::PasswordManagerClient::ReauthSucceeded
292           reauth_succeeded);
293 
294   // Timeout in seconds for the manual fallback for saving.
295   static int save_fallback_timeout_in_seconds_;
296 
297   // The wrapper around current state and data.
298   ManagePasswordsState passwords_data_;
299 
300   // The controller for the blocking dialogs.
301   std::unique_ptr<PasswordBaseDialogController> dialog_controller_;
302 
303   // The helper to pop up a reminder about compromised passwords.
304   std::unique_ptr<password_manager::PostSaveCompromisedHelper>
305       post_save_compromised_helper_;
306 
307   BubbleStatus bubble_status_ = BubbleStatus::NOT_SHOWN;
308 
309   // The timer that controls whether the fallback for saving should be
310   // available. Should be reset once the fallback is not needed (an automatic
311   // popup will be shown or the user saved/updated the password with the
312   // fallback).
313   base::OneShotTimer save_fallback_timer_;
314 
315   // True iff bubble should pop up with revealed password value.
316   bool are_passwords_revealed_when_next_bubble_is_opened_;
317 
318   // The bubbles of different types can pop up unpredictably superseding each
319   // other. However, closing the bubble may affect the state of
320   // ManagePasswordsUIController internally. This is undesired if
321   // ManagePasswordsUIController is in the process of opening a new bubble. The
322   // situation is worse on Windows where the bubble is destroyed asynchronously.
323   // Thus, OnBubbleHidden() can be called after the new one is shown. By that
324   // time the internal state of ManagePasswordsUIController has nothing to do
325   // with the old bubble.
326   // Invalidating all the weak pointers will detach the current bubble.
327   base::WeakPtrFactory<ManagePasswordsUIController> weak_ptr_factory_{this};
328 
329   WEB_CONTENTS_USER_DATA_KEY_DECL();
330 
331   DISALLOW_COPY_AND_ASSIGN(ManagePasswordsUIController);
332 };
333 
334 #endif  // CHROME_BROWSER_UI_PASSWORDS_MANAGE_PASSWORDS_UI_CONTROLLER_H_
335