Bug 1121291 - Remove "Show Passwords" button from pwmgr and allow inline password editing. r=Dolske,rchtara
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Mon, 21 Sep 2015 14:19:28 -0700
changeset 263581 e4e3a8b66db489efcf3a87e3c954614ed1b2b9ff
parent 263580 b59d92a6d64b0d740cbf7d4e067ed3cdcecf8cc9
child 263582 65b643d6e5f35e20c456efc4aa0e9ef4ba7c74a7
push id29414
push usercbook@mozilla.com
push dateTue, 22 Sep 2015 10:19:39 +0000
treeherdermozilla-central@f4f27148d24c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersDolske, rchtara
bugs1121291
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1121291 - Remove "Show Passwords" button from pwmgr and allow inline password editing. r=Dolske,rchtara
toolkit/components/passwordmgr/content/passwordManager.js
toolkit/components/passwordmgr/content/passwordManager.xul
toolkit/components/passwordmgr/test/browser/browser_passwordmgr_contextmenu.js
toolkit/components/passwordmgr/test/browser/browser_passwordmgr_editing.js
toolkit/components/passwordmgr/test/browser/browser_passwordmgr_sort.js
toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js
toolkit/components/telemetry/Histograms.json
toolkit/locales/en-US/chrome/passwordmgr/passwordmgr.properties
--- a/toolkit/components/passwordmgr/content/passwordManager.js
+++ b/toolkit/components/passwordmgr/content/passwordManager.js
@@ -1,26 +1,23 @@
 /* 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/. */
 
 /*** =================== SAVED SIGNONS CODE =================== ***/
 
 var kSignonBundle;
