blob: b71d5476e008422741891432ce32f2679998e62c [file] [log] [blame]
// 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/functional/callback.h"
#include "base/metrics/histogram_macros.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/common/form_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/form_meta_data.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/safe_browsing/buildflags.h"
#include "content/public/browser/back_forward_cache.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/page.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "net/cert/cert_status_flags.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "ui/base/page_transition_types.h"
using autofill::mojom::FocusedFieldType;
namespace password_manager {
namespace {
gfx::RectF TransformToRootCoordinates(
content::RenderFrameHost* render_frame_host,
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 LogSiteIsolationMetricsForSubmittedForm(
content::RenderFrameHost* render_frame_host) {
UMA_HISTOGRAM_BOOLEAN(
"SiteIsolation.IsPasswordFormSubmittedInDedicatedProcess",
render_frame_host->GetSiteInstance()->RequiresDedicatedProcess());
}
bool HasValidURL(content::RenderFrameHost* render_frame_host) {
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);
}
} // namespace
ContentPasswordManagerDriver::ContentPasswordManagerDriver(
content::RenderFrameHost* render_frame_host,
PasswordManagerClient* client,
autofill::AutofillClient* autofill_client)
: render_frame_host_(render_frame_host),
client_(client),
password_generation_helper_(client, this),
password_autofill_manager_(this, autofill_client, client),
password_manager_receiver_(this) {
static unsigned next_free_id = 0;
id_ = next_free_id++;
// 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 (client_->GetLogManager()) {
if (const auto& agent = GetPasswordAutofillAgent()) {
// Do not call the virtual method SendLoggingAvailability from a
// constructor here, inline its steps instead.
agent->SetLoggingState(client_->GetLogManager()->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) : nullptr;
}
void ContentPasswordManagerDriver::BindPendingReceiver(
mojo::PendingAssociatedReceiver<autofill::mojom::PasswordManagerDriver>
pending_receiver) {
if (render_frame_host_->IsCredentialless())
return;
password_manager_receiver_.Bind(std::move(pending_receiver));
}
void ContentPasswordManagerDriver::UnbindReceiver() {
password_manager_receiver_.reset();
}
int ContentPasswordManagerDriver::GetId() const {
return id_;
}
int ContentPasswordManagerDriver::GetFrameId() const {
// Use the associated FrameTreeNode ID as the Frame ID.
return render_frame_host_->GetFrameTreeNodeId();
}
void ContentPasswordManagerDriver::SetPasswordFillData(
const autofill::PasswordFormFillData& form_data) {
password_autofill_manager_.OnAddPasswordFillData(form_data);
if (const auto& agent = GetPasswordAutofillAgent()) {
agent->SetPasswordFillData(autofill::MaybeClearPasswordValues(form_data));
}
}
void ContentPasswordManagerDriver::InformNoSavedCredentials(
bool should_show_popup_without_passwords) {
GetPasswordAutofillManager()->OnNoCredentialsFound();
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) {
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/1233990): Test that PasswordManager doesn't receive url
// and full_url from renderer.
if (!HasValidURL(render_frame_host_))
return;
GetPasswordManager()->OnGeneratedPasswordAccepted(
this, GetFormWithFrameAndFormMetaData(render_frame_host_, raw_form),
generation_element_id, password);
}
void ContentPasswordManagerDriver::FillSuggestion(
const std::u16string& username,
const std::u16string& password) {
GetAutofillAgent()->FillPasswordSuggestion(username, password);
}
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::TouchToFillClosed(
ShowVirtualKeyboard show_virtual_keyboard) {
GetPasswordAutofillAgent()->TouchToFillClosed(show_virtual_keyboard.value());
}
void ContentPasswordManagerDriver::TriggerFormSubmission() {
GetPasswordAutofillAgent()->TriggerFormSubmission();
}
#endif
void ContentPasswordManagerDriver::PreviewSuggestion(
const std::u16string& username,
const std::u16string& password) {
GetAutofillAgent()->PreviewPasswordSuggestion(username, password);
}
void ContentPasswordManagerDriver::PreviewGenerationSuggestion(
const std::u16string& password) {
GetAutofillAgent()->PreviewPasswordGenerationSuggestion(password);
}
void ContentPasswordManagerDriver::ClearPreviewedForm() {
GetAutofillAgent()->ClearPreviewedForm();
}
void ContentPasswordManagerDriver::SetSuggestionAvailability(
autofill::FieldRendererId generation_element_id,
const autofill::mojom::AutofillState state) {
GetAutofillAgent()->SetSuggestionAvailability(generation_element_id, state);
}
PasswordGenerationFrameHelper*
ContentPasswordManagerDriver::GetPasswordGenerationHelper() {
return &password_generation_helper_;
}
PasswordManager* ContentPasswordManagerDriver::GetPasswordManager() {
return client_->GetPasswordManager();
}
PasswordAutofillManager*
ContentPasswordManagerDriver::GetPasswordAutofillManager() {
return &password_autofill_manager_;
}
void ContentPasswordManagerDriver::SendLoggingAvailability() {
if (const auto& agent = GetPasswordAutofillAgent()) {
agent->SetLoggingState(client_->GetLogManager()->IsLoggingActive());
}
}
bool ContentPasswordManagerDriver::IsInPrimaryMainFrame() const {
return render_frame_host_->IsInPrimaryMainFrame();
}
bool ContentPasswordManagerDriver::CanShowAutofillUi() const {
// Don't show AutofillUi for inactive RenderFrameHost.
return render_frame_host_->IsActive();
}
::ui::AXTreeID ContentPasswordManagerDriver::GetAxTreeId() const {
return render_frame_host_->GetAXTreeID();
}
const GURL& ContentPasswordManagerDriver::GetLastCommittedURL() const {
return render_frame_host_->GetLastCommittedURL();
}
void ContentPasswordManagerDriver::AnnotateFieldsWithParsingResult(
const autofill::ParsingResult& parsing_result) {
if (const auto& agent = GetPasswordAutofillAgent()) {
agent->AnnotateFieldsWithParsingResult(parsing_result);
}
}
void ContentPasswordManagerDriver::GeneratePassword(
autofill::mojom::PasswordGenerationAgent::TriggeredGeneratePasswordCallback
callback) {
GetPasswordGenerationAgent()->TriggeredGeneratePassword(std::move(callback));
}
void ContentPasswordManagerDriver::PasswordFormsParsed(
const std::vector<autofill::FormData>& raw_forms) {
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(render_frame_host_))
return;
std::vector<autofill::FormData> forms = raw_forms;
for (auto& form : forms)
SetFrameAndFormMetaData(render_frame_host_, form);
GetPasswordManager()->OnPasswordFormsParsed(this, forms);
}
void ContentPasswordManagerDriver::PasswordFormsRendered(
const std::vector<autofill::FormData>& raw_forms) {
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(render_frame_host_))
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) {
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(render_frame_host_))
return;
GetPasswordManager()->OnPasswordFormSubmitted(
this, GetFormWithFrameAndFormMetaData(render_frame_host_, raw_form));
LogSiteIsolationMetricsForSubmittedForm(render_frame_host_);
}
void ContentPasswordManagerDriver::InformAboutUserInput(
const autofill::FormData& raw_form) {
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.
// TODO(crbug.com/1233990): Test that PasswordManager doesn't receive url
// and full_url from renderer.
if (!HasValidURL(render_frame_host_))
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) {
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 (!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(render_frame_host_))
return;
GetPasswordManager()->OnPasswordFormCleared(
this, GetFormWithFrameAndFormMetaData(render_frame_host_, raw_form));
}
void ContentPasswordManagerDriver::RecordSavePasswordProgress(
const std::string& log) {
if (!password_manager::bad_message::CheckFrameNotPrerendering(
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_->GetLogManager())
<< autofill::Tag{"div"}
<< autofill::Attrib{"class", "preserve-white-space"} << log
<< autofill::CTag{"div"};
}
void ContentPasswordManagerDriver::UserModifiedPasswordField() {
if (!password_manager::bad_message::CheckFrameNotPrerendering(
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& field_name,
const std::u16string& value,
bool autocomplete_attribute_has_username) {
if (!password_manager::bad_message::CheckFrameNotPrerendering(
render_frame_host_))
return;
GetPasswordManager()->OnUserModifiedNonPasswordField(
this, renderer_id, field_name, value,
autocomplete_attribute_has_username);
// A user has modified an input field, it wouldn't be a submission "after
// Touch To Fill".
client_->ResetSubmissionTrackingAfterTouchToFill();
}
void ContentPasswordManagerDriver::ShowPasswordSuggestions(
base::i18n::TextDirection text_direction,
const std::u16string& typed_username,
int options,
const gfx::RectF& bounds) {
if (!password_manager::bad_message::CheckFrameNotPrerendering(
render_frame_host_))
return;
GetPasswordAutofillManager()->OnShowPasswordSuggestions(
text_direction, typed_username, options,
TransformToRootCoordinates(render_frame_host_, bounds));
}
#if BUILDFLAG(IS_ANDROID)
void ContentPasswordManagerDriver::ShowTouchToFill(
autofill::mojom::SubmissionReadinessState submission_readiness) {
if (!password_manager::bad_message::CheckFrameNotPrerendering(
render_frame_host_))
return;
client_->ShowTouchToFill(this, submission_readiness);
}
#endif
void ContentPasswordManagerDriver::CheckSafeBrowsingReputation(
const GURL& form_action,
const GURL& frame_url) {
if (!password_manager::bad_message::CheckFrameNotPrerendering(
render_frame_host_))
return;
#if defined(ON_FOCUS_PING_ENABLED)
client_->CheckSafeBrowsingReputation(form_action, frame_url);
#endif
}
void ContentPasswordManagerDriver::FocusedInputChanged(
autofill::FieldRendererId focused_field_id,
FocusedFieldType focused_field_type) {
if (!password_manager::bad_message::CheckFrameNotPrerendering(
render_frame_host_))
return;
client_->FocusedInputChanged(this, focused_field_id, focused_field_type);
}
void ContentPasswordManagerDriver::LogFirstFillingResult(
autofill::FormRendererId form_renderer_id,
int32_t result) {
if (!password_manager::bad_message::CheckFrameNotPrerendering(
render_frame_host_))
return;
GetPasswordManager()->LogFirstFillingResult(this, form_renderer_id, result);
}
void ContentPasswordManagerDriver::SetKeyPressHandler(
const content::RenderWidgetHost::KeyPressEventCallback& handler) {
UnsetKeyPressHandler();
content::RenderWidgetHostView* view = render_frame_host_->GetView();
if (!view)
return;
view->GetRenderWidgetHost()->AddKeyPressEventCallback(handler);
key_press_handler_ = handler;
}
void ContentPasswordManagerDriver::UnsetKeyPressHandler() {
if (key_press_handler_.is_null())
return;
content::RenderWidgetHostView* view = render_frame_host_->GetView();
if (!view)
return;
view->GetRenderWidgetHost()->RemoveKeyPressEventCallback(key_press_handler_);
key_press_handler_.Reset();
}
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();
}
const mojo::AssociatedRemote<autofill::mojom::PasswordAutofillAgent>&
ContentPasswordManagerDriver::GetPasswordAutofillAgent() {
if (render_frame_host_->IsCredentialless() ||
render_frame_host_->GetLifecycleState() ==
content::RenderFrameHost::LifecycleState::kPrerendering) {
password_autofill_agent_.reset();
return password_autofill_agent_; // Unbound remote.
}
if (!password_autofill_agent_) {
// Some test environments may have no remote interface support.
if (render_frame_host_->GetRemoteAssociatedInterfaces()) {
render_frame_host_->GetRemoteAssociatedInterfaces()->GetInterface(
&password_autofill_agent_);
}
}
return password_autofill_agent_;
}
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_;
}
} // namespace password_manager