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

#include "components/password_manager/content/browser/content_password_manager_driver.h"

#include <utility>

#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/task/sequenced_task_runner.h"
#include "components/autofill/content/browser/content_autofill_client.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/logging/log_router.h"
#include "components/autofill/core/common/aliases.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/unique_ids.h"
#include "components/password_manager/content/browser/bad_message.h"
#include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
#include "components/password_manager/content/browser/content_password_manager_util.h"
#include "components/password_manager/content/browser/form_meta_data.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
#include "components/password_manager/core/browser/features/password_features.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_metrics_recorder.h"
#include "components/password_manager/core/browser/password_suggestion_generator.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/safe_browsing/buildflags.h"
#include "content/public/browser/back_forward_cache.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/context_menu_params.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "mojo/public/cpp/bindings/message.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "ui/gfx/geometry/rect_f.h"

using autofill::mojom::FocusedFieldType;

namespace password_manager {

namespace {

void LogSiteIsolationMetricsForSubmittedForm(
    content::RenderFrameHost* render_frame_host) {
  UMA_HISTOGRAM_BOOLEAN(
      "SiteIsolation.IsPasswordFormSubmittedInDedicatedProcess",
      render_frame_host->GetSiteInstance()->RequiresDedicatedProcess());
}

}  // namespace

ContentPasswordManagerDriver::ContentPasswordManagerDriver(
    content::RenderFrameHost* render_frame_host,
    PasswordManagerClient* client)
    : render_frame_host_(render_frame_host),
      client_(client),
      password_generation_helper_(client, this),
      password_autofill_manager_(
          this,
          autofill::ContentAutofillClient::FromWebContents(
              content::WebContents::FromRenderFrameHost(render_frame_host)),
          client) {
  static DriverId::Generator id_generator;
  id_ = id_generator.GenerateNextId();

  render_frame_host_->GetRemoteAssociatedInterfaces()->GetInterface(
      &password_autofill_agent_);

  // For some frames `this` may be instantiated before log manager creation, so
  // here we can not send logging state to renderer process for them. For such
  // cases, after the log manager got ready later,
  // ContentPasswordManagerDriverFactory::RequestSendLoggingAvailability() will
  // call ContentPasswordManagerDriver::SendLoggingAvailability() on `this` to
  // do it actually.
  if (autofill::LogManager* log_manager = client_->GetCurrentLogManager()) {
    // RenderFrameHost might be a speculative one: it hasn't committed its
    // document. We don't know if its is safe to use the whole
    // PasswordAutofillAgent interface. For this reason, we use directly
    // `password_autofill_agent_`, as opposed to `GetPasswordAutofillAgent()`.
    // We know the `SetLoggingState()` is safe to be called no matter the state
    // of the RenderFrameHost.
    password_autofill_agent_->SetLoggingState(log_manager->IsLoggingActive());
  }
}

ContentPasswordManagerDriver::~ContentPasswordManagerDriver() = default;

// static
ContentPasswordManagerDriver*
ContentPasswordManagerDriver::GetForRenderFrameHost(
    content::RenderFrameHost* render_frame_host) {
  ContentPasswordManagerDriverFactory* factory =
      ContentPasswordManagerDriverFactory::FromWebContents(
          content::WebContents::FromRenderFrameHost(render_frame_host));
  return factory ? factory->GetDriverForFrame(
                       render_frame_host,
                       base::PassKey<ContentPasswordManagerDriver>())
                 : nullptr;
}

void ContentPasswordManagerDriver::BindPendingReceiver(
    mojo::PendingAssociatedReceiver<autofill::mojom::PasswordManagerDriver>
        pending_receiver) {
  if (IsRenderFrameHostSupported()) {
    password_manager_receiver_.Bind(std::move(pending_receiver));
  }
}

void ContentPasswordManagerDriver::DidNavigate() {
  if (!IsRenderFrameHostSupported()) {
    password_manager_receiver_.reset();
  }
}

bool ContentPasswordManagerDriver::HasValidURL(bool may_kill_renderer) {
  GURL url = GetURLFromRenderFrameHost(render_frame_host_);

  // URL might be invalid when GetLastCommittedOrigin is opaque.
  if (!url.is_valid()) {
    return false;
  }

  return password_manager::bad_message::CheckChildProcessSecurityPolicyForURL(
      render_frame_host_, url,
      password_manager::BadMessageReason::CPMD_BAD_ORIGIN_FORM_SUBMITTED,
      may_kill_renderer);
}

bool ContentPasswordManagerDriver::IsRenderFrameHostSupported() {
  if (render_frame_host_->GetProcess()->IsPdf()) {
    return false;
  }

  // Explanation of current PasswordManagerDriver limitations:
  // * Currently, PasswordManagerDriver binding has RenderFrameHost lifetime,
  //   not document lifetime. This can lead to premature binding in rare race
  //   conditions (see https://crbug.com/329989911).
  // * Due to this, we can't reliably determine if the document will be
  //   credentialless at this stage. Returning 'false' speculatively would be
  //   destructive.
  // * Workaround: Temporarily return 'true'; the function will be re-evaluated
  //   on commit via `DidNavigate`.
  //
  // TODO(https://crbug.com/40615943): After RenderDocument is enabled, consider
  // simplifying by binding PasswordManagerDriver via `PopulateFrameBinders`
  // instead of `RegisterAssociatedInterfaceBindersForRenderFrameHost`.
  if (render_frame_host_->GetLifecycleState() ==
      content::RenderFrameHost::LifecycleState::kPendingCommit) {
    return true;
  }

  if (render_frame_host_->GetLifecycleState() ==
      content::RenderFrameHost::LifecycleState::kPrerendering) {
    return false;
  }

  // [spec] https://wicg.github.io/anonymous-iframe/#spec-autofill
  // > Browsers that implement autofill or password manager functionalities
  //   should make them unavailable in credentialless iframes.
  if (render_frame_host_->IsCredentialless()) {
    return false;
  }

  return true;
}

DriverId ContentPasswordManagerDriver::GetId() const {
  return id_;
}

int ContentPasswordManagerDriver::GetFrameId() const {
  // Use the associated FrameTreeNode ID as the Frame ID.
  return render_frame_host_->GetFrameTreeNodeId().value();
}

gfx::RectF ContentPasswordManagerDriver::TransformToRootCoordinates(
    const gfx::RectF& bounds_in_frame_coordinates) {
  content::RenderWidgetHostView* rwhv = render_frame_host_->GetView();
  if (!rwhv) {
    return bounds_in_frame_coordinates;
  }
  return gfx::RectF(rwhv->TransformPointToRootCoordSpaceF(
                        bounds_in_frame_coordinates.origin()),
                    bounds_in_frame_coordinates.size());
}

void ContentPasswordManagerDriver::PropagateFillDataOnParsingCompletion(
    const autofill::PasswordFormFillData& form_data) {
  if (base::FeatureList::IsEnabled(
          features::kCallOnAddPasswordFillDataAsynchronously)) {
    // This asynchronous call is to avoid reentrant AutofillManager::Observer
    // calls. See crbug.com/500883329 for details.
    // While PasswordAutofillAgent::ApplyFillDataOnParsingCompletion() may call
    // back into the browser process, those Mojo events are processed after this
    // posted task.
    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(&PasswordAutofillManager::OnAddPasswordFillData,
                       password_autofill_manager_.GetWeakPtr(), form_data));
  } else {
    password_autofill_manager_.OnAddPasswordFillData(form_data);
  }
  if (const auto& agent = GetPasswordAutofillAgent()) {
    agent->ApplyFillDataOnParsingCompletion(
        autofill::MaybeClearPasswordValues(form_data));
  }
}

