Commit 8a518b6f authored by Jan Wilken Dörrie's avatar Jan Wilken Dörrie Committed by Commit Bot

[Passwords] Fix FillingAssistance for https://login.live.com

This change fixes recording the FillingAssistance for websites that
submit fields that differ from the fields that the Password Manager
filled in. This happens on popular websites such as
https://login.live.com.

Bug: 1071122
Change-Id: I6088034a1840d16b931ee3d8c8303e9bab74a66c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2160933Reviewed-by: default avatarVadym Doroshenko  <dvadym@chromium.org>
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#761913}
parent 824437b6
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_vector.h" #include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/public/web/web_document.h" #include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_form_element.h"
#include "third_party/blink/public/web/web_widget.h" #include "third_party/blink/public/web/web_widget.h"
#include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/keycodes/keyboard_codes.h"
...@@ -2247,6 +2248,48 @@ TEST_F(PasswordAutofillAgentTest, RememberFieldPropertiesOnSubmit) { ...@@ -2247,6 +2248,48 @@ TEST_F(PasswordAutofillAgentTest, RememberFieldPropertiesOnSubmit) {
SubmissionIndicatorEvent::HTML_FORM_SUBMISSION); SubmissionIndicatorEvent::HTML_FORM_SUBMISSION);
} }
TEST_F(PasswordAutofillAgentTest, FixEmptyFieldPropertiesOnSubmit) {
SimulateOnFillPasswordForm(fill_data_);
// Simulate a user click so that the password field's real value is filled.
SimulateElementClick(kUsernameName);
// Simulate replacing the username and password field.
static constexpr char kJavaScript[] =
"const old_username = document.getElementById('username');"
"const old_password = document.getElementById('password');"
"const new_username = document.createElement('input');"
"new_username.value = old_username.value;"
"new_username.id = 'new_username';"
"const new_password = document.createElement('input');"
"new_password.value = old_password.value;"
"new_password.id = 'new_password';"
"const form = document.getElementById('LoginTestForm');"
"form.appendChild(new_username);"
"form.appendChild(new_password);"
"form.removeChild(old_username);"
"form.removeChild(old_password);";
ExecuteJavaScriptForTests(kJavaScript);
auto form_element = GetMainFrame()
->GetDocument()
.GetElementById(WebString::FromUTF8("LoginTestForm"))
.To<WebFormElement>();
SaveAndSubmitForm(form_element);
std::map<base::string16, FieldPropertiesMask> expected_properties_masks;
expected_properties_masks[ASCIIToUTF16("new_username")] =
FieldPropertiesFlags::AUTOFILLED_ON_PAGELOAD;
expected_properties_masks[ASCIIToUTF16("new_password")] =
FieldPropertiesFlags::AUTOFILLED_ON_PAGELOAD;
ExpectFieldPropertiesMasks(PasswordFormSubmitted, expected_properties_masks,
SubmissionIndicatorEvent::HTML_FORM_SUBMISSION);
}
TEST_F(PasswordAutofillAgentTest, TEST_F(PasswordAutofillAgentTest,
RememberFieldPropertiesOnSameDocumentNavigation) { RememberFieldPropertiesOnSameDocumentNavigation) {
LoadHTML(kNoFormHTML); LoadHTML(kNoFormHTML);
......
...@@ -22,6 +22,10 @@ namespace autofill { ...@@ -22,6 +22,10 @@ namespace autofill {
// of user typed value and field properties mask). // of user typed value and field properties mask).
class FieldDataManager : public base::RefCounted<FieldDataManager> { class FieldDataManager : public base::RefCounted<FieldDataManager> {
public: public:
using FieldDataMap =
std::map<FieldRendererId,
std::pair<base::Optional<base::string16>, FieldPropertiesMask>>;
FieldDataManager(); FieldDataManager();
void ClearData(); void ClearData();
...@@ -47,14 +51,16 @@ class FieldDataManager : public base::RefCounted<FieldDataManager> { ...@@ -47,14 +51,16 @@ class FieldDataManager : public base::RefCounted<FieldDataManager> {
bool DidUserType(FieldRendererId id) const; bool DidUserType(FieldRendererId id) const;
const FieldDataMap& field_data_map() const {
return field_value_and_properties_map_;
}
private: private:
friend class base::RefCounted<FieldDataManager>; friend class base::RefCounted<FieldDataManager>;
~FieldDataManager(); ~FieldDataManager();
std::map<FieldRendererId, FieldDataMap field_value_and_properties_map_;
std::pair<base::Optional<base::string16>, FieldPropertiesMask>>
field_value_and_properties_map_;
}; };
} // namespace autofill } // namespace autofill
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "third_party/blink/public/web/web_autofill_client.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_document.h"
#include "third_party/blink/public/web/web_element.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_form_element.h"
#include "third_party/blink/public/web/web_local_frame.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_node.h"
...@@ -411,6 +412,33 @@ bool ShowPopupWithoutPasswords(const WebInputElement& password_element) { ...@@ -411,6 +412,33 @@ bool ShowPopupWithoutPasswords(const WebInputElement& password_element) {
return !password_element.IsNull() && IsElementEditable(password_element); return !password_element.IsNull() && IsElementEditable(password_element);
} }
// This method tries to fix `fields` with empty typed or filled properties by
// matching them against previously filled or typed in fields with the same
// value and copying their filled or typed mask.
//
// This helps against websites where submitted fields differ from fields that
// had previously been autofilled or typed into.
void FillNonTypedOrFilledPropertiesMasks(std::vector<FormFieldData>* fields,
const FieldDataManager& manager) {
static constexpr FieldPropertiesMask FILLED_OR_TYPED =
FieldPropertiesFlags::AUTOFILLED | FieldPropertiesFlags::USER_TYPED;
for (auto& field : *fields) {
if (field.properties_mask & FILLED_OR_TYPED)
continue;
for (const auto& pair : manager.field_data_map()) {
const auto& field_data = pair.second;
if ((field_data.second & FILLED_OR_TYPED) &&
field_data.first == field.value) {
field.properties_mask |= field_data.second & FILLED_OR_TYPED;
break;
}
}
}
}
} // namespace } // namespace
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
...@@ -1169,6 +1197,9 @@ void PasswordAutofillAgent::OnWillSubmitForm(const WebFormElement& form) { ...@@ -1169,6 +1197,9 @@ void PasswordAutofillAgent::OnWillSubmitForm(const WebFormElement& form) {
submitted_form_data->submission_event = submitted_form_data->submission_event =
SubmissionIndicatorEvent::HTML_FORM_SUBMISSION; SubmissionIndicatorEvent::HTML_FORM_SUBMISSION;
FillNonTypedOrFilledPropertiesMasks(&submitted_form_data->fields,
*field_data_manager_);
if (FrameCanAccessPasswordManager()) { if (FrameCanAccessPasswordManager()) {
// Some observers depend on sending this information now instead of when // Some observers depend on sending this information now instead of when
// the frame starts loading. If there are redirects that cause a new // the frame starts loading. If there are redirects that cause a new
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment