toolkit/components/passwordmgr/content/passwordManager.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 // -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /*** =================== SAVED SIGNONS CODE =================== ***/
michael@0 8
michael@0 9 var kSignonBundle;
michael@0 10 var showingPasswords = false;
michael@0 11
michael@0 12 function SignonsStartup() {
michael@0 13 kSignonBundle = document.getElementById("signonBundle");
michael@0 14 document.getElementById("togglePasswords").label = kSignonBundle.getString("showPasswords");
michael@0 15 document.getElementById("togglePasswords").accessKey = kSignonBundle.getString("showPasswordsAccessKey");
michael@0 16 document.getElementById("signonsIntro").textContent = kSignonBundle.getString("loginsSpielAll");
michael@0 17 LoadSignons();
michael@0 18
michael@0 19 // filter the table if requested by caller
michael@0 20 if (window.arguments &&
michael@0 21 window.arguments[0] &&
michael@0 22 window.arguments[0].filterString)
michael@0 23 setFilter(window.arguments[0].filterString);
michael@0 24
michael@0 25 FocusFilterBox();
michael@0 26 }
michael@0 27
michael@0 28 function setFilter(aFilterString) {
michael@0 29 document.getElementById("filter").value = aFilterString;
michael@0 30 _filterPasswords();
michael@0 31 }
michael@0 32
michael@0 33 var signonsTreeView = {
michael@0 34 _filterSet : [],
michael@0 35 _lastSelectedRanges : [],
michael@0 36 selection: null,
michael@0 37
michael@0 38 rowCount : 0,
michael@0 39 setTree : function(tree) {},
michael@0 40 getImageSrc : function(row,column) {},
michael@0 41 getProgressMode : function(row,column) {},
michael@0 42 getCellValue : function(row,column) {},
michael@0 43 getCellText : function(row,column) {
michael@0 44 var signon = this._filterSet.length ? this._filterSet[row] : signons[row];
michael@0 45 switch (column.id) {
michael@0 46 case "siteCol":
michael@0 47 return signon.httpRealm ?
michael@0 48 (signon.hostname + " (" + signon.httpRealm + ")"):
michael@0 49 signon.hostname;
michael@0 50 case "userCol":
michael@0 51 return signon.username || "";
michael@0 52 case "passwordCol":
michael@0 53 return signon.password || "";
michael@0 54 default:
michael@0 55 return "";
michael@0 56 }
michael@0 57 },
michael@0 58 isSeparator : function(index) { return false; },
michael@0 59 isSorted : function() { return false; },
michael@0 60 isContainer : function(index) { return false; },
michael@0 61 cycleHeader : function(column) {},
michael@0 62 getRowProperties : function(row) { return ""; },
michael@0 63 getColumnProperties : function(column) { return ""; },
michael@0 64 getCellProperties : function(row,column) {
michael@0 65 if (column.element.getAttribute("id") == "siteCol")
michael@0 66 return "ltr";
michael@0 67
michael@0 68 return "";
michael@0 69 }
michael@0 70 };
michael@0 71
michael@0 72
michael@0 73 function LoadSignons() {
michael@0 74 // loads signons into table
michael@0 75 try {
michael@0 76 signons = passwordmanager.getAllLogins();
michael@0 77 } catch (e) {
michael@0 78 signons = [];
michael@0 79 }
michael@0 80 signonsTreeView.rowCount = signons.length;
michael@0 81
michael@0 82 // sort and display the table
michael@0 83 signonsTree.treeBoxObject.view = signonsTreeView;
michael@0 84 // The sort column didn't change. SortTree (called by
michael@0 85 // SignonColumnSort) assumes we want to toggle the sort
michael@0 86 // direction but here we don't so we have to trick it
michael@0 87 lastSignonSortAscending = !lastSignonSortAscending;
michael@0 88 SignonColumnSort(lastSignonSortColumn);
michael@0 89
michael@0 90 // disable "remove all signons" button if there are no signons
michael@0 91 var element = document.getElementById("removeAllSignons");
michael@0 92 var toggle = document.getElementById("togglePasswords");
michael@0 93 if (signons.length == 0) {
michael@0 94 element.setAttribute("disabled","true");
michael@0 95 toggle.setAttribute("disabled","true");
michael@0 96 } else {
michael@0 97 element.removeAttribute("disabled");
michael@0 98 toggle.removeAttribute("disabled");
michael@0 99 }
michael@0 100
michael@0 101 return true;
michael@0 102 }
michael@0 103
michael@0 104 function SignonSelected() {
michael@0 105 var selections = GetTreeSelections(signonsTree);
michael@0 106 if (selections.length) {
michael@0 107 document.getElementById("removeSignon").removeAttribute("disabled");
michael@0 108 }
michael@0 109 }
michael@0 110
michael@0 111 function DeleteSignon() {
michael@0 112 var syncNeeded = (signonsTreeView._filterSet.length != 0);
michael@0 113 DeleteSelectedItemFromTree(signonsTree, signonsTreeView,
michael@0 114 signonsTreeView._filterSet.length ? signonsTreeView._filterSet : signons,
michael@0 115 deletedSignons, "removeSignon", "removeAllSignons");
michael@0 116 FinalizeSignonDeletions(syncNeeded);
michael@0 117 }
michael@0 118
michael@0 119 function DeleteAllSignons() {
michael@0 120 var prompter = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
michael@0 121 .getService(Components.interfaces.nsIPromptService);
michael@0 122
michael@0 123 // Confirm the user wants to remove all passwords
michael@0 124 var dummy = { value: false };
michael@0 125 if (prompter.confirmEx(window,
michael@0 126 kSignonBundle.getString("removeAllPasswordsTitle"),
michael@0 127 kSignonBundle.getString("removeAllPasswordsPrompt"),
michael@0 128 prompter.STD_YES_NO_BUTTONS + prompter.BUTTON_POS_1_DEFAULT,
michael@0 129 null, null, null, null, dummy) == 1) // 1 == "No" button
michael@0 130 return;
michael@0 131
michael@0 132 var syncNeeded = (signonsTreeView._filterSet.length != 0);
michael@0 133 DeleteAllFromTree(signonsTree, signonsTreeView,
michael@0 134 signonsTreeView._filterSet.length ? signonsTreeView._filterSet : signons,
michael@0 135 deletedSignons, "removeSignon", "removeAllSignons");
michael@0 136 FinalizeSignonDeletions(syncNeeded);
michael@0 137 }
michael@0 138
michael@0 139 function TogglePasswordVisible() {
michael@0 140 if (showingPasswords || masterPasswordLogin(AskUserShowPasswords)) {
michael@0 141 showingPasswords = !showingPasswords;
michael@0 142 document.getElementById("togglePasswords").label = kSignonBundle.getString(showingPasswords ? "hidePasswords" : "showPasswords");
michael@0 143 document.getElementById("togglePasswords").accessKey = kSignonBundle.getString(showingPasswords ? "hidePasswordsAccessKey" : "showPasswordsAccessKey");
michael@0 144 document.getElementById("passwordCol").hidden = !showingPasswords;
michael@0 145 _filterPasswords();
michael@0 146 }
michael@0 147
michael@0 148 // Notify observers that the password visibility toggling is
michael@0 149 // completed. (Mostly useful for tests)
michael@0 150 Components.classes["@mozilla.org/observer-service;1"]
michael@0 151 .getService(Components.interfaces.nsIObserverService)
michael@0 152 .notifyObservers(null, "passwordmgr-password-toggle-complete", null);
michael@0 153 }
michael@0 154
michael@0 155 function AskUserShowPasswords() {
michael@0 156 var prompter = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
michael@0 157 var dummy = { value: false };
michael@0 158
michael@0 159 // Confirm the user wants to display passwords
michael@0 160 return prompter.confirmEx(window,
michael@0 161 null,
michael@0 162 kSignonBundle.getString("noMasterPasswordPrompt"), prompter.STD_YES_NO_BUTTONS,
michael@0 163 null, null, null, null, dummy) == 0; // 0=="Yes" button
michael@0 164 }
michael@0 165
michael@0 166 function FinalizeSignonDeletions(syncNeeded) {
michael@0 167 for (var s=0; s<deletedSignons.length; s++) {
michael@0 168 passwordmanager.removeLogin(deletedSignons[s]);
michael@0 169 }
michael@0 170 // If the deletion has been performed in a filtered view, reflect the deletion in the unfiltered table.
michael@0 171 // See bug 405389.
michael@0 172 if (syncNeeded) {
michael@0 173 try {
michael@0 174 signons = passwordmanager.getAllLogins();
michael@0 175 } catch (e) {
michael@0 176 signons = [];
michael@0 177 }
michael@0 178 }
michael@0 179 deletedSignons.length = 0;
michael@0 180 }
michael@0 181
michael@0 182 function HandleSignonKeyPress(e) {
michael@0 183 if (e.keyCode == 46) {
michael@0 184 DeleteSignon();
michael@0 185 }
michael@0 186 }
michael@0 187
michael@0 188 function getColumnByName(column) {
michael@0 189 switch (column) {
michael@0 190 case "hostname":
michael@0 191 return document.getElementById("siteCol");
michael@0 192 case "username":
michael@0 193 return document.getElementById("userCol");
michael@0 194 case "password":
michael@0 195 return document.getElementById("passwordCol");
michael@0 196 }
michael@0 197 }
michael@0 198
michael@0 199 var lastSignonSortColumn = "hostname";
michael@0 200 var lastSignonSortAscending = true;
michael@0 201
michael@0 202 function SignonColumnSort(column) {
michael@0 203 // clear out the sortDirection attribute on the old column
michael@0 204 var lastSortedCol = getColumnByName(lastSignonSortColumn);
michael@0 205 lastSortedCol.removeAttribute("sortDirection");
michael@0 206
michael@0 207 // sort
michael@0 208 lastSignonSortAscending =
michael@0 209 SortTree(signonsTree, signonsTreeView,
michael@0 210 signonsTreeView._filterSet.length ? signonsTreeView._filterSet : signons,
michael@0 211 column, lastSignonSortColumn, lastSignonSortAscending);
michael@0 212 lastSignonSortColumn = column;
michael@0 213
michael@0 214 // set the sortDirection attribute to get the styling going
michael@0 215 // first we need to get the right element
michael@0 216 var sortedCol = getColumnByName(column);
michael@0 217 sortedCol.setAttribute("sortDirection", lastSignonSortAscending ?
michael@0 218 "ascending" : "descending");
michael@0 219 }
michael@0 220
michael@0 221 function SignonClearFilter() {
michael@0 222 var singleSelection = (signonsTreeView.selection.count == 1);
michael@0 223
michael@0 224 // Clear the Tree Display
michael@0 225 signonsTreeView.rowCount = 0;
michael@0 226 signonsTree.treeBoxObject.rowCountChanged(0, -signonsTreeView._filterSet.length);
michael@0 227 signonsTreeView._filterSet = [];
michael@0 228
michael@0 229 // Just reload the list to make sure deletions are respected
michael@0 230 LoadSignons();
michael@0 231
michael@0 232 // Restore selection
michael@0 233 if (singleSelection) {
michael@0 234 signonsTreeView.selection.clearSelection();
michael@0 235 for (let i = 0; i < signonsTreeView._lastSelectedRanges.length; ++i) {
michael@0 236 var range = signonsTreeView._lastSelectedRanges[i];
michael@0 237 signonsTreeView.selection.rangedSelect(range.min, range.max, true);
michael@0 238 }
michael@0 239 } else {
michael@0 240 signonsTreeView.selection.select(0);
michael@0 241 }
michael@0 242 signonsTreeView._lastSelectedRanges = [];
michael@0 243
michael@0 244 document.getElementById("signonsIntro").textContent = kSignonBundle.getString("loginsSpielAll");
michael@0 245 }
michael@0 246
michael@0 247 function FocusFilterBox() {
michael@0 248 var filterBox = document.getElementById("filter");
michael@0 249 if (filterBox.getAttribute("focused") != "true")
michael@0 250 filterBox.focus();
michael@0 251 }
michael@0 252
michael@0 253 function SignonMatchesFilter(aSignon, aFilterValue) {
michael@0 254 if (aSignon.hostname.toLowerCase().indexOf(aFilterValue) != -1)
michael@0 255 return true;
michael@0 256 if (aSignon.username &&
michael@0 257 aSignon.username.toLowerCase().indexOf(aFilterValue) != -1)
michael@0 258 return true;
michael@0 259 if (aSignon.httpRealm &&
michael@0 260 aSignon.httpRealm.toLowerCase().indexOf(aFilterValue) != -1)
michael@0 261 return true;
michael@0 262 if (showingPasswords && aSignon.password &&
michael@0 263 aSignon.password.toLowerCase().indexOf(aFilterValue) != -1)
michael@0 264 return true;
michael@0 265
michael@0 266 return false;
michael@0 267 }
michael@0 268
michael@0 269 function FilterPasswords(aFilterValue, view) {
michael@0 270 aFilterValue = aFilterValue.toLowerCase();
michael@0 271 return signons.filter(function (s) SignonMatchesFilter(s, aFilterValue));
michael@0 272 }
michael@0 273
michael@0 274 function SignonSaveState() {
michael@0 275 // Save selection
michael@0 276 var seln = signonsTreeView.selection;
michael@0 277 signonsTreeView._lastSelectedRanges = [];
michael@0 278 var rangeCount = seln.getRangeCount();
michael@0 279 for (var i = 0; i < rangeCount; ++i) {
michael@0 280 var min = {}; var max = {};
michael@0 281 seln.getRangeAt(i, min, max);
michael@0 282 signonsTreeView._lastSelectedRanges.push({ min: min.value, max: max.value });
michael@0 283 }
michael@0 284 }
michael@0 285
michael@0 286 function _filterPasswords()
michael@0 287 {
michael@0 288 var filter = document.getElementById("filter").value;
michael@0 289 if (filter == "") {
michael@0 290 SignonClearFilter();
michael@0 291 return;
michael@0 292 }
michael@0 293
michael@0 294 var newFilterSet = FilterPasswords(filter, signonsTreeView);
michael@0 295 if (!signonsTreeView._filterSet.length) {
michael@0 296 // Save Display Info for the Non-Filtered mode when we first
michael@0 297 // enter Filtered mode.
michael@0 298 SignonSaveState();
michael@0 299 }
michael@0 300 signonsTreeView._filterSet = newFilterSet;
michael@0 301
michael@0 302 // Clear the display
michael@0 303 let oldRowCount = signonsTreeView.rowCount;
michael@0 304 signonsTreeView.rowCount = 0;
michael@0 305 signonsTree.treeBoxObject.rowCountChanged(0, -oldRowCount);
michael@0 306 // Set up the filtered display
michael@0 307 signonsTreeView.rowCount = signonsTreeView._filterSet.length;
michael@0 308 signonsTree.treeBoxObject.rowCountChanged(0, signonsTreeView.rowCount);
michael@0 309
michael@0 310 // if the view is not empty then select the first item
michael@0 311 if (signonsTreeView.rowCount > 0)
michael@0 312 signonsTreeView.selection.select(0);
michael@0 313
michael@0 314 document.getElementById("signonsIntro").textContent = kSignonBundle.getString("loginsSpielFiltered");
michael@0 315 }
michael@0 316
michael@0 317 function CopyPassword() {
michael@0 318 // Don't copy passwords if we aren't already showing the passwords & a master
michael@0 319 // password hasn't been entered.
michael@0 320 if (!showingPasswords && !masterPasswordLogin())
michael@0 321 return;
michael@0 322 // Copy selected signon's password to clipboard
michael@0 323 var clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"].
michael@0 324 getService(Components.interfaces.nsIClipboardHelper);
michael@0 325 var row = document.getElementById("signonsTree").currentIndex;
michael@0 326 var password = signonsTreeView.getCellText(row, {id : "passwordCol" });
michael@0 327 clipboard.copyString(password, document);
michael@0 328 }
michael@0 329
michael@0 330 function CopyUsername() {
michael@0 331 // Copy selected signon's username to clipboard
michael@0 332 var clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"].
michael@0 333 getService(Components.interfaces.nsIClipboardHelper);
michael@0 334 var row = document.getElementById("signonsTree").currentIndex;
michael@0 335 var username = signonsTreeView.getCellText(row, {id : "userCol" });
michael@0 336 clipboard.copyString(username);
michael@0 337 }
michael@0 338
michael@0 339 function UpdateCopyPassword() {
michael@0 340 var singleSelection = (signonsTreeView.selection.count == 1);
michael@0 341 var passwordMenuitem = document.getElementById("context-copypassword");
michael@0 342 var usernameMenuitem = document.getElementById("context-copyusername");
michael@0 343 if (singleSelection) {
michael@0 344 usernameMenuitem.removeAttribute("disabled");
michael@0 345 passwordMenuitem.removeAttribute("disabled");
michael@0 346 } else {
michael@0 347 usernameMenuitem.setAttribute("disabled", "true");
michael@0 348 passwordMenuitem.setAttribute("disabled", "true");
michael@0 349 }
michael@0 350 }
michael@0 351
michael@0 352 function masterPasswordLogin(noPasswordCallback) {
michael@0 353 // This doesn't harm if passwords are not encrypted
michael@0 354 var tokendb = Components.classes["@mozilla.org/security/pk11tokendb;1"]
michael@0 355 .createInstance(Components.interfaces.nsIPK11TokenDB);
michael@0 356 var token = tokendb.getInternalKeyToken();
michael@0 357
michael@0 358 // If there is no master password, still give the user a chance to opt-out of displaying passwords
michael@0 359 if (token.checkPassword(""))
michael@0 360 return noPasswordCallback ? noPasswordCallback() : true;
michael@0 361
michael@0 362 // So there's a master password. But since checkPassword didn't succeed, we're logged out (per nsIPK11Token.idl).
michael@0 363 try {
michael@0 364 // Relogin and ask for the master password.
michael@0 365 token.login(true); // 'true' means always prompt for token password. User will be prompted until
michael@0 366 // clicking 'Cancel' or entering the correct password.
michael@0 367 } catch (e) {
michael@0 368 // An exception will be thrown if the user cancels the login prompt dialog.
michael@0 369 // User is also logged out of Software Security Device.
michael@0 370 }
michael@0 371
michael@0 372 return token.isLoggedIn();
michael@0 373 }

mercurial