Commit 733e377c authored by Mohamed Amir Yosef's avatar Mohamed Amir Yosef Committed by Commit Bot

[Passwords] AreAllFieldsEmpty() should deal with FormData

With the new parser in place, FormData should be used to check empty
fields instead of PasswordForm

Change-Id: I8242cc82524d14de4a82c2ffde6d8c059c7d3ee2
Bug: 949519,1017129, 1008798
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1849894
Commit-Queue: Mohamed Amir Yosef <mamir@chromium.org>
Reviewed-by: default avatarVadym Doroshenko <dvadym@chromium.org>
Cr-Commit-Position: refs/heads/master@{#708676}
parent 16980f14
...@@ -226,7 +226,8 @@ void TestPromptNotShown(const char* failure_message, ...@@ -226,7 +226,8 @@ void TestPromptNotShown(const char* failure_message,
// Generate HTML for a simple password form with the specified action URL. // Generate HTML for a simple password form with the specified action URL.
std::string GeneratePasswordFormForAction(const GURL& action_url) { std::string GeneratePasswordFormForAction(const GURL& action_url) {
return "<form method='POST' action='" + action_url.spec() + "'" return "<form method='POST' action='" + action_url.spec() +
"'"
" onsubmit='return true;' id='testform'>" " onsubmit='return true;' id='testform'>"
" <input type='password' id='password_field'>" " <input type='password' id='password_field'>"
"</form>"; "</form>";
...@@ -241,7 +242,8 @@ void InjectBlankFrameWithPasswordForm(content::WebContents* web_contents, ...@@ -241,7 +242,8 @@ void InjectBlankFrameWithPasswordForm(content::WebContents* web_contents,
"var frame = document.createElement('iframe');" "var frame = document.createElement('iframe');"
"frame.id = 'iframe';" "frame.id = 'iframe';"
"document.body.appendChild(frame);" "document.body.appendChild(frame);"
"frame.contentDocument.body.innerHTML = \"" + form_html + "\""; "frame.contentDocument.body.innerHTML = \"" +
form_html + "\"";
ASSERT_TRUE(content::ExecuteScript(web_contents, ASSERT_TRUE(content::ExecuteScript(web_contents,
inject_blank_frame_with_password_form)); inject_blank_frame_with_password_form));
} }
...@@ -290,6 +292,22 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptIfFormReappeared) { ...@@ -290,6 +292,22 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptIfFormReappeared) {
TestPromptNotShown("normal form", WebContents()); TestPromptNotShown("normal form", WebContents());
} }
IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
PromptIfChangePasswordFormReappearedEmpty) {
NavigateToFile("/password/update_form_empty_fields.html");
// Fill a form and submit through a <input type="submit"> button. Nothing
// special.
NavigationObserver observer(WebContents());
std::string fill_and_submit =
"document.getElementById('password').value = 'old_pass';"
"document.getElementById('new_password_1').value = 'new_pass';"
"document.getElementById('new_password_2').value = 'new_pass';"
"document.getElementById('chg_submit_wo_username_button').click()";
ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit));
observer.Wait();
EXPECT_TRUE(BubbleObserver(WebContents()).IsSavePromptShownAutomatically());
}
IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
NoPromptIfFormReappearedWithPartsHidden) { NoPromptIfFormReappearedWithPartsHidden) {
NavigateToFile("/password/failed_partly_visible.html"); NavigateToFile("/password/failed_partly_visible.html");
...@@ -1497,8 +1515,7 @@ IN_PROC_BROWSER_TEST_F( ...@@ -1497,8 +1515,7 @@ IN_PROC_BROWSER_TEST_F(
"document.getElementById('username_redirect').value = 'user';" "document.getElementById('username_redirect').value = 'user';"
"document.getElementById('password_redirect').value = 'password';" "document.getElementById('password_redirect').value = 'password';"
"document.getElementById('submit_redirect').click()"; "document.getElementById('submit_redirect').click()";
ASSERT_TRUE( ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit_redirect));
content::ExecuteScript(WebContents(), fill_and_submit_redirect));
NavigationObserver redirect_observer(WebContents()); NavigationObserver redirect_observer(WebContents());
redirect_observer.SetPathToWaitFor("/password/redirect.html"); redirect_observer.SetPathToWaitFor("/password/redirect.html");
...@@ -3408,7 +3425,8 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, AboutBlankPopupsAreIgnored) { ...@@ -3408,7 +3425,8 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, AboutBlankPopupsAreIgnored) {
std::string form_html = GeneratePasswordFormForAction(submit_url); std::string form_html = GeneratePasswordFormForAction(submit_url);
std::string open_blank_popup_with_password_form = std::string open_blank_popup_with_password_form =
"var w = window.open('about:blank');" "var w = window.open('about:blank');"
"w.document.body.innerHTML = \"" + form_html + "\";"; "w.document.body.innerHTML = \"" +
form_html + "\";";
ASSERT_TRUE(content::ExecuteScript(WebContents(), ASSERT_TRUE(content::ExecuteScript(WebContents(),
open_blank_popup_with_password_form)); open_blank_popup_with_password_form));
tab_add.Wait(); tab_add.Wait();
...@@ -3504,7 +3522,9 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, ...@@ -3504,7 +3522,9 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
std::string form_html = GeneratePasswordFormForAction(submit_url); std::string form_html = GeneratePasswordFormForAction(submit_url);
std::string inject_data_frame_with_password_form = std::string inject_data_frame_with_password_form =
"var frame = document.createElement('iframe');\n" "var frame = document.createElement('iframe');\n"
"frame.src = \"data:text/html," + form_html + "\";\n" "frame.src = \"data:text/html," +
form_html +
"\";\n"
"document.body.appendChild(frame);\n"; "document.body.appendChild(frame);\n";
ASSERT_TRUE(content::ExecuteScript(WebContents(), ASSERT_TRUE(content::ExecuteScript(WebContents(),
inject_data_frame_with_password_form)); inject_data_frame_with_password_form));
......
<html>
<body>
Navigation complete. Below is the password update form again with empty fields.
<form action="update_form_empty_fields.html" id="chg_testform_wo_username">
<input type="password" id="password" name="password">
<input type="password" id="new_password_1" name="new_password_1">
<input type="password" id="new_password_2" name="new_password_2">
<input type="submit" id="chg_submit_wo_username_button" name="chg_submit_button">
</form>
</body>
</html>
...@@ -1768,7 +1768,8 @@ bool WebFormElementToFormData( ...@@ -1768,7 +1768,8 @@ bool WebFormElementToFormData(
form->unique_renderer_id = form_element.UniqueRendererFormId(); form->unique_renderer_id = form_element.UniqueRendererFormId();
form->url = GetCanonicalOriginForDocument(frame->GetDocument()); form->url = GetCanonicalOriginForDocument(frame->GetDocument());
form->action = GetCanonicalActionForForm(form_element); form->action = GetCanonicalActionForForm(form_element);
form->is_action_empty = form_element.Action().IsNull(); form->is_action_empty =
form_element.Action().IsNull() || form_element.Action().IsEmpty();
if (IsAutofillFieldMetadataEnabled()) { if (IsAutofillFieldMetadataEnabled()) {
SCOPED_UMA_HISTOGRAM_TIMER( SCOPED_UMA_HISTOGRAM_TIMER(
"PasswordManager.ButtonTitlePerformance.HasFormTag"); "PasswordManager.ButtonTitlePerformance.HasFormTag");
......
...@@ -127,14 +127,6 @@ uint32_t FindFormsDifferences(const FormData& lhs, const FormData& rhs) { ...@@ -127,14 +127,6 @@ uint32_t FindFormsDifferences(const FormData& lhs, const FormData& rhs) {
return differences_bitmask; return differences_bitmask;
} }
// Since empty or unspecified form's action is automatically set to the page
// origin, this function checks if a form's action is empty by comparing it to
// its origin.
bool HasNonEmptyAction(const FormData& form) {
// TODO(crbug.com/1008798): The logic isn't accurate and should be fixed.
return form.action != form.url;
}
bool FormContainsFieldWithName(const FormData& form, bool FormContainsFieldWithName(const FormData& form,
const base::string16& element) { const base::string16& element) {
if (element.empty()) if (element.empty())
...@@ -240,8 +232,8 @@ bool PasswordFormManager::IsEqualToSubmittedForm( ...@@ -240,8 +232,8 @@ bool PasswordFormManager::IsEqualToSubmittedForm(
if (IsHttpAuth()) if (IsHttpAuth())
return false; return false;
if (form.action.is_valid() && HasNonEmptyAction(form) && if (form.action.is_valid() && !form.is_action_empty &&
HasNonEmptyAction(submitted_form_) && !submitted_form_.is_action_empty &&
submitted_form_.action == form.action) { submitted_form_.action == form.action) {
return true; return true;
} }
......
...@@ -59,9 +59,13 @@ namespace { ...@@ -59,9 +59,13 @@ namespace {
// already. // already.
using Logger = autofill::SavePasswordProgressLogger; using Logger = autofill::SavePasswordProgressLogger;
bool AreAllFieldsEmpty(const PasswordForm& form) { bool AreAllFieldsEmpty(const FormData& form_data) {
return form.username_value.empty() && form.password_value.empty() && for (const auto& field : form_data.fields) {
form.new_password_value.empty(); if (!field.value.empty())
return false;
}
return true;
} }
// Returns true if the user needs to be prompted before a password can be // Returns true if the user needs to be prompted before a password can be
...@@ -741,8 +745,7 @@ void PasswordManager::OnPasswordFormsRendered( ...@@ -741,8 +745,7 @@ void PasswordManager::OnPasswordFormsRendered(
} }
// Record all visible forms from the frame. // Record all visible forms from the frame.
all_visible_forms_.insert(all_visible_forms_.end(), all_visible_forms_.insert(all_visible_forms_.end(), visible_forms.begin(),
visible_forms.begin(),
visible_forms.end()); visible_forms.end());
if (!did_stop_loading && if (!did_stop_loading &&
...@@ -768,7 +771,7 @@ void PasswordManager::OnPasswordFormsRendered( ...@@ -768,7 +771,7 @@ void PasswordManager::OnPasswordFormsRendered(
for (const PasswordForm& form : all_visible_forms_) { for (const PasswordForm& form : all_visible_forms_) {
if (submitted_manager->IsEqualToSubmittedForm(form.form_data)) { if (submitted_manager->IsEqualToSubmittedForm(form.form_data)) {
if (submitted_manager->IsPossibleChangePasswordFormWithoutUsername() && if (submitted_manager->IsPossibleChangePasswordFormWithoutUsername() &&
AreAllFieldsEmpty(form)) { AreAllFieldsEmpty(form.form_data)) {
continue; continue;
} }
submitted_manager->GetMetricsRecorder()->LogSubmitFailed(); submitted_manager->GetMetricsRecorder()->LogSubmitFailed();
......
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