void ContentPasswordManagerDriver::InformNoSavedCredentials(
    bool should_show_popup_without_passwords) {
  if (const auto& agent = GetPasswordAutofillAgent()) {
    agent->InformNoSavedCredentials(should_show_popup_without_passwords);
  }
}

void ContentPasswordManagerDriver::FormEligibleForGenerationFound(
    const autofill::PasswordFormGenerationData& form) {
  if (GetPasswordGenerationHelper()->IsGenerationEnabled(
          /*log_debug_data=*/true)) {
    GetPasswordGenerationAgent()->FoundFormEligibleForGeneration(form);
  }
}

void ContentPasswordManagerDriver::GeneratedPasswordAccepted(
    const std::u16string& password) {
  // Same check as in PasswordGenerationAgent::GeneratedPasswordAccepted. The
  // generated password can't be too short.
  CHECK_LE(4u, password.size());
  GetPasswordGenerationAgent()->GeneratedPasswordAccepted(password);
}

void ContentPasswordManagerDriver::GeneratedPasswordAccepted(
    const autofill::FormData& raw_form,
    autofill::FieldRendererId generation_element_id,
    const std::u16string& password) {
  // In case we can't obtain a valid URL or a frame isn't allowed to perform an
  // operation with generated URL, don't forward anything to password manager.
  // TODO(crbug.com/40191770): Test that PasswordManager doesn't receive url
  // and full_url from renderer.
  if (!HasValidURL(/*may_kill_renderer=*/true)) {
    return;
  }

  GetPasswordManager()->OnGeneratedPasswordAccepted(
      this, GetFormWithFrameAndFormMetaData(render_frame_host_, raw_form),
      generation_element_id, password);
}

void ContentPasswordManagerDriver::GeneratedPasswordRejected() {
  GetPasswordGenerationAgent()->GeneratedPasswordRejected();
}

void ContentPasswordManagerDriver::FocusNextFieldAfterPasswords() {
  GetPasswordGenerationAgent()->FocusNextFieldAfterPasswords();
}

void ContentPasswordManagerDriver::FillField(
    autofill::FieldRendererId triggering_field_id,
    const std::u16string& value,
    autofill::FieldPropertiesFlags field_flags,
    base::OnceCallback<void(bool)> success_callback) {
  if (const auto& agent = GetPasswordAutofillAgent()) {
    agent->FillField(triggering_field_id, value, field_flags,
                     std::move(success_callback));
  }
}

void ContentPasswordManagerDriver::TriggerPasswordRecoverySuggestions(
    autofill::FieldRendererId field_id) {
  autofill::AutofillDriver* autofill_driver =
      autofill::ContentAutofillDriver::GetForRenderFrameHost(
          render_frame_host_);
  if (!autofill_driver) {
    return;
  }
  autofill_driver->RendererShouldTriggerSuggestions(
      /*field_id=*/{.frame_token = autofill_driver->GetFrameToken(),
                    .renderer_id = field_id},
      autofill::AutofillSuggestionTriggerSource::kProactivePasswordRecovery);
}

void ContentPasswordManagerDriver::FillChangePasswordForm(
    autofill::FieldRendererId password_element_id,
    autofill::FieldRendererId new_password_element_id,
    autofill::FieldRendererId confirm_password_element_id,
    const std::u16string& old_password,
    const std::u16string& new_password,
    base::OnceCallback<void(const std::optional<autofill::FormData>&)>
        form_data_callback) {
  if (const auto& agent = GetPasswordAutofillAgent()) {
    agent->FillChangePasswordForm(
        password_element_id, new_password_element_id,
        confirm_password_element_id, old_password, new_password,
        base::BindOnce(
            &ContentPasswordManagerDriver::OnChangePasswordFormFilled,
            weak_factory_.GetWeakPtr(), std::move(form_data_callback)));
  }
}

void ContentPasswordManagerDriver::FillSuggestion(
    const std::u16string& username,
    const std::u16string& password,
    base::OnceCallback<void(bool)> success_callback) {
  GetPasswordAutofillAgent()->FillPasswordSuggestion(
      username, password, std::move(success_callback));
}

void ContentPasswordManagerDriver::FillSuggestionById(
    autofill::FieldRendererId username_element_id,
    autofill::FieldRendererId password_element_id,
    const std::u16string& username,
    const std::u16string& password,
    autofill::AutofillSuggestionTriggerSource suggestion_source) {
  GetPasswordAutofillAgent()->FillPasswordSuggestionById(
      username_element_id, password_element_id, username, password,
      suggestion_source);
}

void ContentPasswordManagerDriver::FillIntoFocusedField(
    bool is_password,
    const std::u16string& credential) {
  if (const auto& agent = GetPasswordAutofillAgent()) {
    agent->FillIntoFocusedField(is_password, credential);
  }
}

#if BUILDFLAG(IS_ANDROID)
void ContentPasswordManagerDriver::TriggerFormSubmission() {
  GetPasswordAutofillAgent()->TriggerFormSubmission();
}
#endif

void ContentPasswordManagerDriver::PreviewField(
    autofill::FieldRendererId field_id,
    const std::u16string& value) {
  if (const auto& agent = GetPasswordAutofillAgent()) {
    agent->PreviewField(field_id, value);
  }
}

void ContentPasswordManagerDriver::PreviewSuggestion(
    const std::u16string& username,
    const std::u16string& password) {
  GetAutofillAgent()->PreviewPasswordSuggestion(username, password);
}

void ContentPasswordManagerDriver::PreviewSuggestionById(
    autofill::FieldRendererId username_element_id,
    autofill::FieldRendererId password_element_id,
    const std::u16string& username,
    const std::u16string& password) {
  GetPasswordAutofillAgent()->PreviewPasswordSuggestionById(
      username_element_id, password_element_id, username, password);
}

void ContentPasswordManagerDriver::PreviewGenerationSuggestion(
    const std::u16string& password) {
  GetAutofillAgent()->PreviewPasswordGenerationSuggestion(password);
}

void ContentPasswordManagerDriver::ClearPreviewedForm() {
  GetAutofillAgent()->ClearPreviewedForm();
}

void ContentPasswordManagerDriver::SetSuggestionAvailability(
    autofill::FieldRendererId element_id,
    autofill::mojom::AutofillSuggestionAvailability suggestion_availability) {
  GetAutofillAgent()->SetSuggestionAvailability(element_id,
                                                suggestion_availability);
}

PasswordGenerationFrameHelper*
ContentPasswordManagerDriver::GetPasswordGenerationHelper() {
  return &password_generation_helper_;
}

PasswordManagerInterface* ContentPasswordManagerDriver::GetPasswordManager() {
  return client_->GetPasswordManager();
}

PasswordAutofillManager*
ContentPasswordManagerDriver::GetPasswordAutofillManager() {
  return &password_autofill_manager_;
}

autofill::PasswordManagerDelegate*
ContentPasswordManagerDriver::GetPasswordManagerDelegate() {
  return &password_autofill_manager_;
}

void ContentPasswordManagerDriver::SendLoggingAvailability() {
  if (const auto& agent = GetPasswordAutofillAgent()) {
    autofill::LogManager* log_manager = client_->GetCurrentLogManager();
    agent->SetLoggingState(log_manager && log_manager->IsLoggingActive());
  }
}

bool ContentPasswordManagerDriver::IsInPrimaryMainFrame() const {
  return render_frame_host_->IsInPrimaryMainFrame();
}

bool ContentPasswordManagerDriver::IsNestedWithinFencedFrame() const {
  return render_frame_host_->IsNestedWithinFencedFrame();
}

bool ContentPasswordManagerDriver::IsDirectChildOfPrimaryMainFrame() const {
  // If it has no parent, returns `false` by default.
  if (!render_frame_host_->GetParent()) {
    return false;
  }
  return render_frame_host_->GetParent()->IsInPrimaryMainFrame();
}

bool ContentPasswordManagerDriver::CanShowAutofillUi() const {
  // Don't show AutofillUi for inactive RenderFrameHost.
  return render_frame_host_->IsActive();
}

const GURL& ContentPasswordManagerDriver::GetLastCommittedURL() const {
  return render_frame_host_->GetLastCommittedURL();
}

const url::Origin& ContentPasswordManagerDriver::GetLastCommittedOrigin()
    const {
  return render_frame_host_->GetLastCommittedOrigin();
}

bool ContentPasswordManagerDriver::HasCrossOriginAncestor() const {
  content::RenderFrameHost* parent =
      render_frame_host_->GetParentOrOuterDocument();
  const url::Origin& target_origin =
      render_frame_host_->GetLastCommittedOrigin();
  while (parent) {
    if (!parent->GetLastCommittedOrigin().IsSameOriginWith(target_origin)) {
      return true;
    }
    parent = parent->GetParentOrOuterDocument();
  }
  return false;
}

void ContentPasswordManagerDriver::CheckViewAreaVisible(
    autofill::FieldRendererId field_id,
    base::OnceCallback<void(bool)> callback) {
  if (const auto& agent = GetPasswordAutofillAgent()) {
    agent->CheckViewAreaVisible(field_id, std::move(callback));
  }
}

autofill::AutofillDriver* ContentPasswordManagerDriver::GetAutofillDriver()
    const {
  return autofill::ContentAutofillDriver::GetForRenderFrameHost(
      render_frame_host());
}

void ContentPasswordManagerDriver::AnnotateFieldsWithParsingResult(
    const autofill::ParsingResult& parsing_result) {
  if (const auto& agent = GetPasswordAutofillAgent()) {
    agent->AnnotateFieldsWithParsingResult(parsing_result);
  }
}

base::WeakPtr<password_manager::PasswordManagerDriver>
ContentPasswordManagerDriver::AsWeakPtr() {
  return weak_factory_.GetWeakPtr();
}

void ContentPasswordManagerDriver::GeneratePassword(
    autofill::mojom::PasswordGenerationAgent::TriggeredGeneratePasswordCallback
        callback) {
  GetPasswordGenerationAgent()->TriggeredGeneratePassword(std::move(callback));
}

bool ContentPasswordManagerDriver::IsPasswordFieldForPasswordManager(
    autofill::FieldRendererId field_renderer_id,
    std::optional<blink::mojom::FormControlType> form_control_type) {
  if (form_control_type == blink::mojom::FormControlType::kInputPassword) {
    return true;
  }
  password_manager::PasswordGenerationFrameHelper*
      password_generation_frame_helper = GetPasswordGenerationHelper();
  if (!password_generation_frame_helper) {
    return false;
  }
  return password_generation_frame_helper->IsManualGenerationEnabledField(
      field_renderer_id);
}

void ContentPasswordManagerDriver::PasswordFormsParsed(
    const std::vector<autofill::FormData>& raw_forms) {
  if (!CheckFrameActiveAndNotPrerendering(render_frame_host_)) {
    return;
  }

  // In case we can't obtain a valid URL or a frame isn't allowed to perform an
  // operation with generated URL, don't forward anything to password manager.
  if (!HasValidURL(/*may_kill_renderer=*/true)) {
    return;
  }

  autofill::LogManager* log_manager = client_->GetCurrentLogManager();
  std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
  if (log_manager && log_manager->IsLoggingActive()) {
    logger = std::make_unique<BrowserSavePasswordProgressLogger>(log_manager);
  }
  std::vector<autofill::FormData> forms = raw_forms;
  for (auto& form : forms) {
    SetFrameAndFormMetaData(render_frame_host_, form);
    if (logger) {
      logger->LogFormData(
          BrowserSavePasswordProgressLogger::STRING_FORM_IS_PASSWORD, form);
    }
  }

  GetPasswordManager()->OnPasswordFormsParsed(this, forms);
}

void ContentPasswordManagerDriver::PasswordFormsRendered(
    const std::vector<autofill::FormData>& raw_forms) {
  if (!CheckFrameActiveAndNotPrerendering(render_frame_host_)) {
    return;
  }

  // In case we can't obtain a valid URL or a frame isn't allowed to perform an
  // operation with generated URL, don't forward anything to password manager.
  if (!HasValidURL(/*may_kill_renderer=*/true)) {
    return;
  }

  std::vector<autofill::FormData> forms = raw_forms;
  for (auto& form : forms)
    SetFrameAndFormMetaData(render_frame_host_, form);

  GetPasswordManager()->OnPasswordFormsRendered(this, forms);
}

