#include "components/autofill/content/renderer/password_autofill_agent.h"
#include <stddef.h>
#include <iterator>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/i18n/case_conversion.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/ranges/algorithm.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/password_form_conversion_utils.h"
#include "components/autofill/content/renderer/password_generation_agent.h"
#include "components/autofill/content/renderer/prefilled_values_detector.h"
#include "components/autofill/content/renderer/renderer_save_password_progress_logger.h"
#include "components/autofill/content/renderer/suggestion_properties.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/autofill/core/common/signatures.h"
#include "components/password_manager/core/common/password_manager_constants.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_util.h"
#include "components/safe_browsing/buildflags.h"
#include "content/public/renderer/render_frame.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/features_generated.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/public/web/web_autofill_client.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_form_control_element.h"
#include "third_party/blink/public/web/web_form_element.h"
#include "third_party/blink/public/web/web_input_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_node.h"
#include "third_party/blink/public/web/web_view.h"
#include "ui/base/page_transition_types.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "url/gurl.h"
WebAutofillState;
WebDocument;
WebDocumentLoader;
WebElement;
WebElementCollection;
WebFormControlElement;
WebFormElement;
WebFrame;
WebInputElement;
WebLocalFrame;
WebNode;
WebSecurityOrigin;
WebString;
WebURL;
WebVector;
WebView;
IsRendererRecognizedCredentialForm;
namespace autofill {
namespace {
ExtractOption;
GetFieldRendererId;
GetFormByRendererId;
GetFormControlByRendererId;
GetFormRendererId;
IsElementEditable;
IsWebElementFocusableForAutofill;
SubmissionIndicatorEvent;
SubmissionSource;
constexpr auto kInputPassword = …;
const size_t kMaximumTextSizeForAutocomplete = …;
const char kDebugAttributeForFormSignature[] = …;
const char kDebugAttributeForAlternativeFormSignature[] = …;
const char kDebugAttributeForFieldSignature[] = …;
const char kDebugAttributeForParserAnnotations[] = …;
const char kDebugAttributeForVisibility[] = …;
constexpr char kDebugAttributeForAutofill[] = …;
constexpr char kHtmlAttributeForAutofillTooltip[] = …;
FormInputElementMap;
Logger;
FormElementsList;
bool DoUsernamesMatch(const std::u16string& potential_suggestion,
const std::u16string& current_username,
bool exact_match) { … }
bool IsUsernameAmendable(const WebInputElement& username_element,
bool is_password_field_selected) { … }
void LogMessage(Logger* logger, Logger::StringID message) { … }
void LogBoolean(Logger* logger, Logger::StringID message, bool value) { … }
void LogHTMLForm(Logger* logger,
Logger::StringID message_id,
const WebFormElement& form) { … }
bool CanShowUsernameSuggestion(const PasswordFormFillData& fill_data,
const std::u16string& typed_username) { … }
void FindMatchesByUsername(const PasswordFormFillData& fill_data,
const std::u16string& current_username,
bool exact_username_match,
RendererSavePasswordProgressLogger* logger,
std::u16string* username,
std::u16string* password) { … }
std::string GetRegistryControlledDomain(const GURL& signon_realm) { … }
bool IsPublicSuffixDomainMatch(const std::string& url1,
const std::string& url2) { … }
std::string GetFormSignatureAsString(const FormData& form_data) { … }
std::string GetAlternativeFormSignatureAsString(const FormData& form_data) { … }
void SetAttributeInternal(WebElement target,
const std::string& attribute_utf8,
const std::string& value_utf8) { … }
void SetAttributeAsync(WebElement target,
const std::string& attribute_utf8,
const std::string& value_utf8) { … }
void AnnotateFieldsWithSignatures(
base::span<const WebFormControlElement> fields,
const std::string& form_signature,
const std::string& alternative_form_signature) { … }
bool HasPasswordField(const WebLocalFrame& frame) { … }
WebInputElement FindUsernameElementPrecedingPasswordElement(
WebLocalFrame* frame,
const WebInputElement& password_element) { … }
bool IsInCrossOriginIframeOrEmbeddedFrame(const WebInputElement& element) { … }
void AnnotateFieldWithParsingResult(
FieldRendererId renderer_id,
const std::string& password_managers_annotation) { … }
bool HasDocumentWithValidFrame(const WebInputElement& element) { … }
[[nodiscard]] std::vector<FormFieldData> FillNonTypedOrFilledPropertiesMasks(
std::vector<FormFieldData> fields,
const FieldDataManager& manager) { … }
size_t GetIndexOfElement(const FormData& form_data,
const WebInputElement& element) { … }
bool HasTextInputs(const FormData& form_data) { … }
#if BUILDFLAG(IS_ANDROID)
bool IsWebAuthnForm(base::optional_ref<const FormData> form_data) {
auto has_webauthn_attribute = [](const FormFieldData& field) {
return field.parsed_autocomplete() && field.parsed_autocomplete()->webauthn;
};
return form_data &&
base::ranges::any_of(form_data->fields(), has_webauthn_attribute);
}
mojom::SubmissionReadinessState CalculateSubmissionReadiness(
const FormData& form_data,
const WebInputElement& username_element,
WebInputElement password_element) {
if (!password_element) {
return mojom::SubmissionReadinessState::kNoPasswordField;
}
if (!username_element) {
return mojom::SubmissionReadinessState::kNoUsernameField;
}
size_t username_index = GetIndexOfElement(form_data, username_element);
size_t password_index = GetIndexOfElement(form_data, password_element);
size_t number_of_elements = form_data.fields().size();
if (username_index == number_of_elements ||
password_index == number_of_elements) {
return mojom::SubmissionReadinessState::kError;
}
auto ShouldIgnoreField = [](const FormFieldData& field) {
if (!field.IsFocusable())
return true;
return field.form_control_type() == mojom::FormControlType::kInputCheckbox;
};
for (size_t i = username_index + 1; i < password_index; ++i) {
if (ShouldIgnoreField(form_data.fields()[i])) {
continue;
}
return mojom::SubmissionReadinessState::kFieldBetweenUsernameAndPassword;
}
if (!password_element.IsLastInputElementInForm())
return mojom::SubmissionReadinessState::kFieldAfterPasswordField;
size_t number_of_visible_elements = 0;
for (size_t i = 0; i < number_of_elements; ++i) {
if (ShouldIgnoreField(form_data.fields()[i])) {
continue;
}
if (username_index != i && password_index != i &&
form_data.fields()[i].value().empty()) {
return mojom::SubmissionReadinessState::kEmptyFields;
}
number_of_visible_elements++;
}
if (number_of_visible_elements > 2)
return mojom::SubmissionReadinessState::kMoreThanTwoFields;
return mojom::SubmissionReadinessState::kTwoFields;
}
#endif
}
class PasswordAutofillAgent::DeferringPasswordManagerDriver
: public mojom::PasswordManagerDriver { … };
PasswordAutofillAgent::PasswordAutofillAgent(
content::RenderFrame* render_frame,
blink::AssociatedInterfaceRegistry* registry,
EnableHeavyFormDataScraping enable_heavy_form_data_scraping)
: … { … }
PasswordAutofillAgent::~PasswordAutofillAgent() = default;
void PasswordAutofillAgent::Init(AutofillAgent* autofill_agent) { … }
void PasswordAutofillAgent::BindPendingReceiver(
mojo::PendingAssociatedReceiver<mojom::PasswordAutofillAgent>
pending_receiver) { … }
void PasswordAutofillAgent::SetPasswordGenerationAgent(
PasswordGenerationAgent* generation_agent) { … }
PasswordAutofillAgent::FormStructureInfo::FormStructureInfo() = default;
PasswordAutofillAgent::FormStructureInfo::FormStructureInfo(
const FormStructureInfo& other) = default;
PasswordAutofillAgent::FormStructureInfo&
PasswordAutofillAgent::FormStructureInfo::operator=(
const PasswordAutofillAgent::FormStructureInfo& other) = default;
PasswordAutofillAgent::FormStructureInfo::FormStructureInfo(
FormStructureInfo&& other) = default;
PasswordAutofillAgent::FormStructureInfo&
PasswordAutofillAgent::FormStructureInfo::operator=(
PasswordAutofillAgent::FormStructureInfo&& other) = default;
PasswordAutofillAgent::FormStructureInfo::~FormStructureInfo() = default;
PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper()
: … { … }
PasswordAutofillAgent::PasswordValueGatekeeper::~PasswordValueGatekeeper() =
default;
void PasswordAutofillAgent::PasswordValueGatekeeper::RegisterElement(
WebInputElement element) { … }
void PasswordAutofillAgent::PasswordValueGatekeeper::OnUserGesture() { … }
void PasswordAutofillAgent::PasswordValueGatekeeper::Reset() { … }
void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue(
WebInputElement element) { … }
bool PasswordAutofillAgent::TextDidChangeInTextField(
const WebInputElement& element) { … }
void PasswordAutofillAgent::NotifyPasswordManagerAboutFieldModification(
const WebInputElement& element) { … }
void PasswordAutofillAgent::UpdatePasswordStateForTextChange(
const WebInputElement& element) { … }
void PasswordAutofillAgent::TrackAutofilledElement(
const WebFormControlElement& element) { … }
void PasswordAutofillAgent::FillPasswordSuggestion(
const std::u16string& username,
const std::u16string& password) { … }
void PasswordAutofillAgent::FillIntoFocusedField(
bool is_password,
const std::u16string& credential) { … }
void PasswordAutofillAgent::PreviewField(FieldRendererId field_id,
const std::u16string& value) { … }
void PasswordAutofillAgent::FillField(FieldRendererId field_id,
const std::u16string& value) { … }
void PasswordAutofillAgent::DoPreviewField(WebInputElement input,
const std::u16string& credential,
bool is_password) { … }
void PasswordAutofillAgent::DoFillField(WebInputElement input,
const std::u16string& credential) { … }
void PasswordAutofillAgent::FillPasswordFieldAndSave(
WebInputElement password_input,
const std::u16string& credential) { … }
void PasswordAutofillAgent::PreviewSuggestion(
const WebFormControlElement& control_element,
const std::u16string& username,
const std::u16string& password) { … }
void PasswordAutofillAgent::ClearPreviewedForm() { … }
bool PasswordAutofillAgent::FindPasswordInfoForElement(
const WebInputElement& element,
UseFallbackData use_fallback_data,
WebInputElement* username_element,
WebInputElement* password_element,
PasswordInfo** password_info) { … }
bool PasswordAutofillAgent::IsUsernameOrPasswordFillable(
const WebInputElement& username_element,
const WebInputElement& password_element,
PasswordInfo* password_info) { … }
bool PasswordAutofillAgent::HasElementsToFill(
const WebInputElement& trigger_element,
UseFallbackData use_fallback_data,
WebInputElement* username_element,
WebInputElement* password_element,
PasswordInfo** password_info) { … }
void PasswordAutofillAgent::MaybeCheckSafeBrowsingReputation(
const WebInputElement& element) { … }
#if BUILDFLAG(IS_ANDROID)
bool PasswordAutofillAgent::ShouldSuppressKeyboard() {
return keyboard_replacing_surface_state_ ==
KeyboardReplacingSurfaceState::kIsShowing;
}
bool PasswordAutofillAgent::TryToShowKeyboardReplacingSurface(
const WebFormControlElement& control_element) {
if (keyboard_replacing_surface_state_ !=
KeyboardReplacingSurfaceState::kShouldShow) {
return false;
}
const WebInputElement input_element =
control_element.DynamicTo<WebInputElement>();
WebInputElement username_element;
WebInputElement password_element;
PasswordInfo* password_info = nullptr;
if (!input_element || !IsElementEditable(input_element) ||
!FindPasswordInfoForElement(input_element, UseFallbackData(false),
&username_element, &password_element,
&password_info)) {
return false;
}
bool has_amendable_username_element = IsUsernameAmendable(
username_element,
input_element.FormControlTypeForAutofill() == kInputPassword);
bool has_editable_password_element =
password_element && IsElementEditable(password_element);
CHECK(has_amendable_username_element || has_editable_password_element);
WebFormElement form = password_element
? form_util::GetOwningForm(password_element)
: form_util::GetOwningForm(username_element);
std::optional<FormData> form_data =
form ? GetFormDataFromWebForm(form)
: GetFormDataFromUnownedInputElements();
GetPasswordManagerDriver().ShowKeyboardReplacingSurface(
form_data ? CalculateSubmissionReadiness(*form_data, username_element,
password_element)
: mojom::SubmissionReadinessState::kNoInformation,
IsWebAuthnForm(form_data));
keyboard_replacing_surface_state_ = KeyboardReplacingSurfaceState::kIsShowing;
return true;
}
#endif
bool PasswordAutofillAgent::ShowSuggestions(
const WebInputElement& element,
AutofillSuggestionTriggerSource trigger_source) { … }
bool PasswordAutofillAgent::FrameCanAccessPasswordManager() { … }
void PasswordAutofillAgent::OnDynamicFormsSeen() { … }
void PasswordAutofillAgent::UserGestureObserved() { … }
void PasswordAutofillAgent::AnnotateFormsAndFieldsWithSignatures(
WebVector<WebFormElement>& forms) { … }
void PasswordAutofillAgent::SendPasswordForms(bool only_visible) { … }
void PasswordAutofillAgent::DidDispatchDOMContentLoadedEvent() { … }
void PasswordAutofillAgent::DidFinishLoad() { … }
void PasswordAutofillAgent::DidCommitProvisionalLoad(
ui::PageTransition transition) { … }
void PasswordAutofillAgent::OnDestruct() { … }
bool PasswordAutofillAgent::IsPrerendering() const { … }
bool PasswordAutofillAgent::IsUsernameInputField(
const WebInputElement& input_element) const { … }
void PasswordAutofillAgent::ReadyToCommitNavigation(
WebDocumentLoader* document_loader) { … }
void PasswordAutofillAgent::OnProbablyFormSubmitted() { … }
void PasswordAutofillAgent::SetPasswordFillData(
const PasswordFormFillData& form_data) { … }
void PasswordAutofillAgent::SetLoggingState(bool active) { … }
void PasswordAutofillAgent::AnnotateFieldsWithParsingResult(
const ParsingResult& parsing_result) { … }
void PasswordAutofillAgent::InformNoSavedCredentials(
bool should_show_popup_without_passwords) { … }
#if BUILDFLAG(IS_ANDROID)
void PasswordAutofillAgent::KeyboardReplacingSurfaceClosed(
bool show_virtual_keyboard) {
keyboard_replacing_surface_state_ = KeyboardReplacingSurfaceState::kWasShown;
auto focused_input_element = focused_element().DynamicTo<WebInputElement>();
if (!focused_input_element || focused_element().IsReadOnly()) {
return;
}
if (show_virtual_keyboard) {
render_frame()->ShowVirtualKeyboard();
ShowSuggestions(
focused_input_element,
autofill::AutofillSuggestionTriggerSource::kFormControlElementClicked);
}
}
void PasswordAutofillAgent::TriggerFormSubmission() {
WebFormControlElement form_control =
GetFormControlByRendererId(field_renderer_id_to_submit_);
if (!form_control) {
return;
}
WebInputElement input = form_control.To<WebInputElement>();
input.DispatchSimulatedEnter();
field_renderer_id_to_submit_ = FieldRendererId();
}
#endif
std::optional<FormData> PasswordAutofillAgent::GetFormDataFromWebForm(
const WebFormElement& web_form) { … }
std::optional<FormData>
PasswordAutofillAgent::GetFormDataFromUnownedInputElements() { … }
void PasswordAutofillAgent::InformAboutFormClearing(
const WebFormElement& form) { … }
void PasswordAutofillAgent::InformAboutFieldClearing(
const WebInputElement& cleared_element) { … }
bool PasswordAutofillAgent::ShowSuggestionsForDomain(
const WebInputElement& element,
AutofillSuggestionTriggerSource trigger_source) { … }
bool PasswordAutofillAgent::ShowManualFallbackSuggestions(
const WebInputElement& element) { … }
void PasswordAutofillAgent::ShowSuggestionPopup(
const std::u16string& typed_username,
const WebInputElement& user_input,
AutofillSuggestionTriggerSource trigger_source) { … }
void PasswordAutofillAgent::CleanupOnDocumentShutdown() { … }
void PasswordAutofillAgent::InformBrowserAboutUserInput(
const WebFormElement& form,
const WebInputElement& element) { … }
bool PasswordAutofillAgent::FillUserNameAndPassword(
WebInputElement username_element,
WebInputElement password_element,
const PasswordFormFillData& fill_data,
RendererSavePasswordProgressLogger* logger) { … }
void PasswordAutofillAgent::LogPrefilledUsernameFillOutcome(
PrefilledUsernameFillOutcome outcome) { … }
void PasswordAutofillAgent::OnProvisionallySaveForm(
const WebFormElement& form,
const WebFormControlElement& element,
SaveFormReason source) { … }
void PasswordAutofillAgent::FireHostSubmitEvent(
FormRendererId form_id,
mojom::SubmissionSource source) { … }
void PasswordAutofillAgent::OnFormSubmitted(const WebFormElement& form) { … }
void PasswordAutofillAgent::OnInferredFormSubmission(SubmissionSource source) { … }
void PasswordAutofillAgent::HidePopup() { … }
mojom::PasswordManagerDriver&
PasswordAutofillAgent::GetPasswordManagerDriver() { … }
std::pair<WebInputElement, WebInputElement>
PasswordAutofillAgent::FindUsernamePasswordElements(
const PasswordFormFillData& form_data) { … }
void PasswordAutofillAgent::StoreDataForFillOnAccountSelect(
const PasswordFormFillData& form_data,
WebInputElement username_element,
WebInputElement password_element) { … }
void PasswordAutofillAgent::MaybeStoreFallbackData(
const PasswordFormFillData& form_data) { … }
void PasswordAutofillAgent::LogFirstFillingResult(
const PasswordFormFillData& form_data,
FillingResult result) { … }
PasswordAutofillAgent::FormStructureInfo
PasswordAutofillAgent::ExtractFormStructureInfo(const FormData& form_data) { … }
bool PasswordAutofillAgent::WasFormStructureChanged(
const FormStructureInfo& form_info) const { … }
void PasswordAutofillAgent::TryFixAutofilledForm(
std::vector<WebFormControlElement>& control_elements) const { … }
void PasswordAutofillAgent::AutofillField(const std::u16string& value,
WebInputElement field) { … }
bool PasswordAutofillAgent::CanShowPopupWithoutPasswords(
const WebInputElement& password_element) const { … }
bool PasswordAutofillAgent::IsPasswordFieldFilledByUser(
const WebFormControlElement& element) const { … }
void PasswordAutofillAgent::NotifyPasswordManagerAboutClearedForm(
const WebFormElement& cleared_form) { … }
void PasswordAutofillAgent::MaybeTriggerSuggestionsOnFocusedElement(
const WebInputElement& username_element,
const WebInputElement& password_element) { … }
}