blob: de6277c83cc0320dfdeb4504a024e9501400bf6d [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
#include <memory>
#include <vector>
#include "base/macros.h"
#include "chrome/browser/ui/passwords/manage_passwords_state.h"
#include "chrome/browser/ui/passwords/passwords_client_ui_delegate.h"
#include "chrome/browser/ui/passwords/passwords_model_delegate.h"
#include "chrome/common/buildflags.h"
#include "components/password_manager/core/browser/password_store.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
namespace base {
class TimeDelta;
namespace content {
class WebContents;
namespace password_manager {
enum class CredentialType;
struct InteractionsStats;
class PasswordFormManagerForUI;
class AccountChooserPrompt;
struct AccountInfo;
class AutoSigninFirstRunPrompt;
class ManagePasswordsIconView;
class PasswordDialogController;
class PasswordDialogControllerImpl;
// Per-tab class to control the Omnibox password icon and bubble.
class ManagePasswordsUIController
: public content::WebContentsObserver,
public content::WebContentsUserData<ManagePasswordsUIController>,
public password_manager::PasswordStore::Observer,
public PasswordsModelDelegate,
public PasswordsClientUIDelegate {
~ManagePasswordsUIController() override;
#if defined(UNIT_TEST)
static void set_save_fallback_timeout_in_seconds(int timeout) {
save_fallback_timeout_in_seconds_ = timeout;
// PasswordsClientUIDelegate:
void OnPasswordSubmitted(
std::unique_ptr<password_manager::PasswordFormManagerForUI> form_manager)
void OnUpdatePasswordSubmitted(
std::unique_ptr<password_manager::PasswordFormManagerForUI> form_manager)
void OnShowManualFallbackForSaving(
std::unique_ptr<password_manager::PasswordFormManagerForUI> form_manager,
bool has_generated_password,
bool is_update) override;
void OnHideManualFallbackForSaving() override;
bool OnChooseCredentials(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_credentials,
const GURL& origin,
const ManagePasswordsState::CredentialsCallback& callback) override;
void OnAutoSignin(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
const GURL& origin) override;
void OnPromptEnableAutoSignin() override;
void OnAutomaticPasswordSave(
std::unique_ptr<password_manager::PasswordFormManagerForUI> form_manager)
void OnPasswordAutofilled(
const std::map<base::string16, const autofill::PasswordForm*>&
const GURL& origin,
const std::vector<const autofill::PasswordForm*>* federated_matches)
// PasswordStore::Observer:
void OnLoginsChanged(
const password_manager::PasswordStoreChangeList& changes) override;
// Set the state of the Omnibox icon, and possibly show the associated bubble
// without user interaction.
virtual void UpdateIconAndBubbleState(ManagePasswordsIconView* icon);
// True iff the bubble is to be opened automatically.
bool IsAutomaticallyOpeningBubble() const {
return bubble_status_ == SHOULD_POP_UP;
base::WeakPtr<PasswordsModelDelegate> GetModelDelegateProxy();
// PasswordsModelDelegate:
content::WebContents* GetWebContents() const override;
const GURL& GetOrigin() const override;
GetPasswordFormMetricsRecorder() override;
password_manager::ui::State GetState() const override;
const autofill::PasswordForm& GetPendingPassword() const override;
password_manager::metrics_util::CredentialSourceType GetCredentialSource()
const override;
const std::vector<std::unique_ptr<autofill::PasswordForm>>& GetCurrentForms()
const override;
const password_manager::InteractionsStats* GetCurrentInteractionStats()
const override;
bool BubbleIsManualFallbackForSaving() const override;
void OnBubbleShown() override;
void OnBubbleHidden() override;
void OnNoInteraction() override;
void OnNopeUpdateClicked() override;
void NeverSavePassword() override;
void OnPasswordsRevealed() override;
void SavePassword(const base::string16& username,
const base::string16& password) override;
void ChooseCredential(
const autofill::PasswordForm& form,
password_manager::CredentialType credential_type) override;
void NavigateToPasswordManagerAccountDashboard() override;
void NavigateToPasswordManagerSettingsPage() override;
void EnableSync(const AccountInfo& account,
bool is_default_promo_account) override;
void OnDialogHidden() override;
bool AuthenticateUser() override;
bool ArePasswordsRevealedWhenBubbleIsOpened() const override;
#if defined(UNIT_TEST)
// Overwrites the client for |passwords_data_|.
void set_client(password_manager::PasswordManagerClient* client) {
#endif // defined(UNIT_TEST)
explicit ManagePasswordsUIController(
content::WebContents* web_contents);
// The pieces of saving and blacklisting passwords that interact with
// FormManager, split off into internal functions for testing/mocking.
virtual void SavePasswordInternal();
virtual void NeverSavePasswordInternal();
// Called when a PasswordForm is autofilled, when a new PasswordForm is
// submitted, or when a navigation occurs to update the visibility of the
// manage passwords icon and bubble.
virtual void UpdateBubbleAndIconVisibility();
// Called to create the account chooser dialog. Mocked in tests.
virtual AccountChooserPrompt* CreateAccountChooser(
PasswordDialogController* controller);
// Called to create the account chooser dialog. Mocked in tests.
virtual AutoSigninFirstRunPrompt* CreateAutoSigninPrompt(
PasswordDialogController* controller);
// Check if |web_contents()| is attached to some Browser. Mocked in tests.
virtual bool HasBrowserWindow() const;
// True if the bubble is to be opened automatically or after re-auth.
bool ShouldBubblePopUp() const {
return IsAutomaticallyOpeningBubble() ||
bubble_status_ == SHOULD_POP_UP_AFTER_REAUTH;
// Returns whether the bubble is currently open.
bool IsShowingBubbleForTest() const {
return bubble_status_ != BubbleStatus::NOT_SHOWN;
// content::WebContentsObserver:
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
void OnVisibilityChanged(content::Visibility visibility) override;
friend class content::WebContentsUserData<ManagePasswordsUIController>;
enum BubbleStatus {
// The bubble is to be popped up in the next call to
// UpdateBubbleAndIconVisibility().
// The bubble is to be reopened after re-authentication.
// Same as SHOWN but the icon is to be updated when the bubble is closed.
// Returns the timeout for the manual save fallback.
static base::TimeDelta GetTimeoutForSaveFallback();
// Shows the password bubble without user interaction.
void ShowBubbleWithoutUserInteraction();
// Resets |bubble_status_| signalling that if the bubble was due to pop up,
// it shouldn't anymore.
void ClearPopUpFlagForBubble();
// Closes the account chooser gracefully so the callback is called. Then sets
// the state to MANAGE_STATE.
void DestroyAccountChooser();
// content::WebContentsObserver:
void WebContentsDestroyed() override;
// Requests authentication and reopens the bubble if the controller still
// exists and is in a pending state.
void RequestAuthenticationAndReopenBubble();
// Re-opens the bubble. The password in the reopened bubble will be revealed
// if the authentication was successful.
void ReopenBubbleAfterAuth(bool auth_is_successful);
// Shows an authentication dialog and returns true if auth is successful.
virtual bool ShowAuthenticationDialog();
// Timeout in seconds for the manual fallback for saving.
static int save_fallback_timeout_in_seconds_;
// The wrapper around current state and data.
ManagePasswordsState passwords_data_;
// The controller for the blocking dialogs.
std::unique_ptr<PasswordDialogControllerImpl> dialog_controller_;
BubbleStatus bubble_status_;
// The timer that controls whether the fallback for saving should be
// available. Should be reset once the fallback is not needed (an automatic
// popup will be shown or the user saved/updated the password with the
// fallback).
base::OneShotTimer save_fallback_timer_;
// True iff bubble should pop up with revealed password value.
bool are_passwords_revealed_when_next_bubble_is_opened_;
// The bubbles of different types can pop up unpredictably superseding each
// other. However, closing the bubble may affect the state of
// ManagePasswordsUIController internally. This is undesired if
// ManagePasswordsUIController is in the process of opening a new bubble. The
// situation is worse on Windows where the bubble is destroyed asynchronously.
// Thus, OnBubbleHidden() can be called after the new one is shown. By that
// time the internal state of ManagePasswordsUIController has nothing to do
// with the old bubble.
// Invalidating all the weak pointers will detach the current bubble.
base::WeakPtrFactory<ManagePasswordsUIController> weak_ptr_factory_;