Bug 1278158 - Allowing filling login forms with an inputElement but without loginFormForFill. r=MattN a=gchang
MozReview-Commit-ID: 2aZCvMpH1eH
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -465,17 +465,17 @@ var LoginManagerContent = {
* recipes:
* Fill recipes transmitted together with the original message.
* inputElement:
* Optional input password element from the form we want to fill.
* }
*/
fillForm({ topDocument, loginFormOrigin, loginsFound, recipes, inputElement }) {
let topState = this.stateForDocument(topDocument);
- if (!topState.loginFormForFill) {
+ if (!inputElement && !topState.loginFormForFill) {
log("fillForm: There is no login form anymore. The form may have been",
"removed or the document may have changed.");
return;
}
if (LoginUtils._getPasswordOrigin(topDocument.documentURI) != loginFormOrigin) {
if (!inputElement ||
LoginUtils._getPasswordOrigin(inputElement.ownerDocument.documentURI) != loginFormOrigin) {
log("fillForm: The requested origin doesn't match the one form the",
--- a/toolkit/components/passwordmgr/test/browser/browser.ini
+++ b/toolkit/components/passwordmgr/test/browser/browser.ini
@@ -1,13 +1,14 @@
[DEFAULT]
support-files =
../formsubmit.sjs
authenticate.sjs
form_basic.html
+ form_basic_iframe.html
formless_basic.html
form_same_origin_action.html
form_cross_origin_insecure_action.html
form_cross_origin_secure_action.html
head.js
insecure_test.html
insecure_test_subframe.html
multiple_forms.html
@@ -42,17 +43,18 @@ support-files =
[browser_hasInsecureLoginForms.js]
[browser_hasInsecureLoginForms_streamConverter.js]
[browser_insecurePasswordWarning.js]
[browser_notifications.js]
[browser_notifications_2.js]
[browser_passwordmgr_editing.js]
skip-if = os == "linux"
[browser_context_menu.js]
-subsuite = clipboard
+skip-if = e10s
+[browser_context_menu_iframe.js]
skip-if = e10s
[browser_passwordmgr_contextmenu.js]
subsuite = clipboard
[browser_passwordmgr_fields.js]
[browser_passwordmgr_observers.js]
[browser_passwordmgr_sort.js]
[browser_passwordmgr_switchtab.js]
[browser_passwordmgrdlg.js]
--- a/toolkit/components/passwordmgr/test/browser/browser_context_menu.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_context_menu.js
@@ -225,75 +225,16 @@ add_task(function* test_context_menu_use
}
contextMenu.hidePopup();
}
}
});
});
/**
- * Check if the password field is correctly filled when it's in an iframe.
- */
-add_task(function* test_context_menu_iframe_fill() {
- Services.prefs.setBoolPref("signon.schemeUpgrades", true);
- yield BrowserTestUtils.withNewTab({
- gBrowser,
- url: TEST_HOSTNAME + MULTIPLE_FORMS_PAGE_PATH,
- }, function* (browser) {
- let iframe = browser.contentWindow.document.getElementById("test-iframe");
- let passwordInput = iframe.contentDocument.getElementById("form-basic-password");
-
- let contextMenuShownPromise = BrowserTestUtils.waitForEvent(window, "popupshown");
- let eventDetails = {type: "contextmenu", button: 2};
-
- // To click at the right point we have to take into account the iframe offset.
- let iframeRect = iframe.getBoundingClientRect();
- let inputRect = passwordInput.getBoundingClientRect();
- let clickPos = {
- offsetX: iframeRect.left + inputRect.width / 2,
- offsetY: iframeRect.top + inputRect.height / 2,
- };
-
- // Synthesize a right mouse click over the password input element.
- BrowserTestUtils.synthesizeMouse(passwordInput, clickPos.offsetX, clickPos.offsetY, eventDetails, browser);
- yield contextMenuShownPromise;
-
- // Synthesize a mouse click over the fill login menu header.
- let popupHeader = document.getElementById("fill-login");
- let popupShownPromise = BrowserTestUtils.waitForEvent(popupHeader, "popupshown");
- EventUtils.synthesizeMouseAtCenter(popupHeader, {});
- yield popupShownPromise;
-
- let popupMenu = document.getElementById("fill-login-popup");
-
- // Stores the original value of username
- let usernameInput = iframe.contentDocument.getElementById("form-basic-username");
- let usernameOriginalValue = usernameInput.value;
-
- // Execute the command of the first login menuitem found at the context menu.
- let firstLoginItem = popupMenu.getElementsByClassName("context-login-item")[0];
- firstLoginItem.doCommand();
-
- yield BrowserTestUtils.waitForEvent(passwordInput, "input", "Password input value changed");
-
- // Find the used login by it's username.
- let login = getLoginFromUsername(firstLoginItem.label);
-
- Assert.equal(login.password, passwordInput.value, "Password filled and correct.");
-
- Assert.equal(usernameOriginalValue,
- usernameInput.value,
- "Username value was not changed.");
-
- let contextMenu = document.getElementById("contentAreaContextMenu");
- contextMenu.hidePopup();
- });
-});
-
-/**
* Synthesize mouse clicks to open the password manager context menu popup
* for a target password input element.
*
* assertCallback should return true if we should continue or else false.
*/
function* openPasswordContextMenu(browser, passwordInput, assertCallback = null) {
// Synthesize a right mouse click over the password input element.
let contextMenuShownPromise = BrowserTestUtils.waitForEvent(window, "popupshown");
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/browser/browser_context_menu_iframe.js
@@ -0,0 +1,136 @@
+/*
+ * Test the password manager context menu.
+ */
+
+"use strict";
+
+const TEST_HOSTNAME = "https://example.com";
+
+// Test with a page that only has a form within an iframe, not in the top-level document
+const IFRAME_PAGE_PATH = "/browser/toolkit/components/passwordmgr/test/browser/form_basic_iframe.html";
+
+/**
+ * Initialize logins needed for the tests and disable autofill
+ * for login forms for easier testing of manual fill.
+ */
+add_task(function* test_initialize() {
+ Services.prefs.setBoolPref("signon.autofillForms", false);
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("signon.autofillForms");
+ Services.prefs.clearUserPref("signon.schemeUpgrades");
+ });
+ for (let login of loginList()) {
+ Services.logins.addLogin(login);
+ }
+});
+
+/**
+ * Check if the password field is correctly filled when it's in an iframe.
+ */
+add_task(function* test_context_menu_iframe_fill() {
+ Services.prefs.setBoolPref("signon.schemeUpgrades", true);
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: TEST_HOSTNAME + IFRAME_PAGE_PATH
+ }, function* (browser) {
+ let iframe = browser.contentWindow.document.getElementById("test-iframe");
+ let passwordInput = iframe.contentDocument.getElementById("form-basic-password");
+
+ let contextMenuShownPromise = BrowserTestUtils.waitForEvent(window, "popupshown");
+ let eventDetails = {type: "contextmenu", button: 2};
+
+ // To click at the right point we have to take into account the iframe offset.
+ let iframeRect = iframe.getBoundingClientRect();
+ let inputRect = passwordInput.getBoundingClientRect();
+ let clickPos = {
+ offsetX: iframeRect.left + inputRect.width / 2,
+ offsetY: iframeRect.top + inputRect.height / 2,
+ };
+
+ // Synthesize a right mouse click over the password input element.
+ BrowserTestUtils.synthesizeMouse(passwordInput, clickPos.offsetX, clickPos.offsetY, eventDetails, browser);
+ yield contextMenuShownPromise;
+
+ // Synthesize a mouse click over the fill login menu header.
+ let popupHeader = document.getElementById("fill-login");
+ let popupShownPromise = BrowserTestUtils.waitForEvent(popupHeader, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(popupHeader, {});
+ yield popupShownPromise;
+
+ let popupMenu = document.getElementById("fill-login-popup");
+
+ // Stores the original value of username
+ let usernameInput = iframe.contentDocument.getElementById("form-basic-username");
+ let usernameOriginalValue = usernameInput.value;
+
+ // Execute the command of the first login menuitem found at the context menu.
+ let firstLoginItem = popupMenu.getElementsByClassName("context-login-item")[0];
+ firstLoginItem.doCommand();
+
+ yield BrowserTestUtils.waitForEvent(passwordInput, "input", "Password input value changed");
+
+ // Find the used login by it's username.
+ let login = getLoginFromUsername(firstLoginItem.label);
+
+ Assert.equal(login.password, passwordInput.value, "Password filled and correct.");
+
+ Assert.equal(usernameOriginalValue,
+ usernameInput.value,
+ "Username value was not changed.");
+
+ let contextMenu = document.getElementById("contentAreaContextMenu");
+ contextMenu.hidePopup();
+ });
+});
+
+/**
+ * Search for a login by it's username.
+ *
+ * Only unique login/hostname combinations should be used at this test.
+ */
+function getLoginFromUsername(username) {
+ return loginList().find(login => login.username == username);
+}
+
+/**
+ * List of logins used for the test.
+ *
+ * We should only use unique usernames in this test,
+ * because we need to search logins by username. There is one duplicate u+p combo
+ * in order to test de-duping in the menu.
+ */
+function loginList() {
+ return [
+ LoginTestUtils.testData.formLogin({
+ hostname: "https://example.com",
+ formSubmitURL: "https://example.com",
+ username: "username",
+ password: "password",
+ }),
+ // Same as above but HTTP in order to test de-duping.
+ LoginTestUtils.testData.formLogin({
+ hostname: "http://example.com",
+ formSubmitURL: "http://example.com",
+ username: "username",
+ password: "password",
+ }),
+ LoginTestUtils.testData.formLogin({
+ hostname: "http://example.com",
+ formSubmitURL: "http://example.com",
+ username: "username1",
+ password: "password1",
+ }),
+ LoginTestUtils.testData.formLogin({
+ hostname: "https://example.com",
+ formSubmitURL: "https://example.com",
+ username: "username2",
+ password: "password2",
+ }),
+ LoginTestUtils.testData.formLogin({
+ hostname: "http://example.org",
+ formSubmitURL: "http://example.org",
+ username: "username-cross-origin",
+ password: "password-cross-origin",
+ }),
+ ];
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/browser/form_basic_iframe.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <meta charset="utf-8">
+</head>
+
+<body>
+ <!-- Form in an iframe -->
+ <iframe src="https://example.org/browser/toolkit/components/passwordmgr/test/browser/form_basic.html" id="test-iframe"></iframe>
+</body>
+
+</html>