Bug 1174900 - Capture doorhanger password field toggle should stay hidden for master password users;r=MattN
MozReview-Commit-ID: DLlu2WhQamN
--- a/browser/components/preferences/in-content/security.js
+++ b/browser/components/preferences/in-content/security.js
@@ -1,12 +1,15 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
+XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
+ "resource://gre/modules/LoginHelper.jsm");
+
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
var gSecurityPane = {
_pane: null,
/**
* Initializes master password UI.
*/
@@ -131,17 +134,17 @@ var gSecurityPane = {
/**
* Initializes master password UI: the "use master password" checkbox, selects
* the master password button to show, and enables/disables it as necessary.
* The master password is controlled by various bits of NSS functionality, so
* the UI for it can't be controlled by the normal preference bindings.
*/
_initMasterPasswordUI: function ()
{
- var noMP = !this._masterPasswordSet();
+ var noMP = !LoginHelper.isMasterPasswordSet();
var button = document.getElementById("changeMasterPassword");
button.disabled = noMP;
var checkbox = document.getElementById("useMasterPassword");
checkbox.checked = !noMP;
},
@@ -214,35 +217,16 @@ var gSecurityPane = {
if (!blockDownloadsPref.value) {
blockUncommonUnwanted.setAttribute("disabled", "true");
}
blockUncommonUnwanted.checked = blockUnwantedPref.value && blockUncommonPref.value;
},
/**
- * Returns true if the user has a master password set and false otherwise.
- */
- _masterPasswordSet: function ()
- {
- var secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].
- getService(Ci.nsIPKCS11ModuleDB);
- var slot = secmodDB.findSlotByName("");
- if (slot) {
- var status = slot.status;
- var hasMP = status != Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED &&
- status != Ci.nsIPKCS11Slot.SLOT_READY;
- return hasMP;
- } else {
- // XXX I have no bloody idea what this means
- return false;
- }
- },
-
- /**
* Enables/disables the master password button depending on the state of the
* "use master password" checkbox, and prompts for master password removal if
* one is set.
*/
updateMasterPasswordButton: function ()
{
var checkbox = document.getElementById("useMasterPassword");
var button = document.getElementById("changeMasterPassword");
--- a/toolkit/components/passwordmgr/LoginHelper.jsm
+++ b/toolkit/components/passwordmgr/LoginHelper.jsm
@@ -640,15 +640,32 @@ this.LoginHelper = {
toDeletes.add(Path.join(profileDir, signonFile));
Services.prefs.clearUserPref(pref);
} catch (e) {}
}
for (let file of toDeletes) {
File.remove(file);
}
+ },
+
+ /**
+ * Returns true if the user has a master password set and false otherwise.
+ */
+ isMasterPasswordSet() {
+ let secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].
+ getService(Ci.nsIPKCS11ModuleDB);
+ let slot = secmodDB.findSlotByName("");
+ if (slot) {
+ let status = slot.status;
+ let hasMP = status != Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED &&
+ status != Ci.nsIPKCS11Slot.SLOT_READY;
+ return hasMP;
+ } else {
+ return false;
+ }
}
};
XPCOMUtils.defineLazyGetter(this, "log", () => {
let logger = LoginHelper.createLogger("LoginHelper");
return logger;
});
--- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
+++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
@@ -962,25 +962,24 @@ LoginManagerPrompter.prototype = {
eventCallback: function (topic) {
switch (topic) {
case "showing":
currentNotification = this;
chromeDoc.getElementById("password-notification-username")
.addEventListener("input", onInput);
chromeDoc.getElementById("password-notification-password")
.addEventListener("input", onInput);
+ let toggleBtn = chromeDoc.getElementById("password-notification-visibilityToggle");
+
if (Services.prefs.getBoolPref("signon.rememberSignons.visibilityToggle")) {
- chromeDoc.getElementById("password-notification-visibilityToggle")
- .addEventListener("command", onVisibilityToggle);
- chromeDoc.getElementById("password-notification-visibilityToggle")
- .setAttribute("label", togglePasswordLabel);
- chromeDoc.getElementById("password-notification-visibilityToggle")
- .setAttribute("accesskey", togglePasswordAccessKey);
- chromeDoc.getElementById("password-notification-visibilityToggle")
- .removeAttribute("hidden");
+ toggleBtn.addEventListener("command", onVisibilityToggle);
+ toggleBtn.setAttribute("label", togglePasswordLabel);
+ toggleBtn.setAttribute("accesskey", togglePasswordAccessKey);
+ toggleBtn.setAttribute("hidden",
+ LoginHelper.isMasterPasswordSet());
}
break;
case "shown":
writeDataToUI();
break;
case "dismissed":
readDataFromUI();
// Fall through.
--- a/toolkit/components/passwordmgr/test/LoginTestUtils.jsm
+++ b/toolkit/components/passwordmgr/test/LoginTestUtils.jsm
@@ -244,8 +244,59 @@ this.LoginTestUtils.recipes = {
if (!LoginManagerParent.recipeParentPromise) {
return null;
}
return LoginManagerParent.recipeParentPromise.then((recipeParent) => {
return recipeParent;
});
},
};
+
+this.LoginTestUtils.master = {
+ masterPassword: "omgsecret!",
+
+ enableMasterPassword() {
+ this._setMasterPassword(true);
+ },
+
+ disableMasterPassword() {
+ this._setMasterPassword(false);
+ },
+
+ _setMasterPassword(enable) {
+ let oldPW, newPW;
+ if (enable) {
+ oldPW = "";
+ newPW = this.masterPassword;
+ } else {
+ oldPW = this.masterPassword;
+ newPW = "";
+ }
+ // Set master password. Note that this does not log you in, so the next
+ // invocation of pwmgr can trigger a MP prompt.
+
+ try {
+ let status;
+ let secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
+ .getService(Ci.nsIPKCS11ModuleDB);
+ let slot = secmodDB.findSlotByName("");
+ if (slot) {
+ status = slot.status;
+ } else {
+ return false;
+ }
+
+ let pk11db = Cc["@mozilla.org/security/pk11tokendb;1"]
+ .getService(Ci.nsIPK11TokenDB);
+ let token = pk11db.findTokenByName("");
+ if (status == Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED) {
+ token.initPassword(newPW);
+ } else if (status == Ci.nsIPKCS11Slot.SLOT_READY) {
+ info("MP change from " + oldPW + " to " + newPW);
+ token.changePassword(oldPW, newPW);
+ }
+ return true;
+ } catch(e) {
+ dump("MasterPassword.setPassword: " + e);
+ }
+ return false;
+ }
+}
--- a/toolkit/components/passwordmgr/test/browser/browser_notifications_2.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_notifications_2.js
@@ -80,8 +80,45 @@ add_task(function* test_toggle_password(
Assert.ok(toggleCheckbox.checked);
Assert.equal(passwordTextbox.type, "", "Password textbox changed to plain text");
yield EventUtils.synthesizeMouseAtCenter(toggleCheckbox, {});
Assert.ok(!toggleCheckbox.checked);
Assert.equal(passwordTextbox.type, "password", "Password textbox changed to * text");
});
});
+
+/**
+ * Test that the doorhanger password toggle checkbox is disabled
+ * when the master word is set.
+ *
+ */
+add_task(function* test_checkbox_disabled_if_has_master_password() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "https://example.com/browser/toolkit/components/" +
+ "passwordmgr/test/browser/form_basic.html",
+ }, function* (browser) {
+ // Submit the form in the content page with the credentials from the test
+ // case. This will cause the doorhanger notification to be displayed.
+ let promiseShown = BrowserTestUtils.waitForEvent(PopupNotifications.panel,
+ "popupshown");
+ LoginTestUtils.master.enableMasterPassword();
+
+ yield ContentTask.spawn(browser, null,
+ function* () {
+ let doc = content.document;
+ doc.getElementById("form-basic-username").value = "username";
+ doc.getElementById("form-basic-password").value = "p";
+ doc.getElementById("form-basic").submit();
+ });
+ yield promiseShown;
+
+ let notificationElement = PopupNotifications.panel.childNodes[0];
+ let passwordTextbox = notificationElement.querySelector("#password-notification-password");
+ let toggleCheckbox = notificationElement.querySelector("#password-notification-visibilityToggle");
+
+ Assert.equal(passwordTextbox.type, "password", "Password textbox should show * text");
+ Assert.ok(toggleCheckbox.getAttribute("hidden"), "checkbox is hidden when master password is set");
+
+ LoginTestUtils.master.disableMasterPassword();
+ });
+});