chromium/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate.h

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_TOUCH_TO_FILL_PASSWORD_MANAGER_TOUCH_TO_FILL_CONTROLLER_AUTOFILL_DELEGATE_H_
#define CHROME_BROWSER_TOUCH_TO_FILL_PASSWORD_MANAGER_TOUCH_TO_FILL_CONTROLLER_AUTOFILL_DELEGATE_H_

#include "base/containers/span.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/types/pass_key.h"
#include "base/types/strong_alias.h"
#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h"
#include "chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_delegate.h"
#include "components/autofill/core/common/unique_ids.h"
#include "components/device_reauth/device_authenticator.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "ui/gfx/native_widget_types.h"

namespace password_manager {
class PasskeyCredential;
class PasswordCredentialFiller;
class PasswordManagerClient;
class UiCredential;
class WebAuthnCredentialsDelegate;
}  // namespace password_manager

namespace content {
class WebContents;
}

class ChromePasswordManagerClient;
class TouchToFillController;
class Profile;

// Delegate interface for TouchToFillController being used in an autofill
// context.
class TouchToFillControllerAutofillDelegate
    : public TouchToFillControllerDelegate {
 public:
  using ShowHybridOption = base::StrongAlias<struct ShowHybridOptionTag, bool>;
  using ShowPasswordMigrationWarningCallback = base::RepeatingCallback<void(
      gfx::NativeWindow,
      Profile*,
      password_manager::metrics_util::PasswordMigrationWarningTriggers)>;
  using ShowDataLossWarningCallback = base::RepeatingCallback<void(void)>;

  // The action a user took when interacting with the Touch To Fill sheet.
  //
  // These values are persisted to logs. Entries should not be renumbered and
  // numeric values should never be reused. Needs to stay in sync with
  // TouchToFill.UserAction in enums.xml.
  //
  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.touch_to_fill
  enum class UserAction {
    kSelectedCredential = 0,
    kDismissed = 1,
    kSelectedManagePasswords = 2,
    kSelectedPasskeyCredential = 3,
    kSelectedHybrid = 4,
    kMaxValue = kSelectedHybrid,
  };

  // The final outcome that closes the Touch To Fill sheet.
  //
  // These values are persisted to logs. Entries should not be renumbered and
  // numeric values should never be reused. Needs to stay in sync with
  // TouchToFill.Outcome in enums.xml.
  enum class TouchToFillOutcome {
    kCredentialFilled = 0,
    kSheetDismissed = 1,
    kReauthenticationFailed = 2,
    kManagePasswordsSelected = 3,
    kPasskeyCredentialSelected = 4,
    kHybridSignInSelected = 5,
    kMaxValue = kHybridSignInSelected,
  };

  // No-op constructor for tests.
  TouchToFillControllerAutofillDelegate(
      base::PassKey<class TouchToFillControllerAutofillTest>,
      password_manager::PasswordManagerClient* password_client,
      content::WebContents* web_contents,
      std::unique_ptr<device_reauth::DeviceAuthenticator> authenticator,
      base::WeakPtr<password_manager::WebAuthnCredentialsDelegate>
          webauthn_delegate,
      std::unique_ptr<password_manager::PasswordCredentialFiller> filler,
      const password_manager::PasswordForm* form_to_fill,
      autofill::FieldRendererId focused_field_renderer_id,
      ShowHybridOption should_show_hybrid_option,
      ShowPasswordMigrationWarningCallback show_password_migration_warning,
      std::unique_ptr<PasswordAccessLossWarningBridge>
          data_loss_warning_bridge);

  TouchToFillControllerAutofillDelegate(
      ChromePasswordManagerClient* password_client,
      std::unique_ptr<device_reauth::DeviceAuthenticator> authenticator,
      base::WeakPtr<password_manager::WebAuthnCredentialsDelegate>
          webauthn_delegate,
      std::unique_ptr<password_manager::PasswordCredentialFiller> filler,
      const password_manager::PasswordForm* form_to_fill,
      autofill::FieldRendererId focused_field_renderer_id,
      ShowHybridOption should_show_hybrid_option);
  TouchToFillControllerAutofillDelegate(
      const TouchToFillControllerAutofillDelegate&) = delete;
  TouchToFillControllerAutofillDelegate& operator=(
      const TouchToFillControllerAutofillDelegate&) = delete;
  ~TouchToFillControllerAutofillDelegate() override;

  // TouchToFillControllerDelegate:
  void OnShow(base::span<const password_manager::UiCredential> credentials,
              base::span<password_manager::PasskeyCredential>
                  passkey_credentials) override;
  void OnCredentialSelected(const password_manager::UiCredential& credential,
                            base::OnceClosure action_completed) override;
  void OnPasskeyCredentialSelected(
      const password_manager::PasskeyCredential& credential,
      base::OnceClosure action_completed) override;
  void OnManagePasswordsSelected(bool passkeys_shown,
                                 base::OnceClosure action_completed) override;
  void OnHybridSignInSelected(base::OnceClosure action_completed) override;
  void OnDismiss(base::OnceClosure action_completed) override;
  void OnCredManDismissed(base::OnceClosure action_completed) override;
  GURL GetFrameUrl() override;
  bool ShouldShowTouchToFill() override;
  bool ShouldTriggerSubmission() override;
  bool ShouldShowHybridOption() override;
  bool ShouldShowNoPasskeysSheetIfRequired() override;
  gfx::NativeView GetNativeView() override;

 private:
  // Called after the biometric reauth completes. If `authSuccessful` is
  // true, `credential` will be filled into the form.
  void OnReauthCompleted(password_manager::UiCredential credential,
                         bool authSuccessful);

  // Fills the credential into the form.
  void FillCredential(const password_manager::UiCredential& credential);

  // Called upon completion or dismissal to perform cleanup.
  void CleanUpFillerAndReportOutcome(TouchToFillOutcome outcome,
                                     bool show_virtual_keyboard);

  void ShowPasswordMigrationWarningIfNeeded();

  // Callback to the controller to be invoked when a finalizing action has
  // completed. This will result in the destruction of the delegate so
  // no internal state should be touched after its invocation.
  base::OnceClosure action_complete_;

  // Weak pointer to the PasswordManagerClient this class is tied to.
  raw_ptr<password_manager::PasswordManagerClient> password_client_ = nullptr;

  raw_ptr<content::WebContents> web_contents_;

  // Authenticator used to trigger a biometric auth before filling.
  std::unique_ptr<device_reauth::DeviceAuthenticator> authenticator_;

  // Weak pointer to WebAuthnCredentialsDelegate to select passkeys or start
  // hybrid sign in.
  base::WeakPtr<password_manager::WebAuthnCredentialsDelegate>
      webauthn_delegate_;

  // PasswordCredentialFiller is used to interact with the PasswordManagerDriver
  // to fill the username and password. PasswordCredentialFiller also submits
  // the form if required.
  std::unique_ptr<password_manager::PasswordCredentialFiller> filler_;

  // The form which should be autofilled.
  raw_ptr<const password_manager::PasswordForm> form_to_fill_ = nullptr;

  autofill::FieldRendererId focused_field_renderer_id_;

  // Whether the controller should show an option for passkey hybrid sign-in.
  ShowHybridOption should_show_hybrid_option_ = ShowHybridOption(false);

  // Shows the password migration warning (expected to be shown after filling
  // user's credentials).
  ShowPasswordMigrationWarningCallback show_password_migration_warning_;

  // Bridge used to show the data loss warning (expected to be shown after
  // filling user's credentials).
  std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_warning_bridge_;

  ukm::SourceId source_id_ = ukm::kInvalidSourceId;
};

#endif  // CHROME_BROWSER_TOUCH_TO_FILL_PASSWORD_MANAGER_TOUCH_TO_FILL_CONTROLLER_AUTOFILL_DELEGATE_H_