From 33a1012482a421050aaae82d491b24d4aaf3b70c Mon Sep 17 00:00:00 2001 From: Anant Narayanan Date: Tue, 3 Mar 2009 00:42:57 +0100 Subject: [PATCH 1/4] Password sync for 0.3 (bug #468697) --- services/sync/modules/engines/passwords.js | 341 +++++++++--------- .../sync/modules/type_records/passwords.js | 100 +++++ services/sync/modules/util.js | 10 +- services/sync/services-sync.js | 2 +- 4 files changed, 275 insertions(+), 178 deletions(-) create mode 100644 services/sync/modules/type_records/passwords.js diff --git a/services/sync/modules/engines/passwords.js b/services/sync/modules/engines/passwords.js index 5e0245e3acc..6cd9e474e20 100644 --- a/services/sync/modules/engines/passwords.js +++ b/services/sync/modules/engines/passwords.js @@ -19,6 +19,7 @@ * * Contributor(s): * Justin Dolske + * Anant Narayanan * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -37,13 +38,17 @@ const EXPORTED_SYMBOLS = ['PasswordEngine']; const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +Cu.import("resource://weave/log4moz.js"); Cu.import("resource://weave/util.js"); -Cu.import("resource://weave/async.js"); Cu.import("resource://weave/engines.js"); -Cu.import("resource://weave/syncCores.js"); Cu.import("resource://weave/stores.js"); Cu.import("resource://weave/trackers.js"); +Cu.import("resource://weave/async.js"); +Cu.import("resource://weave/ext/Observers.js"); +Cu.import("resource://weave/type_records/passwords.js"); Function.prototype.async = Async.sugar; @@ -51,206 +56,206 @@ function PasswordEngine() { this._init(); } PasswordEngine.prototype = { - __proto__: new SyncEngine(), - - get name() { return "passwords"; }, - get displayName() { return "Saved Passwords"; }, - get logName() { return "PasswordEngine"; }, - get serverPrefix() { return "user-data/passwords/"; }, - - __store: null, - get _store() { - if (!this.__store) - this.__store = new PasswordStore(); - return this.__store; + __proto__: SyncEngine.prototype, + name: "passwords", + displayName: "Passwords", + logName: "Passwords", + _storeObj: PasswordStore, + _trackerObj: PasswordTracker, + _recordObj: LoginRec, + + /* We override syncStartup & syncFinish to populate/reset our local cache + of loginInfo items. We can remove this when the interface to query + LoginInfo items by GUID is ready + */ + _syncStartup: function PasswordStore__syncStartup() { + let self = yield; + this._store._cacheLogins(); + yield SyncEngine.prototype._syncStartup.async(this, self.cb); }, - - __core: null, - get _core() { - if (!this.__core) - this.__core = new PasswordSyncCore(this._store); - return this.__core; - }, - - __tracker: null, - get _tracker() { - if (!this.__tracker) - this.__tracker = new PasswordTracker(); - return this.__tracker; + + _syncFinish: function PasswordStore__syncFinish() { + let self = yield; + this._store._clearLoginCache(); + yield SyncEngine.prototype._syncFinish.async(this, self.cb); } }; -function PasswordSyncCore(store) { - this._store = store; - this._init(); -} -PasswordSyncCore.prototype = { - _logName: "PasswordSync", - _store: null, - - _commandLike: function PSC_commandLike(a, b) { - // Not used. - return false; - } -}; -PasswordSyncCore.prototype.__proto__ = new SyncCore(); - function PasswordStore() { this._init(); } PasswordStore.prototype = { + __proto__: Store.prototype, _logName: "PasswordStore", - _lookup: null, - __loginManager: null, get _loginManager() { - if (!this.__loginManager) - this.__loginManager = Utils.getLoginManager(); - return this.__loginManager; + let loginManager = Utils.getLoginManager(); + this.__defineGetter__("_loginManager", function() loginManager); + return loginManager; }, - __nsLoginInfo: null, - get _nsLoginInfo() { - if (!this.__nsLoginInfo) - this.__nsLoginInfo = Utils.makeNewLoginInfo(); - return this.__nsLoginInfo; - }, - - /* - * _hashLoginInfo - * - * nsILoginInfo objects don't have a unique GUID, so we need to generate one - * on the fly. This is done by taking a hash of every field in the object. - * Note that the resulting GUID could potentiually reveal passwords via - * dictionary attacks or brute force. But GUIDs shouldn't be obtainable by - * anyone, so this should generally be safe. - */ - _hashLoginInfo: function PasswordStore__hashLoginInfo(aLogin) { - var loginKey = aLogin.hostname + ":" + - aLogin.formSubmitURL + ":" + - aLogin.httpRealm + ":" + - aLogin.username + ":" + - aLogin.password + ":" + - aLogin.usernameField + ":" + - aLogin.passwordField; - - return Utils.sha1(loginKey); - }, - - _createCommand: function PasswordStore__createCommand(command) { - this._log.info("PasswordStore got createCommand: " + command ); - - var login = new this._nsLoginInfo(command.data.hostname, - command.data.formSubmitURL, - command.data.httpRealm, - command.data.username, - command.data.password, - command.data.usernameField, - command.data.passwordField); - - this._loginManager.addLogin(login); - }, - - _removeCommand: function PasswordStore__removeCommand(command) { - this._log.info("PasswordStore got removeCommand: " + command ); - - if (command.GUID in this._lookup) { - var data = this._lookup[command.GUID]; - var login = new this._nsLoginInfo(data.hostname, - data.formSubmitURL, - data.httpRealm, - data.username, - data.password, - data.usernameField, - data.passwordField); - this._loginManager.removeLogin(login); - } else { - this._log.warn("Invalid GUID for remove, ignoring request!"); + get _loginItems() { + let loginItems = {}; + let logins = this._loginManager.getAllLogins({}); + for (let i = 0; i < logins.length; i++) { + let metaInfo = logins[i].QueryInterface(Ci.nsILoginMetaInfo); + loginItems[metaInfo.guid] = logins[i]; } + + this.__defineGetter__("_loginItems", function() loginItems); + return loginItems; + }, + + _nsLoginInfo: null, + _init: function PasswordStore_init() { + Store.prototype._init.call(this); + this._nsLoginInfo = new Components.Constructor( + "@mozilla.org/login-manager/loginInfo;1", + Ci.nsILoginInfo, + "init" + ); + }, + + _cacheLogins: function PasswordStore__cacheLogins() { + /* Force the getter to populate the property + Also, this way, we don't fail if the store is created twice? + */ + return this._loginItems; + }, + + _clearLoginCache: function PasswordStore__clearLoginCache() { + this.__loginItems = null; + }, + + _nsLoginInfoFromRecord: function PasswordStore__nsLoginInfoRec(record) { + return new this._nsLoginInfo(record.hostname, + record.formSubmitURL, + record.httpRealm, + record.username, + record.password, + record.usernameField, + record.passwordField); }, - _editCommand: function PasswordStore__editCommand(command) { - this._log.info("PasswordStore got editCommand: " + command ); - throw "Password syncs are expected to only be create/remove!"; - }, - - wrap: function PasswordStore_wrap() { - /* Return contents of this store, as JSON. */ - var items = {}; - var logins = this._loginManager.getAllLogins({}); - - for (var i = 0; i < logins.length; i++) { - var login = logins[i]; - - var key = this._hashLoginInfo(login); - - items[key] = { hostname : login.hostname, - formSubmitURL : login.formSubmitURL, - httpRealm : login.httpRealm, - username : login.username, - password : login.password, - usernameField : login.usernameField, - passwordField : login.passwordField }; + getAllIDs: function PasswordStore__getAllIDs() { + let items = {}; + let logins = this._loginManager.getAllLogins({}); + + for (let i = 0; i < logins.length; i++) { + let metaInfo = logins[i].QueryInterface(Ci.nsILoginMetaInfo); + items[metaInfo.guid] = logins[i].hostname; } - - this._lookup = items; + return items; }, + changeItemID: function PasswordStore__changeItemID(oldID, newID) { + if (!(oldID in this._loginItems)) { + this._log.warn("Can't change GUID " + oldID + " to " + + newID + ": Item does not exist"); + return; + } + let info = this._loginItems[oldID]; + + if (newID in this._loginItems) { + this._log.warn("Can't change GUID " + oldID + " to " + + newID + ": new ID already in use"); + return; + } + + this._log.debug("Changing GUID " + oldID + " to " + newID); + + let prop = Cc["@mozilla.org/hash-property-bag;1"]. + createInstance(Ci.nsIWritablePropertyBag2); + prop.setPropertyAsAUTF8String("guid", newID); + + this._loginManager.modifyLogin(info, prop); + }, + + itemExists: function PasswordStore__itemExists(id) { + return ((id in this._loginItems) == true); + }, + + createRecord: function PasswordStore__createRecord(guid, cryptoMetaURL) { + let record = new LoginRec(); + record.id = guid; + if (guid in this._loginItems) { + let login = this._loginItems[guid]; + record.encryption = cryptoMetaURL; + record.hostname = login.hostname; + record.formSubmitURL = login.formSubmitURL; + record.httpRealm = login.httpRealm; + record.username = login.username; + record.password = login.password; + record.usernameField = login.usernameField; + record.passwordField = login.passwordField; + } else { + /* Deleted item */ + record.cleartext = null; + } + return record; + }, + + create: function PasswordStore__create(record) { + this._loginManager.addLogin(this._nsLoginInfoFromRecord(record)); + }, + + remove: function PasswordStore__remove(record) { + if (record.id in this._loginItems) { + this._loginManager.removeLogin(this._loginItems[record.id]); + return; + } + + this._log.debug("Asked to remove record that doesn't exist, ignoring!"); + }, + + update: function PasswordStore__update(record) { + if (!(record.id in this._loginItems)) { + this._log.debug("Skipping update for unknown item: " + record.id); + return; + } + let login = this._loginItems[record.id]; + this._log.trace("Updating " + record.id + " (" + itemId + ")"); + + let newinfo = this._nsLoginInfoFromRecord(record); + this._loginManager.modifyLogin(login, newinfo); + }, + wipe: function PasswordStore_wipe() { this._loginManager.removeAllLogins(); - }, - - _resetGUIDs: function PasswordStore__resetGUIDs() { - let self = yield; - // Not needed. } }; -PasswordStore.prototype.__proto__ = new Store(); function PasswordTracker() { this._init(); } PasswordTracker.prototype = { + __proto__: Tracker.prototype, _logName: "PasswordTracker", - __loginManager : null, - get _loginManager() { - if (!this.__loginManager) - this.__loginManager = Cc["@mozilla.org/login-manager;1"]. - getService(Ci.nsILoginManager); - return this.__loginManager; + _init: function PasswordTracker_init() { + Tracker.prototype._init.call(this); + Observers.add("passwordmgr-storage-changed", this); }, - /* We use nsILoginManager's countLogins() method, as it is - * the only method that doesn't require the user to enter - * a master password, but still gives us an idea of how much - * info has changed. - * - * FIXME: This does not track edits of passwords, so we - * artificially add 30 to every score. We should move to - * using the LoginManager shim at some point. - * - * Each addition/removal is worth 15 points. - */ - _loginCount: 0, - get score() { - var count = this._loginManager.countLogins("", "", ""); - var score = (Math.abs(this._loginCount - count) * 15) + 30; + /* A single add, remove or change is 15 points, all items removed is 50 */ + observe: function PasswordTracker_observe(aSubject, aTopic, aData) { + if (this.ignoreAll) + return; - if (score >= 100) - return 100; - else - return score; - }, + this._log.debug("Received notification " + aData); - resetScore: function PasswordTracker_resetScore() { - this._loginCount = this._loginManager.countLogins("", "", ""); - }, - - _init: function PasswordTracker__init() { - this._log = Log4Moz.Service.getLogger("Service." + this._logName); - this._loginCount = this._loginManager.countLogins("", "", ""); + switch (aData) { + case 'addLogin': + case 'modifyLogin': + case 'removeLogin': + let metaInfo = aSubject.QueryInterface(Ci.nsILoginMetaInfo); + this._score += 15; + this.addChangedID(metaInfo.guid); + break; + case 'removeAllLogins': + this._score += 50; + break; + } } }; -PasswordTracker.prototype.__proto__ = new Tracker(); diff --git a/services/sync/modules/type_records/passwords.js b/services/sync/modules/type_records/passwords.js new file mode 100644 index 00000000000..fe81b4ba01f --- /dev/null +++ b/services/sync/modules/type_records/passwords.js @@ -0,0 +1,100 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Weave. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Anant Narayanan + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const EXPORTED_SYMBOLS = ['LoginRec']; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; + +Cu.import("resource://weave/log4moz.js"); +Cu.import("resource://weave/util.js"); +Cu.import("resource://weave/async.js"); +Cu.import("resource://weave/base_records/wbo.js"); +Cu.import("resource://weave/base_records/crypto.js"); +Cu.import("resource://weave/base_records/keys.js"); + +Function.prototype.async = Async.sugar; + +function LoginRec(uri) { + this._LoginRec_init(uri); +} +LoginRec.prototype = { + __proto__: CryptoWrapper.prototype, + _logName: "Record.Login", + + _LoginRec_init: function LoginItem_init(uri) { + this._CryptoWrap_init(uri); + this.cleartext = { + }; + }, + + get hostname() this.cleartext.hostname, + set hostname(value) { + this.cleartext.hostname = value; + }, + + get formSubmitURL() this.cleartext.formSubmitURL, + set formSubmitURL(value) { + this.cleartext.formSubmitURL = value; + }, + + get httpRealm() this.cleartext.httpRealm, + set httpRealm(value) { + this.cleartext.httpRealm = value; + }, + + get username() this.cleartext.username, + set username(value) { + this.cleartext.username = value; + }, + + get password() this.cleartext.password, + set password(value) { + this.cleartext.password = value; + }, + + get usernameField() this.cleartext.usernameField, + set usernameField(value) { + this.cleartext.usernameField = value; + }, + + get passwordField() this.cleartext.passwordField, + set passwordField(value) { + this.cleartext.passwordField = value; + } +}; diff --git a/services/sync/modules/util.js b/services/sync/modules/util.js index 03ad0e07561..d71a2155dc1 100644 --- a/services/sync/modules/util.js +++ b/services/sync/modules/util.js @@ -93,15 +93,7 @@ let Utils = { return Cc["@mozilla.org/login-manager;1"]. getService(Ci.nsILoginManager); }, - - makeNewLoginInfo: function getNewLoginInfo() { - return new Components.Constructor( - "@mozilla.org/login-manager/loginInfo;1", - Ci.nsILoginInfo, - "init" - ); - }, - + findPassword: function findPassword(realm, username) { // fixme: make a request and get the realm ? let password; diff --git a/services/sync/services-sync.js b/services/sync/services-sync.js index 03eff5790cb..53b22293fdc 100644 --- a/services/sync/services-sync.js +++ b/services/sync/services-sync.js @@ -16,7 +16,7 @@ pref("extensions.weave.syncOnQuit.enabled", true); pref("extensions.weave.engine.bookmarks", true); pref("extensions.weave.engine.history", true); pref("extensions.weave.engine.cookies", false); -pref("extensions.weave.engine.passwords", false); +pref("extensions.weave.engine.passwords", true); pref("extensions.weave.engine.forms", false); pref("extensions.weave.engine.tabs", true); pref("extensions.weave.engine.input", false); From 0932057beb8160205e678102fdfe8fce27760b23 Mon Sep 17 00:00:00 2001 From: Anant Narayanan Date: Tue, 3 Mar 2009 00:57:37 +0100 Subject: [PATCH 2/4] Rename methods to be less confusing --- services/sync/modules/engines/passwords.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/sync/modules/engines/passwords.js b/services/sync/modules/engines/passwords.js index 6cd9e474e20..ee2e88bd4b9 100644 --- a/services/sync/modules/engines/passwords.js +++ b/services/sync/modules/engines/passwords.js @@ -68,13 +68,13 @@ PasswordEngine.prototype = { of loginInfo items. We can remove this when the interface to query LoginInfo items by GUID is ready */ - _syncStartup: function PasswordStore__syncStartup() { + _syncStartup: function PasswordEngine__syncStartup() { let self = yield; this._store._cacheLogins(); yield SyncEngine.prototype._syncStartup.async(this, self.cb); }, - _syncFinish: function PasswordStore__syncFinish() { + _syncFinish: function PasswordEngine__syncFinish() { let self = yield; this._store._clearLoginCache(); yield SyncEngine.prototype._syncFinish.async(this, self.cb); From fd1d0e8eefbc9a72799c719b64fb660dfad13df8 Mon Sep 17 00:00:00 2001 From: Anant Narayanan Date: Tue, 3 Mar 2009 01:15:48 +0100 Subject: [PATCH 3/4] Remove getter that fixes the 'two-store' problem --- services/sync/modules/engines.js | 7 ++-- services/sync/modules/engines/passwords.js | 40 +++++++--------------- 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/services/sync/modules/engines.js b/services/sync/modules/engines.js index 0e7d4a6f00f..d54e089deb8 100644 --- a/services/sync/modules/engines.js +++ b/services/sync/modules/engines.js @@ -112,10 +112,11 @@ Engine.prototype = { get enabled() Utils.prefs.getBoolPref("engine." + this.name), get score() this._tracker.score, + __store: null, get _store() { - let store = new this._storeObj(); - this.__defineGetter__("_store", function() store); - return store; + if (!this.__store) + this.__store = new this._storeObj(); + return this.__store; }, get _tracker() { diff --git a/services/sync/modules/engines/passwords.js b/services/sync/modules/engines/passwords.js index ee2e88bd4b9..449acaba5ca 100644 --- a/services/sync/modules/engines/passwords.js +++ b/services/sync/modules/engines/passwords.js @@ -64,16 +64,7 @@ PasswordEngine.prototype = { _trackerObj: PasswordTracker, _recordObj: LoginRec, - /* We override syncStartup & syncFinish to populate/reset our local cache - of loginInfo items. We can remove this when the interface to query - LoginInfo items by GUID is ready - */ - _syncStartup: function PasswordEngine__syncStartup() { - let self = yield; - this._store._cacheLogins(); - yield SyncEngine.prototype._syncStartup.async(this, self.cb); - }, - + /* Wipe cache when sync finishes */ _syncFinish: function PasswordEngine__syncFinish() { let self = yield; this._store._clearLoginCache(); @@ -93,17 +84,19 @@ PasswordStore.prototype = { this.__defineGetter__("_loginManager", function() loginManager); return loginManager; }, - + + __loginItems: null, get _loginItems() { - let loginItems = {}; - let logins = this._loginManager.getAllLogins({}); - for (let i = 0; i < logins.length; i++) { - let metaInfo = logins[i].QueryInterface(Ci.nsILoginMetaInfo); - loginItems[metaInfo.guid] = logins[i]; + if (!this.__loginItems) { + this.__loginItems = {}; + let logins = this._loginManager.getAllLogins({}); + for (let i = 0; i < logins.length; i++) { + let metaInfo = logins[i].QueryInterface(Ci.nsILoginMetaInfo); + this.__loginItems[metaInfo.guid] = logins[i]; + } } - - this.__defineGetter__("_loginItems", function() loginItems); - return loginItems; + + return this.__loginItems; }, _nsLoginInfo: null, @@ -113,14 +106,7 @@ PasswordStore.prototype = { "@mozilla.org/login-manager/loginInfo;1", Ci.nsILoginInfo, "init" - ); - }, - - _cacheLogins: function PasswordStore__cacheLogins() { - /* Force the getter to populate the property - Also, this way, we don't fail if the store is created twice? - */ - return this._loginItems; + ); }, _clearLoginCache: function PasswordStore__clearLoginCache() { From 85834524e081da39fbbde33ae8829093e486e43b Mon Sep 17 00:00:00 2001 From: Dan Mills Date: Mon, 2 Mar 2009 18:55:26 -0800 Subject: [PATCH 4/4] Switch away from __defineGetter__ due to bug 481104; explicitly cache logins in password engine; whitespace fixes --- services/sync/modules/engines.js | 17 +++----- services/sync/modules/engines/passwords.js | 50 ++++++++++------------ services/sync/modules/util.js | 2 +- 3 files changed, 29 insertions(+), 40 deletions(-) diff --git a/services/sync/modules/engines.js b/services/sync/modules/engines.js index d54e089deb8..422ff25f6fb 100644 --- a/services/sync/modules/engines.js +++ b/services/sync/modules/engines.js @@ -112,7 +112,6 @@ Engine.prototype = { get enabled() Utils.prefs.getBoolPref("engine." + this.name), get score() this._tracker.score, - __store: null, get _store() { if (!this.__store) this.__store = new this._storeObj(); @@ -120,9 +119,9 @@ Engine.prototype = { }, get _tracker() { - let tracker = new this._trackerObj(); - this.__defineGetter__("_tracker", function() tracker); - return tracker; + if (!this.__tracker) + this.__tracker = new this._trackerObj(); + return this.__tracker; }, _init: function Engine__init() { @@ -167,12 +166,6 @@ SyncEngine.prototype = { _recordObj: CryptoWrapper, - get _memory() { - let mem = Cc["@mozilla.org/xpcom/memory-service;1"].getService(Ci.nsIMemory); - this.__defineGetter__("_memory", function() mem); - return mem; - }, - get baseURL() { let url = Svc.Prefs.get("clusterURL"); if (!url) @@ -228,10 +221,10 @@ SyncEngine.prototype = { }, _lowMemCheck: function SyncEngine__lowMemCheck() { - if (this._memory.isLowMemory()) { + if (Svc.Memory.isLowMemory()) { this._log.warn("Low memory, forcing GC"); Cu.forceGC(); - if (this._memory.isLowMemory()) { + if (Svc.Memory.isLowMemory()) { this._log.warn("Low memory, aborting sync!"); throw "Low memory"; } diff --git a/services/sync/modules/engines/passwords.js b/services/sync/modules/engines/passwords.js index 449acaba5ca..f15e8d77256 100644 --- a/services/sync/modules/engines/passwords.js +++ b/services/sync/modules/engines/passwords.js @@ -63,11 +63,17 @@ PasswordEngine.prototype = { _storeObj: PasswordStore, _trackerObj: PasswordTracker, _recordObj: LoginRec, - + + _syncStartup: function PasswordEngine__syncStartup() { + let self = yield; + this._store.cacheLogins(); + yield SyncEngine.prototype._syncStartup.async(this, self.cb); + }, + /* Wipe cache when sync finishes */ _syncFinish: function PasswordEngine__syncFinish() { let self = yield; - this._store._clearLoginCache(); + this._store.clearLoginCache(); yield SyncEngine.prototype._syncFinish.async(this, self.cb); } }; @@ -84,21 +90,7 @@ PasswordStore.prototype = { this.__defineGetter__("_loginManager", function() loginManager); return loginManager; }, - - __loginItems: null, - get _loginItems() { - if (!this.__loginItems) { - this.__loginItems = {}; - let logins = this._loginManager.getAllLogins({}); - for (let i = 0; i < logins.length; i++) { - let metaInfo = logins[i].QueryInterface(Ci.nsILoginMetaInfo); - this.__loginItems[metaInfo.guid] = logins[i]; - } - } - return this.__loginItems; - }, - _nsLoginInfo: null, _init: function PasswordStore_init() { Store.prototype._init.call(this); @@ -106,13 +98,9 @@ PasswordStore.prototype = { "@mozilla.org/login-manager/loginInfo;1", Ci.nsILoginInfo, "init" - ); + ); }, - - _clearLoginCache: function PasswordStore__clearLoginCache() { - this.__loginItems = null; - }, - + _nsLoginInfoFromRecord: function PasswordStore__nsLoginInfoRec(record) { return new this._nsLoginInfo(record.hostname, record.formSubmitURL, @@ -123,15 +111,23 @@ PasswordStore.prototype = { record.passwordField); }, + cacheLogins: function PasswordStore_cacheLogins() { + this._loginItems = this.getAllIDs(); + }, + + clearLoginCache: function PasswordStore_clearLoginCache() { + this._loginItems = null; + }, + getAllIDs: function PasswordStore__getAllIDs() { let items = {}; let logins = this._loginManager.getAllLogins({}); - + for (let i = 0; i < logins.length; i++) { let metaInfo = logins[i].QueryInterface(Ci.nsILoginMetaInfo); items[metaInfo.guid] = logins[i].hostname; } - + return items; }, @@ -142,13 +138,13 @@ PasswordStore.prototype = { return; } let info = this._loginItems[oldID]; - + if (newID in this._loginItems) { this._log.warn("Can't change GUID " + oldID + " to " + newID + ": new ID already in use"); return; } - + this._log.debug("Changing GUID " + oldID + " to " + newID); let prop = Cc["@mozilla.org/hash-property-bag;1"]. @@ -191,7 +187,7 @@ PasswordStore.prototype = { this._loginManager.removeLogin(this._loginItems[record.id]); return; } - + this._log.debug("Asked to remove record that doesn't exist, ignoring!"); }, diff --git a/services/sync/modules/util.js b/services/sync/modules/util.js index d71a2155dc1..f73024816b5 100644 --- a/services/sync/modules/util.js +++ b/services/sync/modules/util.js @@ -93,7 +93,7 @@ let Utils = { return Cc["@mozilla.org/login-manager;1"]. getService(Ci.nsILoginManager); }, - + findPassword: function findPassword(realm, username) { // fixme: make a request and get the realm ? let password;