Commit 57c0ab7a authored by kolos's avatar kolos Committed by Commit bot

[Password Manager] Enables processing invisible username fields even if...

[Password Manager] Enables processing invisible username fields even if visible password field was found.

BUG=554052

Review URL: https://codereview.chromium.org/1645493002

Cr-Commit-Position: refs/heads/master@{#371803}
parent 364b0f4a
...@@ -313,17 +313,38 @@ base::string16 FieldName(const WebInputElement& input_field, ...@@ -313,17 +313,38 @@ base::string16 FieldName(const WebInputElement& input_field,
return field_name.empty() ? base::ASCIIToUTF16(dummy_name) : field_name; return field_name.empty() ? base::ASCIIToUTF16(dummy_name) : field_name;
} }
bool FormContainsVisiblePasswordFields(const SyntheticForm& form) { // Helper function that checks the presence of visible password and username
// fields in |form.control_elements|.
// Iff a visible password found, then |*found_visible_password| is set to true.
// Iff a visible password found AND there is a visible username before it, then
// |*found_visible_username_before_visible_password| is set to true.
void FoundVisiblePasswordAndVisibleUsernameBeforePassword(
const SyntheticForm& form,
bool* found_visible_password,
bool* found_visible_username_before_visible_password) {
DCHECK(found_visible_password);
DCHECK(found_visible_username_before_visible_password);
*found_visible_password = false;
*found_visible_username_before_visible_password = false;
bool found_visible_username = false;
for (auto& control_element : form.control_elements) { for (auto& control_element : form.control_elements) {
const WebInputElement* input_element = toWebInputElement(&control_element); const WebInputElement* input_element = toWebInputElement(&control_element);
if (!input_element || !input_element->isEnabled()) if (!input_element || !input_element->isEnabled() ||
!input_element->isTextField())
continue; continue;
if (input_element->isPasswordField() && if (!form_util::IsWebNodeVisible(*input_element))
form_util::IsWebNodeVisible(*input_element)) continue;
return true;
if (input_element->isPasswordField()) {
*found_visible_password = true;
*found_visible_username_before_visible_password = found_visible_username;
break;
} else {
found_visible_username = true;
}
} }
return false;
} }
// Get information about a login form encapsulated in a PasswordForm struct. // Get information about a login form encapsulated in a PasswordForm struct.
...@@ -357,22 +378,36 @@ bool GetPasswordForm(const SyntheticForm& form, ...@@ -357,22 +378,36 @@ bool GetPasswordForm(const SyntheticForm& form,
&predicted_elements); &predicted_elements);
} }
// Check the presence of visible password and username fields.
// If there is a visible password field, then ignore invisible password
// fields. If there is a visible username before visible password, then ignore
// invisible username fields.
// If there is no visible password field, don't ignore any elements (i.e. use
// the latest username field just before selected password field).
bool ignore_invisible_passwords = false;
bool ignore_invisible_usernames = false;
FoundVisiblePasswordAndVisibleUsernameBeforePassword(
form, &ignore_invisible_passwords, &ignore_invisible_usernames);
std::string layout_sequence; std::string layout_sequence;
layout_sequence.reserve(form.control_elements.size()); layout_sequence.reserve(form.control_elements.size());
bool ignore_invisible_fields = FormContainsVisiblePasswordFields(form);
for (size_t i = 0; i < form.control_elements.size(); ++i) { for (size_t i = 0; i < form.control_elements.size(); ++i) {
WebFormControlElement control_element = form.control_elements[i]; WebFormControlElement control_element = form.control_elements[i];
WebInputElement* input_element = toWebInputElement(&control_element); WebInputElement* input_element = toWebInputElement(&control_element);
if (!input_element || !input_element->isEnabled()) if (!input_element || !input_element->isEnabled())
continue; continue;
if (ignore_invisible_fields && !form_util::IsWebNodeVisible(*input_element))
continue; bool element_is_invisible = !form_util::IsWebNodeVisible(*input_element);
if (input_element->isTextField()) { if (input_element->isTextField()) {
if (input_element->isPasswordField()) if (input_element->isPasswordField()) {
if (element_is_invisible && ignore_invisible_passwords)
continue;
layout_sequence.push_back('P'); layout_sequence.push_back('P');
else } else {
if (element_is_invisible && ignore_invisible_usernames)
continue;
layout_sequence.push_back('N'); layout_sequence.push_back('N');
}
} }
bool password_marked_by_autocomplete_attribute = bool password_marked_by_autocomplete_attribute =
......
...@@ -705,6 +705,65 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyNonDisplayedLoginPair) { ...@@ -705,6 +705,65 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyNonDisplayedLoginPair) {
password_form->password_value); password_form->password_value);
} }
TEST_F(MAYBE_PasswordFormConversionUtilsTest,
VisiblePasswordAndInvisibleUsername) {
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddNonDisplayedTextField("username", "William");
builder.AddPasswordField("password", "secret", NULL);
builder.AddSubmitButton("submit");
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(
LoadHTMLAndConvertForm(html, &password_form, nullptr));
ASSERT_TRUE(password_form);
EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element);
EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
}
TEST_F(MAYBE_PasswordFormConversionUtilsTest,
InvisiblePassword_LatestUsernameIsVisible) {
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddNonDisplayedTextField("search", "query");
builder.AddTextField("username", "William", NULL);
builder.AddNonDisplayedPasswordField("password", "secret");
builder.AddSubmitButton("submit");
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(
LoadHTMLAndConvertForm(html, &password_form, nullptr));
ASSERT_TRUE(password_form);
EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element);
EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
}
TEST_F(MAYBE_PasswordFormConversionUtilsTest,
InvisiblePassword_LatestUsernameIsInvisible) {
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddTextField("search", "query", NULL);
builder.AddNonDisplayedTextField("username", "William");
builder.AddNonDisplayedPasswordField("password", "secret");
builder.AddSubmitButton("submit");
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(
LoadHTMLAndConvertForm(html, &password_form, nullptr));
ASSERT_TRUE(password_form);
EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element);
EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
}
TEST_F(MAYBE_PasswordFormConversionUtilsTest, InvalidFormDueToBadActionURL) { TEST_F(MAYBE_PasswordFormConversionUtilsTest, InvalidFormDueToBadActionURL) {
PasswordFormBuilder builder("invalid_target"); PasswordFormBuilder builder("invalid_target");
builder.AddTextField("username", "JohnSmith", NULL); builder.AddTextField("username", "JohnSmith", NULL);
......
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