Bug 967047 - give FxA credentials the same special treatment the legacy sync host credentials get. r=rnewman
authorMark Hammond <mhammond@skippinet.com.au>
Wed, 12 Feb 2014 18:57:16 +1100
changeset 168236 05d01f97ed0c3b83f7ae223a89e04ee7628c163d
parent 168235 3e8524fcafcd90e4100a8b4251fd97b57b00e09f
child 168237 445dca4f26f044063a48b3d0ad8b5518786091a4
push id26199
push userryanvm@gmail.com
push dateWed, 12 Feb 2014 13:33:20 +0000
treeherdermozilla-central@c11bd46b6a2a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrnewman
bugs967047
milestone30.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 967047 - give FxA credentials the same special treatment the legacy sync host credentials get. r=rnewman
services/sync/modules/browserid_identity.js
services/sync/modules/engines/passwords.js
services/sync/modules/identity.js
services/sync/modules/util.js
--- a/services/sync/modules/browserid_identity.js
+++ b/services/sync/modules/browserid_identity.js
@@ -232,18 +232,17 @@ this.BrowserIDManager.prototype = {
 
   /**
    * Sets the active account name.
    *
    * This should almost always be called in favor of setting username, as
    * username is derived from account.
    *
    * Changing the account name has the side-effect of wiping out stored
-   * credentials. Keep in mind that persistCredentials() will need to be called
-   * to flush the changes to disk.
+   * credentials.
    *
    * Set this value to null to clear out identity information.
    */
   set account(value) {
     throw "account setter should be not used in BrowserIDManager";
   },
 
   /**
--- a/services/sync/modules/engines/passwords.js
+++ b/services/sync/modules/engines/passwords.js
@@ -35,28 +35,40 @@ PasswordEngine.prototype = {
   _trackerObj: PasswordTracker,
   _recordObj: LoginRec,
   applyIncomingBatchSize: PASSWORDS_STORE_BATCH_SIZE,
 
   _syncFinish: function _syncFinish() {
     SyncEngine.prototype._syncFinish.call(this);
 
     // Delete the weave credentials from the server once
-    if (!Svc.Prefs.get("deletePwd", false)) {
+    if (!Svc.Prefs.get("deletePwdFxA", false)) {
       try {
-        let ids = Services.logins.findLogins({}, PWDMGR_HOST, "", "")
-                          .map(function(info) {
-          return info.QueryInterface(Components.interfaces.nsILoginMetaInfo).guid;
-        });
-        let coll = new Collection(this.engineURL, null, this.service);
-        coll.ids = ids;
-        let ret = coll.delete();
-        this._log.debug("Delete result: " + ret);
-
-        Svc.Prefs.set("deletePwd", true);
+        let ids = [];
+        for (let host of Utils.getSyncCredentialsHosts()) {
+          for (let info of Services.logins.findLogins({}, host, "", "")) {
+            ids.push(info.QueryInterface(Components.interfaces.nsILoginMetaInfo).guid);
+          }
+        }
+        if (ids.length) {
+          let coll = new Collection(this.engineURL, null, this.service);
+          coll.ids = ids;
+          let ret = coll.delete();
+          this._log.debug("Delete result: " + ret);
+          if (!ret.success && ret.status != 400) {
+            // A non-400 failure means try again next time.
+            return;
+          }
+        } else {
+          this._log.debug("Didn't find any passwords to delete");
+        }
+        // If there were no ids to delete, or we succeeded, or got a 400,
+        // record success.
+        Svc.Prefs.set("deletePwdFxA", true);
+        Svc.Prefs.reset("deletePwd"); // The old prefname we previously used.
       }
       catch(ex) {
         this._log.debug("Password deletes failed: " + Utils.exceptionStr(ex));
       }
     }
   },
 
   _findDupe: function _findDupe(item) {
@@ -145,18 +157,19 @@ PasswordStore.prototype = {
 
   getAllIDs: function PasswordStore__getAllIDs() {
     let items = {};
     let logins = Services.logins.getAllLogins({});
 
     for (let i = 0; i < logins.length; i++) {
       // Skip over Weave password/passphrase entries
       let metaInfo = logins[i].QueryInterface(Ci.nsILoginMetaInfo);
-      if (metaInfo.hostname == PWDMGR_HOST)
+      if (Utils.getSyncCredentialsHosts().has(metaInfo.hostname)) {
         continue;
+      }
 
       items[metaInfo.guid] = metaInfo;
     }
 
     return items;
   },
 
   changeItemID: function PasswordStore__changeItemID(oldID, newID) {
@@ -283,17 +296,17 @@ PasswordTracker.prototype = {
     switch (data) {
       case "modifyLogin":
         subject = subject.QueryInterface(Ci.nsIArray).queryElementAt(1, Ci.nsILoginMetaInfo);
         // fallthrough
       case "addLogin":
       case "removeLogin":
         // Skip over Weave password/passphrase changes.
         subject.QueryInterface(Ci.nsILoginMetaInfo).QueryInterface(Ci.nsILoginInfo);
-        if (subject.hostname == PWDMGR_HOST) {
+        if (Utils.getSyncCredentialsHosts().has(subject.hostname)) {
           break;
         }
 
         this.score += SCORE_INCREMENT_XLARGE;
         this._log.trace(data + ": " + subject.guid);
         this.addChangedID(subject.guid);
         break;
       case "removeAllLogins":
--- a/services/sync/modules/identity.js
+++ b/services/sync/modules/identity.js
@@ -443,19 +443,21 @@ IdentityManager.prototype = {
                                 password, "", "");
     Services.logins.addLogin(login);
   },
 
   /**
    * Deletes Sync credentials from the password manager.
    */
   deleteSyncCredentials: function deleteSyncCredentials() {
-    let logins = Services.logins.findLogins({}, PWDMGR_HOST, "", "");
-    for each (let login in logins) {
-      Services.logins.removeLogin(login);
+    for (let host of Utils.getSyncCredentialsHosts()) {
+      let logins = Services.logins.findLogins({}, host, "", "");
+      for each (let login in logins) {
+        Services.logins.removeLogin(login);
+      }
     }
 
     // Wait until after store is updated in case it fails.
     this._basicPassword = null;
     this._basicPasswordAllowLookup = true;
     this._basicPasswordUpdated = false;
 
     this._syncKey = null;
--- a/services/sync/modules/util.js
+++ b/services/sync/modules/util.js
@@ -596,16 +596,48 @@ this.Utils = {
   calculateBackoff: function calculateBackoff(attempts, baseInterval,
                                               statusInterval) {
     let backoffInterval = attempts *
                           (Math.floor(Math.random() * baseInterval) +
                            baseInterval);
     return Math.max(Math.min(backoffInterval, MAXIMUM_BACKOFF_INTERVAL),
                     statusInterval);
   },
+
+  /**
+   * Return a set of hostnames (including the protocol) which may have
+   * credentials for sync itself stored in the login manager.
+   *
+   * In general, these hosts will not have their passwords synced, will be
+   * reset when we drop sync credentials, etc.
+   */
+  getSyncCredentialsHosts: function() {
+    // This is somewhat expensive and the result static, so we cache the result.
+    if (this._syncCredentialsHosts) {
+      return this._syncCredentialsHosts;
+    }
+    let result = new Set();
+    // the legacy sync host.
+    result.add(PWDMGR_HOST);
+    // The FxA hosts - these almost certainly all have the same hostname, but
+    // better safe than sorry...
+    for (let prefName of ["identity.fxaccounts.remote.force_auth.uri",
+                          "identity.fxaccounts.remote.uri",
+                          "identity.fxaccounts.settings.uri"]) {
+      let prefVal;
+      try {
+        prefVal = Services.prefs.getCharPref(prefName);
+      } catch (_) {
+        continue;
+      }
+      let uri = Services.io.newURI(prefVal, null, null);
+      result.add(uri.prePath);
+    }
+    return this._syncCredentialsHosts = result;
+  },
 };
 
 XPCOMUtils.defineLazyGetter(Utils, "_utf8Converter", function() {
   let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
                     .createInstance(Ci.nsIScriptableUnicodeConverter);
   converter.charset = "UTF-8";
   return converter;
 });