void ContentPasswordManagerDriver::PasswordFormSubmitted(
    const autofill::FormData& raw_form) {
  // Don't check IsActive(): the submitting frame may have entered BFCache.
  if (!password_manager::bad_message::CheckFrameNotPrerendering(
          render_frame_host_)) {
    return;
  }

  // In case we can't obtain a valid URL or a frame isn't allowed to perform an
  // operation with generated URL, don't forward anything to password manager.
  if (!HasValidURL(/*may_kill_renderer=*/true)) {
    return;
  }

  GetPasswordManager()->OnPasswordFormSubmitted(
      this, GetFormWithFrameAndFormMetaData(render_frame_host_, raw_form));

  LogSiteIsolationMetricsForSubmittedForm(render_frame_host_);
}

void ContentPasswordManagerDriver::InformAboutUserInput(
    const autofill::FormData& raw_form) {
  if (!CheckFrameActiveAndNotPrerendering(render_frame_host_)) {
    return;
  }

  // In case we can't obtain a valid URL or a frame isn't allowed to perform an
  // operation with generated URL, don't forward anything to password manager.
  // TODO(crbug.com/40191770): Test that PasswordManager doesn't receive url
  // and full_url from renderer.
  if (!HasValidURL(/*may_kill_renderer=*/true)) {
    return;
  }

  autofill::FormData form_data =
      GetFormWithFrameAndFormMetaData(render_frame_host_, raw_form);
  GetPasswordManager()->OnInformAboutUserInput(this, form_data);

  if (FormHasNonEmptyPasswordField(form_data) &&
      client_->IsIsolationForPasswordSitesEnabled()) {
    // This function signals that a password field has been filled (whether by
    // the user, JS, autofill, or some other means) or a password form has been
    // submitted. Use this as a heuristic to start site-isolating the form's
    // site. This is intended to be used primarily when full site isolation is
    // not used, such as on Android.
    content::SiteInstance::StartIsolatingSite(
        render_frame_host_->GetSiteInstance()->GetBrowserContext(),
        form_data.url(),
        content::ChildProcessSecurityPolicy::IsolatedOriginSource::
            USER_TRIGGERED);
  }
}

void ContentPasswordManagerDriver::DynamicFormSubmission(
    autofill::mojom::SubmissionIndicatorEvent submission_indication_event) {
  // Don't check IsActive(): the submitting frame may have entered BFCache.
  if (!password_manager::bad_message::CheckFrameNotPrerendering(
          render_frame_host_)) {
    return;
  }
  GetPasswordManager()->OnDynamicFormSubmission(this,
                                                submission_indication_event);
  LogSiteIsolationMetricsForSubmittedForm(render_frame_host_);
}

void ContentPasswordManagerDriver::PasswordFormCleared(
    const autofill::FormData& raw_form) {
  if (!CheckFrameActiveAndNotPrerendering(render_frame_host_)) {
    return;
  }

  // In case we can't obtain a valid URL or a frame isn't allowed to perform an
  // operation with generated URL, don't forward anything to password manager.
  if (!HasValidURL(/*may_kill_renderer=*/true)) {
    return;
  }

  GetPasswordManager()->OnPasswordFormCleared(
      this, GetFormWithFrameAndFormMetaData(render_frame_host_, raw_form));
}

void ContentPasswordManagerDriver::RecordSavePasswordProgress(
    const std::string& log) {
  if (!CheckFrameActiveAndNotPrerendering(render_frame_host_)) {
    return;
  }
  // Skip messages from chrome:// URLs as they are just noise for
  // chrome://password-manager-internals based debugging.
  if (GetLastCommittedURL().SchemeIs(content::kChromeUIScheme))
    return;
  LOG_AF(client_->GetCurrentLogManager())
      << autofill::Tag{"div"}
      << autofill::Attrib{"class", "preserve-white-space"} << log
      << autofill::CTag{"div"};
}

void ContentPasswordManagerDriver::UserModifiedPasswordField() {
  if (!CheckFrameActiveAndNotPrerendering(render_frame_host_)) {
    return;
  }
  if (client_->GetMetricsRecorder())
    client_->GetMetricsRecorder()->RecordUserModifiedPasswordField();
  // A user has modified an input field, it wouldn't be a submission "after
  // Touch To Fill".
  client_->ResetSubmissionTrackingAfterTouchToFill();
}

