diff --git a/AUTHORS b/AUTHORS index d664be36554a5a..032503b576e7cf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -493,6 +493,7 @@ Lorenzo Stoakes Lu Guanqun Lucie Brozkova Luiz Von Dentz +Luka Dojcilovic Luke Inman-Semerau Luke Zarko Luoxi Pan diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc index e957cb5b577fa2..53af5a6cf04a2f 100644 --- a/chrome/browser/password_manager/password_manager_browsertest.cc +++ b/chrome/browser/password_manager/password_manager_browsertest.cc @@ -510,6 +510,24 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase, EXPECT_FALSE(prompt_observer->IsSavePromptShownAutomatically()); } +IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase, + PromptForDifferentFormWithEmptyAction) { + // Log in, see a form on the landing page. That form is not related to the + // signin form. The signin and the form on the landing page have empty + // actions, so we should offer saving the password. + NavigateToFile("/password/navigate_to_same_url_empty_actions.html"); + + NavigationObserver observer(WebContents()); + auto prompt_observer = base::MakeUnique(WebContents()); + std::string fill_and_submit = + "document.getElementById('username').value = 'temp';" + "document.getElementById('password').value = 'random';" + "document.getElementById('submit-button').click()"; + ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit)); + observer.Wait(); + EXPECT_TRUE(prompt_observer->IsSavePromptShownAutomatically()); +} + IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase, PromptAfterSubmitWithSubFrameNavigation) { NavigateToFile("/password/multi_frames.html"); diff --git a/chrome/test/data/password/navigate_to_same_url_empty_actions.html b/chrome/test/data/password/navigate_to_same_url_empty_actions.html new file mode 100644 index 00000000000000..cbe882fa0eb9f6 --- /dev/null +++ b/chrome/test/data/password/navigate_to_same_url_empty_actions.html @@ -0,0 +1,35 @@ + + + + + + + + + \ No newline at end of file diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc index cae9cb81f2acff..38152f7698e2cc 100644 --- a/components/password_manager/core/browser/password_manager.cc +++ b/components/password_manager/core/browser/password_manager.cc @@ -71,11 +71,19 @@ bool URLsEqualUpToHttpHttpsSubstitution(const GURL& a, const GURL& b) { return false; } +// 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 autofill::PasswordForm& form) { + return form.action != form.origin; +} + // Checks if the observed form looks like the submitted one to handle "Invalid // password entered" case so we don't offer a password save when we shouldn't. bool IsPasswordFormReappeared(const autofill::PasswordForm& observed_form, const autofill::PasswordForm& submitted_form) { - if (observed_form.action.is_valid() && + if (observed_form.action.is_valid() && HasNonEmptyAction(observed_form) && + HasNonEmptyAction(submitted_form) && URLsEqualUpToHttpHttpsSubstitution(submitted_form.action, observed_form.action)) { return true;