-var showingPasswords = false;
 var dateFormatter = new Intl.DateTimeFormat(undefined,
                       { day: "numeric", month: "short", year: "numeric" });
 var dateAndTimeFormatter = new Intl.DateTimeFormat(undefined,
                              { day: "numeric", month: "short", year: "numeric",
                                hour: "numeric", minute: "numeric" });
 
 function SignonsStartup() {
   kSignonBundle = document.getElementById("signonBundle");
-  document.getElementById("togglePasswords").label = kSignonBundle.getString("showPasswords");
-  document.getElementById("togglePasswords").accessKey = kSignonBundle.getString("showPasswordsAccessKey");
   document.getElementById("signonsIntro").textContent = kSignonBundle.getString("loginsDescriptionAll");
 
   let treecols = document.getElementsByTagName("treecols")[0];
   treecols.addEventListener("click", HandleTreeColumnClick.bind(null, SignonColumnSort));
 
   LoadSignons();
 
   // filter the table if requested by caller
@@ -74,19 +71,24 @@ var signonsTreeView = {
         return dateFormatter.format(time);
       case "timesUsedCol":
         return signon.timesUsed;
       default:
         return "";
     }
   },
   isEditable : function(row, col) {
-    if (col.id == "userCol" || col.id == "passwordCol") {
+    if (col.id == "userCol") {
       return true;
     }
+
+    if (col.id == "passwordCol") {
+      return masterPasswordLogin();
+    }
+
     return false;
   },
   isSeparator : function(index) { return false; },
   isSorted : function() { return false; },
   isContainer : function(index) { return false; },
   cycleHeader : function(column) {},
   getRowProperties : function(row) { return ""; },
   getColumnProperties : function(column) { return ""; },
@@ -123,38 +125,36 @@ var signonsTreeView = {
 };
 
 
 function LoadSignons() {
   // loads signons into table
   try {
     signons = passwordmanager.getAllLogins();
   } catch (e) {
-    signons = [];
+    window.close();
+    return;
   }
   signons.forEach(login => login.QueryInterface(Components.interfaces.nsILoginMetaInfo));
   signonsTreeView.rowCount = signons.length;
 
   // sort and display the table
   signonsTree.view = signonsTreeView;
   // The sort column didn't change. SortTree (called by
   // SignonColumnSort) assumes we want to toggle the sort
   // direction but here we don't so we have to trick it
   lastSignonSortAscending = !lastSignonSortAscending;
   SignonColumnSort(lastSignonSortColumn);
 
   // disable "remove all signons" button if there are no signons
   var element = document.getElementById("removeAllSignons");
-  var toggle = document.getElementById("togglePasswords");
   if (signons.length == 0) {
     element.setAttribute("disabled","true");
-    toggle.setAttribute("disabled","true");
   } else {
     element.removeAttribute("disabled");
-    toggle.removeAttribute("disabled");
   }
 
   return true;
 }
 
 function SignonSelected() {
   var selections = GetTreeSelections(signonsTree);
   if (selections.length) {
@@ -186,44 +186,16 @@ function DeleteAllSignons() {
   var syncNeeded = (signonsTreeView._filterSet.length != 0);
   DeleteAllFromTree(signonsTree, signonsTreeView,
                         signonsTreeView._filterSet.length ? signonsTreeView._filterSet : signons,
                         deletedSignons, "removeSignon", "removeAllSignons");
   FinalizeSignonDeletions(syncNeeded);
   Services.telemetry.getHistogramById("PWMGR_MANAGE_DELETED_ALL").add(1);
 }
 
-function TogglePasswordVisible() {
-  if (showingPasswords || masterPasswordLogin(AskUserShowPasswords)) {
-    showingPasswords = !showingPasswords;
-    document.getElementById("togglePasswords").label = kSignonBundle.getString(showingPasswords ? "hidePasswords" : "showPasswords");
-    document.getElementById("togglePasswords").accessKey = kSignonBundle.getString(showingPasswords ? "hidePasswordsAccessKey" : "showPasswordsAccessKey");
-    document.getElementById("passwordCol").hidden = !showingPasswords;
-    _filterPasswords();
-  }
-
-  // Notify observers that the password visibility toggling is
-  // completed.  (Mostly useful for tests)
-  Components.classes["@mozilla.org/observer-service;1"]
-            .getService(Components.interfaces.nsIObserverService)
-            .notifyObservers(null, "passwordmgr-password-toggle-complete", null);
-  Services.telemetry.getHistogramById("PWMGR_MANAGE_VISIBILITY_TOGGLED").add(showingPasswords);
-}
-
-function AskUserShowPasswords() {
-  var prompter = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
-  var dummy = { value: false };
-
-  // Confirm the user wants to display passwords
-  return prompter.confirmEx(window,
-          null,
-          kSignonBundle.getString("noMasterPasswordPrompt"), prompter.STD_YES_NO_BUTTONS,
-          null, null, null, null, dummy) == 0;    // 0=="Yes" button
-}
-
 function FinalizeSignonDeletions(syncNeeded) {
   for (var s=0; s<deletedSignons.length; s++) {
     passwordmanager.removeLogin(deletedSignons[s]);
     Services.telemetry.getHistogramById("PWMGR_MANAGE_DELETED").add(1);
   }
   // If the deletion has been performed in a filtered view, reflect the deletion in the unfiltered table.
   // See bug 405389.
   if (syncNeeded) {
@@ -327,17 +299,17 @@ function SignonMatchesFilter(aSignon, aF
   if (aSignon.hostname.toLowerCase().indexOf(aFilterValue) != -1)
     return true;
   if (aSignon.username &&
       aSignon.username.toLowerCase().indexOf(aFilterValue) != -1)
     return true;
   if (aSignon.httpRealm &&
       aSignon.httpRealm.toLowerCase().indexOf(aFilterValue) != -1)
     return true;
-  if (showingPasswords && aSignon.password &&
+  if (Services.logins.isLoggedIn && aSignon.password &&
       aSignon.password.toLowerCase().indexOf(aFilterValue) != -1)
     return true;
 
   return false;
 }
 
 function FilterPasswords(aFilterValue, view) {
   aFilterValue = aFilterValue.toLowerCase();
@@ -383,19 +355,18 @@ function _filterPasswords()
   // if the view is not empty then select the first item
   if (signonsTreeView.rowCount > 0)
     signonsTreeView.selection.select(0);
 
   document.getElementById("signonsIntro").textContent = kSignonBundle.getString("loginsDescriptionFiltered");
 }
 
 function CopyPassword() {
-  // Don't copy passwords if we aren't already showing the passwords & a master
-  // password hasn't been entered.
-  if (!showingPasswords && !masterPasswordLogin())
+  // Don't copy passwords if a master password hasn't been entered.
+  if (!masterPasswordLogin())
     return;
   // Copy selected signon's password to clipboard
   var clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"].
                   getService(Components.interfaces.nsIClipboardHelper);
   var row = document.getElementById("signonsTree").currentIndex;
   var password = signonsTreeView.getCellText(row, {id : "passwordCol" });
   clipboard.copyString(password);
   Services.telemetry.getHistogramById("PWMGR_MANAGE_COPIED_PASSWORD").add(1);
@@ -438,23 +409,17 @@ function UpdateContextMenu() {
   if (signonsTreeView.getCellText(selectedRow, { id: "userCol" }) != "") {
     menuItems.get("context-copyusername").removeAttribute("disabled");
   } else {
     menuItems.get("context-copyusername").setAttribute("disabled", "true");
   }
 
   menuItems.get("context-editusername").removeAttribute("disabled");
   menuItems.get("context-copypassword").removeAttribute("disabled");
-
-  // Disable "Edit Password" if the password column isn't showing.
-  if (!document.getElementById("passwordCol").hidden) {
-    menuItems.get("context-editpassword").removeAttribute("disabled");
-  } else {
-    menuItems.get("context-editpassword").setAttribute("disabled", "true");
-  }
+  menuItems.get("context-editpassword").removeAttribute("disabled");
 }
 
 function masterPasswordLogin(noPasswordCallback) {
   // This doesn't harm if passwords are not encrypted
   var tokendb = Components.classes["@mozilla.org/security/pk11tokendb;1"]
                     .createInstance(Components.interfaces.nsIPK11TokenDB);
   var token = tokendb.getInternalKeyToken();
 
--- a/toolkit/components/passwordmgr/content/passwordManager.xul
+++ b/toolkit/components/passwordmgr/content/passwordManager.xul
@@ -77,19 +77,18 @@
                  ignoreincolumnpicker="true"
                  sortDirection="ascending"/>
         <splitter class="tree-splitter"/>
         <treecol id="userCol" label="&treehead.username.label;" flex="25"
                  ignoreincolumnpicker="true"
                  data-field-name="username" persist="width"/>
         <splitter class="tree-splitter"/>
         <treecol id="passwordCol" label="&treehead.password.label;" flex="15"
-                 ignoreincolumnpicker="true"
-                 data-field-name="password" persist="width"
-                 hidden="true"/>
+                 data-field-name="password" persist="width hidden"
+                 type="password"/>
         <splitter class="tree-splitter"/>
         <treecol id="timeCreatedCol" label="&treehead.timeCreated.label;" flex="10"
                  data-field-name="timeCreated" persist="width hidden"
                  hidden="true"/>
         <splitter class="tree-splitter"/>
         <treecol id="timeLastUsedCol" label="&treehead.timeLastUsed.label;" flex="20"
                  data-field-name="timeLastUsed" persist="width hidden"/>
         <splitter class="tree-splitter"/>
@@ -112,18 +111,16 @@
               label="&removeall.label;" accesskey="&removeall.accesskey;"
               oncommand="DeleteAllSignons();"/>
       <spacer flex="1"/>
 #if defined(MOZ_BUILD_APP_IS_BROWSER) && defined(XP_WIN)
       <button accesskey="&import.accesskey;"
               label="&import.label;"
               oncommand="OpenMigrator();"/>
 #endif
-      <button id="togglePasswords"
-              oncommand="TogglePasswordVisible();"/>
     </hbox>
   </vbox>
   <hbox align="end">
     <hbox class="actionButtons" flex="1">
       <spacer flex="1"/>
 #ifndef XP_MACOSX
       <button oncommand="close();" icon="close"
               label="&closebutton.label;" accesskey="&closebutton.accesskey;"/>
--- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_contextmenu.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_contextmenu.js
@@ -45,28 +45,27 @@ function test() {
             assertMenuitemEnabled("copypassword", false);
             assertMenuitemEnabled("editpassword", false);
 
             info("Select the first row (with an empty username)");
             selection.select(0);
             assertMenuitemEnabled("copyusername", false, "empty username");
             assertMenuitemEnabled("editusername", true);
             assertMenuitemEnabled("copypassword", true);
-            assertMenuitemEnabled("editpassword", false, "password column hidden");
+            assertMenuitemEnabled("editpassword", true);
 
             info("Clear the selection");
             selection.clearSelection();
             assertMenuitemEnabled("copyusername", false);
             assertMenuitemEnabled("editusername", false);
             assertMenuitemEnabled("copypassword", false);
             assertMenuitemEnabled("editpassword", false);
 
             info("Select the third row and making the password column visible");
             selection.select(2);
-            doc.getElementById("passwordCol").hidden = false;
             assertMenuitemEnabled("copyusername", true);
             assertMenuitemEnabled("editusername", true);
             assertMenuitemEnabled("copypassword", true);
             assertMenuitemEnabled("editpassword", true, "password column visible");
             menuitem.doCommand();
         }
 
         function assertMenuitemEnabled(idSuffix, expected, reason = "") {
@@ -75,17 +74,16 @@ function test() {
             is(actual, expected, idSuffix + " should be " + (expected ? "enabled" : "disabled") +
                (reason ? ": " + reason : ""));
         }
 
         function cleanUp() {
             Services.ww.registerNotification(function (aSubject, aTopic, aData) {
                 Services.ww.unregisterNotification(arguments.callee);
                 Services.logins.removeAllLogins();
-                doc.getElementById("passwordCol").hidden = true;
                 finish();
             });
             pwmgrdlg.close();
         }
 
         function testPassword() {
             info("Testing Copy Password");
             waitForClipboard("coded", function copyPassword() {
--- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_editing.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_editing.js
@@ -27,21 +27,16 @@ function synthesizeDblClickOnCell(aTree,
   let rect = tbo.getCoordsForCellItem(row, aTree.columns[column], "text");
   let x = rect.x + rect.width / 2;
   let y = rect.y + rect.height / 2;
   // Simulate the double click.
   EventUtils.synthesizeMouse(aTree.body, x, y, { clickCount: 2 },
                              aTree.ownerDocument.defaultView);
 }
 
-function* togglePasswords() {
-  pwmgrdlg.document.querySelector("#togglePasswords").doCommand();
-  yield new Promise(resolve => waitForFocus(resolve, pwmgrdlg));
-}
-
 function* editUsernamePromises(site, oldUsername, newUsername) {
   is(Services.logins.findLogins({}, site, "", "").length, 1, "Correct login found");
   let login = Services.logins.findLogins({}, site, "", "")[0];
   is(login.username, oldUsername, "Correct username saved");
   is(getUsername(0), oldUsername, "Correct username shown");
   synthesizeDblClickOnCell(signonsTree, 1, 0);
   yield ContentTaskUtils.waitForCondition(() => signonsTree.getAttribute("editing"),
                                           "Waiting for editing");
@@ -109,19 +104,17 @@ add_task(function* test_setup() {
     }, pwmgrdlg);
   });
 });
 
 add_task(function* test_edit_multiple_logins() {
   function* testLoginChange(site, oldUsername, oldPassword, newUsername, newPassword) {
     addLogin(site, oldUsername, oldPassword);
     yield* editUsernamePromises(site, oldUsername, newUsername);
-    yield* togglePasswords();
     yield* editPasswordPromises(site, oldPassword, newPassword);
-    yield* togglePasswords();
   }
 
   yield* testLoginChange("http://c.tn/", "userC", "passC", "usernameC", "passwordC");
   yield* testLoginChange("http://b.tn/", "userB", "passB", "usernameB", "passwordB");
   yield* testLoginChange("http://a.tn/", "userA", "passA", "usernameA", "passwordA");
 
   pwmgrdlg.close();
 });
--- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_sort.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_sort.js
@@ -62,45 +62,16 @@ function test() {
         let doc = pwmgrdlg.document;
         let win = doc.defaultView;
         let sTree = doc.getElementById("signonsTree");
         let filter = doc.getElementById("filter");
         let siteCol = doc.getElementById("siteCol");
         let userCol = doc.getElementById("userCol");
         let passwordCol = doc.getElementById("passwordCol");
 
-        let toggleCalls = 0;
-        function toggleShowPasswords(func) {
-            let toggleButton = doc.getElementById("togglePasswords");
-            let showMode = (toggleCalls++ % 2) == 0;
-
-            // only watch for a confirmation dialog every other time being called
-            if (showMode) {
-                Services.ww.registerNotification(function (aSubject, aTopic, aData) {
-                    if (aTopic == "domwindowclosed")
-                        Services.ww.unregisterNotification(arguments.callee);
-                    else if (aTopic == "domwindowopened") {
-                        let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
-                        SimpleTest.waitForFocus(function() {
-                            EventUtils.sendKey("RETURN", win);
-                        }, win);
-                    }
-                });
-            }
-
-            Services.obs.addObserver(function (aSubject, aTopic, aData) {
-                if (aTopic == "passwordmgr-password-toggle-complete") {
-                    Services.obs.removeObserver(arguments.callee, aTopic);
-                    func();
-                }
-            }, "passwordmgr-password-toggle-complete", false);
-
-            EventUtils.synthesizeMouse(toggleButton, 1, 1, {}, win);
-        }
-
         function clickCol(col) {
             EventUtils.synthesizeMouse(col, 20, 1, {}, win);
             setTimeout(runNextTest, 0);
         }
 
         function setFilter(string) {
             filter.value = string;
             filter.doCommand();
@@ -197,12 +168,11 @@ function test() {
 
                     pwmgr.removeAllLogins();
                     finish();
                 });
                 pwmgrdlg.close();
             }
         }
 
-        // Toggle Show Passwords to display Password column, then start tests
-        toggleShowPasswords(runNextTest);
+        runNextTest();
     }
 }
--- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js
@@ -52,98 +52,44 @@ function test() {
         let view = tree.view;
 
         is(filter.value, "", "Filter box should initially be empty");
         is(view.rowCount, 10, "There should be 10 passwords initially");
 
         // Prepare a set of tests
         //   filter: the text entered in the filter search box
         //   count: the number of logins which should match the respective filter
-        //   count2: the number of logins which should match the respective filter
-        //           if the passwords are being shown as well
-        //   Note: if a test doesn't have count2 set, count is used instead.
         let tests = [
-            {filter: "pass", count: 0, count2: 4},
+            {filter: "pass", count: 4},
             {filter: "", count: 10}, // test clearing the filter
             {filter: "moz", count: 7},
             {filter: "mozi", count: 7},
             {filter: "mozil", count: 7},
             {filter: "mozill", count: 7},
             {filter: "mozilla", count: 7},
-            {filter: "mozilla.com", count: 1, count2: 2},
+            {filter: "mozilla.com", count: 2},
             {filter: "user", count: 4},
             {filter: "user ", count: 1},
             {filter: " user", count: 2},
             {filter: "http", count: 10},
             {filter: "https", count: 1},
-            {filter: "secret", count: 0, count2: 2},
+            {filter: "secret", count: 2},
             {filter: "secret!", count: 0},
         ];
 
-        let toggleCalls = 0;
-        function toggleShowPasswords(func) {
-            let toggleButton = doc.getElementById("togglePasswords");
-            let showMode = (toggleCalls++ % 2) == 0;
-
-            // only watch for a confirmation dialog every other time being called
-            if (showMode) {
-                Services.ww.registerNotification(function (aSubject, aTopic, aData) {
-                    if (aTopic == "domwindowclosed")
-                        Services.ww.unregisterNotification(arguments.callee);
-                    else if (aTopic == "domwindowopened") {
-                        let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
-                        SimpleTest.waitForFocus(function() {
-                            EventUtils.sendKey("RETURN", win);
-                        }, win);
-                    }
-                });
-            }
-
-            Services.obs.addObserver(function (aSubject, aTopic, aData) {
-                if (aTopic == "passwordmgr-password-toggle-complete") {
-                    Services.obs.removeObserver(arguments.callee, aTopic);
-                    func();
-                }
-            }, "passwordmgr-password-toggle-complete", false);
-
-            EventUtils.synthesizeMouse(toggleButton, 1, 1, {}, win);
-        }
-
-        function runTests(mode, endFunction) {
+        function runTests(endFunction) {
             let testCounter = 0;
 
             function setFilter(string) {
                 filter.value = string;
                 filter.doCommand();
             }
 
             function runOneTest(test) {
-                function tester() {
-                    is(view.rowCount, expected, expected + " logins should match '" + test.filter + "'");
-                }
-
-                let expected;
-                switch (mode) {
-                case 1: // without showing passwords
-                    expected = test.count;
-                    break;
-                case 2: // showing passwords
-                    expected = ("count2" in test) ? test.count2 : test.count;
-                    break;
-                case 3: // toggle
-                    expected = test.count;
-                    tester();
-                    toggleShowPasswords(function () {
-                        expected = ("count2" in test) ? test.count2 : test.count;
-                        tester();
-                        toggleShowPasswords(proceed);
-                    });
-                    return;
-                }
-                tester();
+                is(view.rowCount, test.count, test.count + " logins should match '" + test.filter + "'");
                 proceed();
             }
 
             function proceed() {
                 // run the next test if necessary or proceed with the tests
                 if (testCounter != tests.length)
                     runNextTest();
                 else
@@ -155,29 +101,17 @@ function test() {
                 setFilter(test.filter);
                 setTimeout(runOneTest, 0, test);
             }
 
             runNextTest();
         }
 
         function step1() {
-            runTests(1, step2);
-        }
-
-        function step2() {
-            toggleShowPasswords(function() {
-                runTests(2, step3);
-            });
-        }
-
-        function step3() {
-            toggleShowPasswords(function() {
-                runTests(3, lastStep);
-            });
+            runTests(lastStep);
         }
 
         function lastStep() {
             // cleanup
             Services.ww.registerNotification(function (aSubject, aTopic, aData) {
                 // unregister ourself
                 Services.ww.unregisterNotification(arguments.callee);
 
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -8637,21 +8637,16 @@
     "description": "Accumulates how the password management interface was opened. (0=Preferences, 1=Page Info)"
   },
   "PWMGR_MANAGE_SORTED": {
     "expires_in_version": "never",
     "keyed": true,
     "kind": "count",
     "description": "Reports the column that logins are sorted by"
   },
-  "PWMGR_MANAGE_VISIBILITY_TOGGLED": {
-    "expires_in_version": "never",
-    "kind": "boolean",
-    "description": "Whether the visibility of passwords was toggled (0=Hide, 1=Show)"
-  },
   "PWMGR_NUM_PASSWORDS_PER_HOSTNAME": {
     "expires_in_version": "never",
     "kind": "linear",
     "high": 21,
     "n_buckets" : 20,
     "description": "The number of passwords per hostname"
   },
   "PWMGR_NUM_SAVED_PASSWORDS": {
--- a/toolkit/locales/en-US/chrome/passwordmgr/passwordmgr.properties
+++ b/toolkit/locales/en-US/chrome/passwordmgr/passwordmgr.properties
@@ -42,21 +42,16 @@ passwordChangeTitle = Confirm Password C
 # String is the username for the login.
 updatePasswordMsg = Would you like to update the saved password for "%S"?
 updatePasswordMsgNoUser = Would you like to update the saved password?
 notifyBarUpdateButtonText = Update Password
 notifyBarUpdateButtonAccessKey = U
 notifyBarDontChangeButtonText = Don't Change
 notifyBarDontChangeButtonAccessKey = D
 userSelectText = Please confirm which user you are changing the password for
-hidePasswords=Hide Passwords
-hidePasswordsAccessKey=P
-showPasswords=Show Passwords
-showPasswordsAccessKey=P
-noMasterPasswordPrompt=Are you sure you wish to show your passwords?
 removeAllPasswordsPrompt=Are you sure you wish to remove all passwords?
 removeAllPasswordsTitle=Remove all passwords
 removeLoginPrompt=Are you sure you wish to remove this login?
 removeLoginTitle=Remove login
 loginsDescriptionAll=Logins for the following sites are stored on your computer:
 loginsDescriptionFiltered=The following logins match your search:
 # LOCALIZATION NOTE (loginHostAge):
 # This is used to show the context menu login items with their age.