diff --git a/toolkit/components/passwordmgr/LoginManagerContent.jsm b/toolkit/components/passwordmgr/LoginManagerContent.jsm index 78227717b4de..9d992357ca62 100644 --- a/toolkit/components/passwordmgr/LoginManagerContent.jsm +++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm @@ -663,10 +663,17 @@ var LoginManagerContent = { // already logged in to the site. for (var i = pwFields[0].index - 1; i >= 0; i--) { var element = form.elements[i]; - if (LoginHelper.isUsernameFieldType(element)) { - usernameField = element; - break; + if (!LoginHelper.isUsernameFieldType(element)) { + continue; } + + if (fieldOverrideRecipe && fieldOverrideRecipe.notUsernameSelector && + element.matches(fieldOverrideRecipe.notUsernameSelector)) { + continue; + } + + usernameField = element; + break; } } diff --git a/toolkit/components/passwordmgr/LoginRecipes.jsm b/toolkit/components/passwordmgr/LoginRecipes.jsm index c8c26b26f3a6..c556636318cb 100644 --- a/toolkit/components/passwordmgr/LoginRecipes.jsm +++ b/toolkit/components/passwordmgr/LoginRecipes.jsm @@ -8,7 +8,7 @@ this.EXPORTED_SYMBOLS = ["LoginRecipesContent", "LoginRecipesParent"]; const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; const REQUIRED_KEYS = ["hosts"]; -const OPTIONAL_KEYS = ["description", "passwordSelector", "pathRegex", "usernameSelector"]; +const OPTIONAL_KEYS = ["description", "notUsernameSelector", "passwordSelector", "pathRegex", "usernameSelector"]; const SUPPORTED_KEYS = REQUIRED_KEYS.concat(OPTIONAL_KEYS); Cu.importGlobalProperties(["URL"]); @@ -227,7 +227,8 @@ var LoginRecipesContent = { let chosenRecipe = null; // Find the first (most-specific recipe that involves field overrides). for (let recipe of recipes) { - if (!recipe.usernameSelector && !recipe.passwordSelector) { + if (!recipe.usernameSelector && !recipe.passwordSelector && + !recipe.notUsernameSelector) { continue; } diff --git a/toolkit/components/passwordmgr/content/recipes.json b/toolkit/components/passwordmgr/content/recipes.json index 5a3738e46bf6..fc747219b481 100644 --- a/toolkit/components/passwordmgr/content/recipes.json +++ b/toolkit/components/passwordmgr/content/recipes.json @@ -21,6 +21,11 @@ "usernameSelector": "#accountname, input[name='loginname']", "passwordSelector": "#password1, input[name='loginpassword']", "pathRegex": "^\/account\/" + }, + { + "description": "Username field will be incorrectly captured in the change password form (bug 1243722)", + "hosts": ["www.facebook.com"], + "notUsernameSelector": "#password_strength" } ] } diff --git a/toolkit/components/passwordmgr/test/mochitest/test_recipe_login_fields.html b/toolkit/components/passwordmgr/test/mochitest/test_recipe_login_fields.html index b616fc2b4da7..943bffc522d8 100644 --- a/toolkit/components/passwordmgr/test/mochitest/test_recipe_login_fields.html +++ b/toolkit/components/passwordmgr/test/mochitest/test_recipe_login_fields.html @@ -4,21 +4,53 @@ Test for recipes overriding login fields + + -

diff --git a/toolkit/components/passwordmgr/test/pwmgr_common.js b/toolkit/components/passwordmgr/test/pwmgr_common.js index abc06e10b8ad..bfdfdd52754e 100644 --- a/toolkit/components/passwordmgr/test/pwmgr_common.js +++ b/toolkit/components/passwordmgr/test/pwmgr_common.js @@ -282,6 +282,26 @@ function promiseFormsProcessed(expectedCount = 1) { }); } +function loadRecipes(recipes) { + return new Promise(resolve => { + chromeScript.addMessageListener("loadedRecipes", function loaded() { + chromeScript.removeMessageListener("loadedRecipes", loaded); + resolve(recipes); + }); + chromeScript.sendAsyncMessage("loadRecipes", recipes); + }); +} + +function resetRecipes() { + return new Promise(resolve => { + chromeScript.addMessageListener("recipesReset", function reset() { + chromeScript.removeMessageListener("recipesReset", reset); + resolve(); + }); + chromeScript.sendAsyncMessage("resetRecipes"); + }); +} + /** * Run a function synchronously in the parent process and destroy it in the test cleanup function. * @param {Function|String} aFunctionOrURL - either a function that will be stringified and run @@ -310,6 +330,7 @@ function runChecksAfterCommonInit(aFunction = null) { pwmgrCommonScript.addMessageListener("registerRunTests", () => registerRunTests()); } pwmgrCommonScript.sendSyncMessage("setupParent"); + return pwmgrCommonScript; } // Code to run when loaded as a chrome script in tests via loadChromeScript @@ -334,6 +355,13 @@ if (this.addMessageListener) { sendAsyncMessage("loadedRecipes", recipes); })); + addMessageListener("resetRecipes", Task.async(function* resetRecipes() { + let { LoginManagerParent } = Cu.import("resource://gre/modules/LoginManagerParent.jsm", {}); + let recipeParent = yield LoginManagerParent.recipeParentPromise; + yield recipeParent.reset(); + sendAsyncMessage("recipesReset"); + })); + var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager); globalMM.addMessageListener("RemoteLogins:onFormSubmit", function onFormSubmit(message) { sendAsyncMessage("formSubmissionProcessed", message.data, message.objects);