void ContentPasswordManagerDriver::UserModifiedNonPasswordField(
    autofill::FieldRendererId renderer_id,
    const std::u16string& value,
    bool autocomplete_attribute_has_username,
    bool is_likely_otp) {
  if (!CheckFrameActiveAndNotPrerendering(render_frame_host_)) {
    return;
  }
  GetPasswordManager()->OnUserModifiedNonPasswordField(
      this, renderer_id, value, autocomplete_attribute_has_username,
      is_likely_otp);
  // A user has modified an input field, it wouldn't be a submission "after
  // Touch To Fill".
  client_->ResetSubmissionTrackingAfterTouchToFill();
}

void ContentPasswordManagerDriver::CheckSafeBrowsingReputation(
    const GURL& form_action,
    const GURL& frame_url) {
  if (!CheckFrameActiveAndNotPrerendering(render_frame_host_)) {
    return;
  }
#if defined(ON_FOCUS_PING_ENABLED) && BUILDFLAG(SAFE_BROWSING_AVAILABLE)
  client_->CheckSafeBrowsingReputation(form_action, frame_url);
#endif
}

void ContentPasswordManagerDriver::FocusedInputChanged(
    autofill::FieldRendererId focused_field_id,
    FocusedFieldType focused_field_type) {
  if (!CheckFrameActiveAndNotPrerendering(render_frame_host_)) {
    return;
  }
  GetPasswordAutofillManager()->FocusedInputChanged();
  client_->FocusedInputChanged(this, focused_field_id, focused_field_type);
}

void ContentPasswordManagerDriver::LogFirstFillingResult(
    autofill::FormRendererId form_renderer_id,
    int32_t result) {
  if (!CheckFrameActiveAndNotPrerendering(render_frame_host_)) {
    return;
  }
  GetPasswordManager()->LogFirstFillingResult(this, form_renderer_id, result);
}

const mojo::AssociatedRemote<autofill::mojom::AutofillAgent>&
ContentPasswordManagerDriver::GetAutofillAgent() {
  autofill::ContentAutofillDriver* autofill_driver =
      autofill::ContentAutofillDriver::GetForRenderFrameHost(
          render_frame_host_);
  DCHECK(autofill_driver);
  return autofill_driver->GetAutofillAgent(/*pass_key=*/{});
}

const mojo::AssociatedRemote<autofill::mojom::PasswordAutofillAgent>&
ContentPasswordManagerDriver::GetPasswordAutofillAgent() {
  // Autofill is not expected to interact with a RenderFrameHost that hasn't yet
  // committed its document.
  CHECK_NE(render_frame_host_->GetLifecycleState(),
           content::RenderFrameHost::LifecycleState::kPendingCommit);

  return IsRenderFrameHostSupported() ? password_autofill_agent_
                                      : password_autofill_agent_unbound_;
}

const mojo::AssociatedRemote<autofill::mojom::PasswordGenerationAgent>&
ContentPasswordManagerDriver::GetPasswordGenerationAgent() {
  DCHECK(!password_gen_agent_ ||
         (content::RenderFrameHost::LifecycleState::kPrerendering !=
          render_frame_host_->GetLifecycleState()));
  if (!password_gen_agent_) {
    render_frame_host_->GetRemoteAssociatedInterfaces()->GetInterface(
        &password_gen_agent_);
  }

  return password_gen_agent_;
}

void ContentPasswordManagerDriver::OnChangePasswordFormFilled(
    base::OnceCallback<void(const std::optional<autofill::FormData>&)>
        form_data_callback,
    const std::optional<autofill::FormData>& raw_form) {
  if (!CheckFrameActiveAndNotPrerendering(render_frame_host_)) {
    return;
  }

  // In case we can't obtain a valid URL or a frame isn't allowed to perform an
  // operation with generated URL, don't forward anything to password manager.
  if (!HasValidURL(/*may_kill_renderer=*/true)) {
    return;
  }
  std::move(form_data_callback)
      .Run(raw_form ? GetFormWithFrameAndFormMetaData(render_frame_host_,
                                                      raw_form.value())
                    : raw_form);
}

}  // namespace password_manager
