Bug 1296767 part 3 - Make BrowserID the only Sync identity manager. r?markh draft
authorEdouard Oger <eoger@fastmail.com>
Fri, 13 Jan 2017 15:02:21 -0500
changeset 467363 16b22133316d18203f3e2155aeacaba9f9dae808
parent 467362 be5e97383698de0eb0d5fbba66510681e13a344e
child 467364 17c86b386a653407534234612daecc44de2df231
push id43155
push userbmo:eoger@fastmail.com
push dateFri, 27 Jan 2017 18:31:15 +0000
reviewersmarkh
bugs1296767
milestone54.0a1
Bug 1296767 part 3 - Make BrowserID the only Sync identity manager. r?markh MozReview-Commit-ID: IC7kRjgtPp8
browser/base/content/browser-syncui.js
browser/base/content/sync/setup.js
services/sync/Weave.js
services/sync/modules-testing/utils.js
services/sync/modules/browserid_identity.js
services/sync/modules/engines.js
services/sync/modules/identity.js
services/sync/modules/policies.js
services/sync/modules/service.js
services/sync/modules/stages/cluster.js
services/sync/modules/status.js
services/sync/moz.build
services/sync/services-sync.js
services/sync/tests/unit/test_identity_manager.js
services/sync/tests/unit/test_load_modules.js
services/sync/tests/unit/xpcshell.ini
tools/lint/eslint/modules.json
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -369,19 +369,20 @@ var gSyncUI = {
      otherwise the tooltip reflects the fact that Sync needs to be
      (re-)configured.
   */
   _updateSyncButtonsTooltip: Task.async(function* () {
     if (!gBrowser)
       return;
 
     let email;
-    try {
-      email = Services.prefs.getCharPref("services.sync.username");
-    } catch (ex) {}
+    let user = yield fxAccounts.getSignedInUser();
+    if (user) {
+      email = user.email;
+    }
 
     let needsSetup = yield this._needsSetup();
     let needsVerification = yield this._needsVerification();
     let loginFailed = this.loginFailed();
     // This is a little messy as the Sync buttons are 1/2 Sync related and
     // 1/2 FxA related - so for some strings we use Sync strings, but for
     // others we reach into gFxAccounts for strings.
     let tooltiptext;
--- a/browser/base/content/sync/setup.js
+++ b/browser/base/content/sync/setup.js
@@ -215,17 +215,16 @@ var gSyncSetup = {
 
     let feedback;
     switch (Weave.Status.login) {
       case Weave.LOGIN_FAILED_NETWORK_ERROR:
       case Weave.LOGIN_FAILED_SERVER_ERROR:
         feedback = server;
         break;
       case Weave.LOGIN_FAILED_LOGIN_REJECTED:
-      case Weave.LOGIN_FAILED_NO_USERNAME:
       case Weave.LOGIN_FAILED_NO_PASSWORD:
         feedback = password;
         break;
       case Weave.LOGIN_FAILED_INVALID_PASSPHRASE:
         feedback = passphrase;
         break;
     }
     this._setFeedbackMessage(feedback, false, Weave.Status.login);
--- a/services/sync/Weave.js
+++ b/services/sync/Weave.js
@@ -97,32 +97,26 @@ WeaveService.prototype = {
     return deferred.promise;
   },
 
   /**
    * Whether Firefox Accounts is enabled.
    *
    * @return bool
    */
+  // TODO - Remove this getter and all accessors
   get fxAccountsEnabled() {
-    try {
-      // Old sync guarantees '@' will never appear in the username while FxA
-      // uses the FxA email address - so '@' is the flag we use.
-      let username = Services.prefs.getCharPref(SYNC_PREFS_BRANCH + "username");
-      return !username || username.includes("@");
-    } catch (_) {
-      return true; // No username == only allow FxA to be configured.
-    }
+    // Always return true.
+    return true;
   },
 
   /**
    * Whether Sync appears to be enabled.
    *
-   * This returns true if all the Sync preferences for storing account
-   * and server configuration are populated.
+   * This returns true if we have an associated FxA account
    *
    * It does *not* perform a robust check to see if the client is working.
    * For that, you'll want to check Weave.Status.checkSetup().
    */
   get enabled() {
     let prefs = Services.prefs.getBranch(SYNC_PREFS_BRANCH);
     return prefs.prefHasUserValue("username");
   },
@@ -137,20 +131,19 @@ WeaveService.prototype = {
 
     case "final-ui-startup":
       // Force Weave service to load if it hasn't triggered from overlays
       this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
       this.timer.initWithCallback({
         notify: function() {
           let isConfigured = false;
           // We only load more if it looks like Sync is configured.
-          let prefs = Services.prefs.getBranch(SYNC_PREFS_BRANCH);
-          if (prefs.prefHasUserValue("username")) {
-            // We have a username. So, do a more thorough check. This will
-            // import a number of modules and thus increase memory
+          if (this.enabled) {
+            // We have an associated FxAccount. So, do a more thorough check.
+            // This will import a number of modules and thus increase memory
             // accordingly. We could potentially copy code performed by
             // this check into this file if our above code is yielding too
             // many false positives.
             Components.utils.import("resource://services-sync/main.js");
             isConfigured = Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED;
           }
           let getHistogramById = Services.telemetry.getHistogramById;
           getHistogramById("WEAVE_CONFIGURED").add(isConfigured);
--- a/services/sync/modules-testing/utils.js
+++ b/services/sync/modules-testing/utils.js
@@ -22,17 +22,16 @@ this.EXPORTED_SYMBOLS = [
   "MockFxaStorageManager",
   "AccountState", // from a module import
   "sumHistogram",
 ];
 
 var {utils: Cu} = Components;
 
 Cu.import("resource://services-sync/status.js");
-Cu.import("resource://services-sync/identity.js");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-crypto/utils.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-sync/browserid_identity.js");
 Cu.import("resource://testing-common/services/common/logging.js");
 Cu.import("resource://testing-common/services/sync/fakeservices.js");
 Cu.import("resource://gre/modules/FxAccounts.jsm");
 Cu.import("resource://gre/modules/FxAccountsClient.jsm");
@@ -165,33 +164,24 @@ this.makeIdentityConfig = function(overr
       token: {
         endpoint: null,
         duration: 300,
         id: "id",
         key: "key",
         hashed_fxa_uid: "f".repeat(32), // used during telemetry validation
         // uid will be set to the username.
       }
-    },
-    sync: {
-      // username will come from the top-level username
-      password: "whatever",
-      syncKey: "abcdeabcdeabcdeabcdeabcdea",
     }
   };
 
   // Now handle any specified overrides.
   if (overrides) {
     if (overrides.username) {
       result.username = overrides.username;
     }
-    if (overrides.sync) {
-      // TODO: allow just some attributes to be specified
-      result.sync = overrides.sync;
-    }
     if (overrides.fxaccount) {
       // TODO: allow just some attributes to be specified
       result.fxaccount = overrides.fxaccount;
     }
   }
   return result;
 }
 
@@ -255,54 +245,40 @@ this.configureIdentity = async function(
   let config = makeIdentityConfig(identityOverrides, server);
   let ns = {};
   Cu.import("resource://services-sync/service.js", ns);
 
   if (server) {
     ns.Service.serverURL = server.baseURI;
   }
 
-  ns.Service._clusterManager = ns.Service.identity.createClusterManager(ns.Service);
-
-  if (ns.Service.identity instanceof BrowserIDManager) {
-    // do the FxAccounts thang...
-
-    // If a server was specified, ensure FxA has a correct cluster URL available.
-    if (server && !config.fxaccount.token.endpoint) {
-      let ep = server.baseURI;
-      if (!ep.endsWith("/")) {
-        ep += "/";
-      }
-      ep += "1.1/" + config.username + "/";
-      config.fxaccount.token.endpoint = ep;
+  // If a server was specified, ensure FxA has a correct cluster URL available.
+  if (server && !config.fxaccount.token.endpoint) {
+    let ep = server.baseURI;
+    if (!ep.endsWith("/")) {
+      ep += "/";
     }
+    ep += "1.1/" + config.username + "/";
+    config.fxaccount.token.endpoint = ep;
+  }
 
-    configureFxAccountIdentity(ns.Service.identity, config);
-    await ns.Service.identity.initializeWithCurrentIdentity();
-    // and cheat to avoid requiring each test do an explicit login - give it
-    // a cluster URL.
-    if (config.fxaccount.token.endpoint) {
-      ns.Service.clusterURL = config.fxaccount.token.endpoint;
-    }
-    return;
+  configureFxAccountIdentity(ns.Service.identity, config);
+  await ns.Service.identity.initializeWithCurrentIdentity();
+  // and cheat to avoid requiring each test do an explicit login - give it
+  // a cluster URL.
+  if (config.fxaccount.token.endpoint) {
+    ns.Service.clusterURL = config.fxaccount.token.endpoint;
   }
-  // old style identity provider.
-  if (server) {
-    ns.Service.clusterURL = server.baseURI + "/";
-  }
-  ns.Service.identity.username = config.username;
-  ns.Service._updateCachedURLs();
-  setBasicCredentials(config.username, config.sync.password, config.sync.syncKey);
 }
 
-this.SyncTestingInfrastructure = async function(server, username, password) {
+this.SyncTestingInfrastructure = async function(server, username) {
   let ns = {};
   Cu.import("resource://services-sync/service.js", ns);
 
-  let config = makeIdentityConfig({ username, password });
+  let config = makeIdentityConfig({ username });
   await configureIdentity(config, server);
   return {
     logStats: initTestLogging(),
     fakeFilesystem: new FakeFilesystemService({}),
     fakeGUIDService: new FakeGUIDService(),
     fakeCryptoService: new FakeCryptoService(),
   }
 }
@@ -318,41 +294,32 @@ this.encryptPayload = function encryptPa
   return {
     ciphertext: cleartext, // ciphertext == cleartext with fake crypto
     IV: "irrelevant",
     hmac: fakeSHA256HMAC(cleartext, CryptoUtils.makeHMACKey("")),
   };
 }
 
 // This helper can be used instead of 'add_test' or 'add_task' to run the
-// specified test function twice - once with the old-style sync identity
-// manager and once with the new-style BrowserID identity manager, to ensure
-// it works in both cases.
+// specified test function with different identity managers.
+// So far we use this with one, the FxA one, but we keep it in case we change
+// idmanagers again.
 //
 // * The test itself should be passed as 'test' - ie, test code will generally
 //   pass |this|.
 // * The test function is a regular test function - although note that it must
 //   be a generator - async operations should yield them, and run_next_test
 //   mustn't be called.
 this.add_identity_test = function(test, testFunction) {
   function note(what) {
     let msg = "running test " + testFunction.name + " with " + what + " identity manager";
     test.do_print(msg);
   }
   let ns = {};
   Cu.import("resource://services-sync/service.js", ns);
-  // one task for the "old" identity manager.
-  test.add_task(async function() {
-    note("sync");
-    let oldIdentity = Status._authManager;
-    ensureLegacyIdentityManager();
-    await testFunction();
-    Status.__authManager = ns.Service.identity = oldIdentity;
-  });
-  // another task for the FxAccounts identity manager.
   test.add_task(async function() {
     note("FxAccounts");
     let oldIdentity = Status._authManager;
     Status.__authManager = ns.Service.identity = new BrowserIDManager();
     await testFunction();
     Status.__authManager = ns.Service.identity = oldIdentity;
   });
 }
--- a/services/sync/modules/browserid_identity.js
+++ b/services/sync/modules/browserid_identity.js
@@ -8,23 +8,21 @@ this.EXPORTED_SYMBOLS = ["BrowserIDManag
 
 var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://services-common/async.js");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-common/tokenserverclient.js");
 Cu.import("resource://services-crypto/utils.js");
-Cu.import("resource://services-sync/identity.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-common/tokenserverclient.js");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://gre/modules/Promise.jsm");
-Cu.import("resource://services-sync/stages/cluster.js");
 Cu.import("resource://gre/modules/FxAccounts.jsm");
 
 // Lazy imports to prevent unnecessary load on startup.
 XPCOMUtils.defineLazyModuleGetter(this, "Weave",
                                   "resource://services-sync/main.js");
 
 XPCOMUtils.defineLazyModuleGetter(this, "BulkKeyBundle",
                                   "resource://services-sync/keys.js");
@@ -84,18 +82,16 @@ this.BrowserIDManager = function Browser
   this._tokenServerClient = new TokenServerClient();
   this._tokenServerClient.observerPrefix = "weave:service";
   // will be a promise that resolves when we are ready to authenticate
   this.whenReadyToAuthenticate = null;
   this._log = log;
 };
 
 this.BrowserIDManager.prototype = {
-  __proto__: IdentityManager.prototype,
-
   _fxaService: null,
   _tokenServerClient: null,
   // https://docs.services.mozilla.com/token/apis.html
   _token: null,
   _signedInUser: null, // the signedinuser we got from FxAccounts.
 
   // null if no error, otherwise a LOGIN_FAILED_* value that indicates why
   // we failed to authenticate (but note it might not be an actual
@@ -133,29 +129,16 @@ this.BrowserIDManager.prototype = {
   deviceID() {
     return this._signedInUser && this._signedInUser.deviceId;
   },
 
   initialize() {
     for (let topic of OBSERVER_TOPICS) {
       Services.obs.addObserver(this, topic, false);
     }
-    // and a background fetch of account data just so we can set this.account,
-    // so we have a username available before we've actually done a login.
-    // XXX - this is actually a hack just for tests and really shouldn't be
-    // necessary. Also, you'd think it would be safe to allow this.account to
-    // be set to null when there's no user logged in, but argue with the test
-    // suite, not with me :)
-    this._fxaService.getSignedInUser().then(accountData => {
-      if (accountData) {
-        this.account = accountData.email;
-      }
-    }).catch(err => {
-      // As above, this is only for tests so it is safe to ignore.
-    });
   },
 
   /**
    * Ensure the user is logged in.  Returns a promise that resolves when
    * the user is logged in, or is rejected if the login attempt has failed.
    */
   ensureLoggedIn() {
     if (!this._shouldHaveSyncKeyBundle && this.whenReadyToAuthenticate) {
@@ -220,24 +203,23 @@ this.BrowserIDManager.prototype = {
     // user completes a force authentication, so we should make
     // sure all credentials are reset before proceeding.
     this.resetCredentials();
     this._authFailureReason = null;
 
     return this._fxaService.getSignedInUser().then(accountData => {
       if (!accountData) {
         this._log.info("initializeWithCurrentIdentity has no user logged in");
-        this.account = null;
         // and we are as ready as we can ever be for auth.
         this._shouldHaveSyncKeyBundle = true;
         this.whenReadyToAuthenticate.reject("no user is logged in");
         return;
       }
 
-      this.account = accountData.email;
+      this.username = accountData.email;
       this._updateSignedInUser(accountData);
       // The user must be verified before we can do anything at all; we kick
       // this and the rest of initialization off in the background (ie, we
       // don't return the promise)
       this._log.info("Waiting for user to be verified.");
       this._fxaService.whenVerified(accountData).then(accountData => {
         this._updateSignedInUser(accountData);
         this._log.info("Starting fetch for key bundle.");
@@ -360,89 +342,65 @@ this.BrowserIDManager.prototype = {
   _now() {
     return this._fxaService.now()
   },
 
   get _localtimeOffsetMsec() {
     return this._fxaService.localtimeOffsetMsec;
   },
 
-  usernameFromAccount(val) {
-    // we don't differentiate between "username" and "account"
-    return val;
+  get syncKeyBundle() {
+    return this._syncKeyBundle;
   },
 
-  /**
-   * Obtains the HTTP Basic auth password.
-   *
-   * Returns a string if set or null if it is not set.
-   */
-  get basicPassword() {
-    this._log.error("basicPassword getter should be not used in BrowserIDManager");
-    return null;
-  },
-
-  /**
-   * Set the HTTP basic password to use.
-   *
-   * Changes will not persist unless persistSyncCredentials() is called.
-   */
-  set basicPassword(value) {
-    throw new Error("basicPassword setter should be not used in BrowserIDManager");
+  get username() {
+    return Svc.Prefs.get("username", null);
   },
 
   /**
-   * Obtain the Sync Key.
+   * Set the username value.
    *
-   * This returns a 26 character "friendly" Base32 encoded string on success or
-   * null if no Sync Key could be found.
-   *
-   * If the Sync Key hasn't been set in this session, this will look in the
-   * password manager for the sync key.
+   * Changing the username has the side-effect of wiping credentials.
    */
-  get syncKey() {
-    if (this.syncKeyBundle) {
-      // TODO: This is probably fine because the code shouldn't be
-      // using the sync key directly (it should use the sync key
-      // bundle), but I don't like it. We should probably refactor
-      // code that is inspecting this to not do validation on this
-      // field directly and instead call a isSyncKeyValid() function
-      // that we can override.
-      return "99999999999999999999999999";
+  set username(value) {
+    if (value) {
+      value = value.toLowerCase();
+
+      if (value == this.username) {
+        return;
+      }
+
+      Svc.Prefs.set("username", value);
+    } else {
+      Svc.Prefs.reset("username");
     }
-    return null;
-  },
 
-  set syncKey(value) {
-    throw "syncKey setter should be not used in BrowserIDManager";
-  },
-
-  get syncKeyBundle() {
-    return this._syncKeyBundle;
+    // If we change the username, we interpret this as a major change event
+    // and wipe out the credentials.
+    this._log.info("Username changed. Removing stored credentials.");
+    this.resetCredentials();
   },
 
   /**
    * Resets/Drops all credentials we hold for the current user.
    */
   resetCredentials() {
-    this.resetSyncKey();
+    this.resetSyncKeyBundle();
     this._token = null;
     this._hashedUID = null;
     // The cluster URL comes from the token, so resetting it to empty will
     // force Sync to not accidentally use a value from an earlier token.
     Weave.Service.clusterURL = null;
   },
 
   /**
-   * Resets/Drops the sync key we hold for the current user.
+   * Resets/Drops the sync key bundle we hold for the current user.
    */
-  resetSyncKey() {
-    this._syncKey = null;
+  resetSyncKeyBundle() {
     this._syncKeyBundle = null;
-    this._syncKeyUpdated = true;
     this._shouldHaveSyncKeyBundle = false;
   },
 
   /**
    * Pre-fetches any information that might help with migration away from this
    * identity.  Called after every sync and is really just an optimization that
    * allows us to avoid a network request for when we actually need the
    * migration info.
@@ -454,29 +412,42 @@ this.BrowserIDManager.prototype = {
   /**
     * Return credentials hosts for this identity only.
     */
   _getSyncCredentialsHosts() {
     return Utils.getSyncCredentialsHostsFxA();
   },
 
   /**
+   * Deletes Sync credentials from the password manager.
+   */
+  deleteSyncCredentials() {
+    for (let host of this._getSyncCredentialsHosts()) {
+      let logins = Services.logins.findLogins({}, host, "", "");
+      for (let login of logins) {
+        Services.logins.removeLogin(login);
+      }
+    }
+  },
+
+  /**
    * The current state of the auth credentials.
    *
    * This essentially validates that enough credentials are available to use
    * Sync. It doesn't check we have all the keys we need as the master-password
    * may have been locked when we tried to get them - we rely on
    * unlockAndVerifyAuthState to check that for us.
    */
   get currentAuthState() {
     if (this._authFailureReason) {
       this._log.info("currentAuthState returning " + this._authFailureReason +
                      " due to previous failure");
       return this._authFailureReason;
     }
+
     // TODO: need to revisit this. Currently this isn't ready to go until
     // both the username and syncKeyBundle are both configured and having no
     // username seems to make things fail fast so that's good.
     if (!this.username) {
       return LOGIN_FAILED_NO_USERNAME;
     }
 
     return STATUS_OK;
@@ -796,21 +767,49 @@ this.BrowserIDManager.prototype = {
     return LOGIN_FAILED_NETWORK_ERROR;
   },
 };
 
 /* An implementation of the ClusterManager for this identity
  */
 
 function BrowserIDClusterManager(service) {
-  ClusterManager.call(this, service);
+  this._log = log;
+  this.service = service;
 }
 
 BrowserIDClusterManager.prototype = {
-  __proto__: ClusterManager.prototype,
+  get identity() {
+    return this.service.identity;
+  },
+
+  /**
+   * Determine the cluster for the current user and update state.
+   */
+  setCluster() {
+    // Make sure we didn't get some unexpected response for the cluster.
+    let cluster = this._findCluster();
+    this._log.debug("Cluster value = " + cluster);
+    if (cluster == null) {
+      return false;
+    }
+
+    // Convert from the funky "String object with additional properties" that
+    // resource.js returns to a plain-old string.
+    cluster = cluster.toString();
+    // Don't update stuff if we already have the right cluster
+    if (cluster == this.service.clusterURL) {
+      return false;
+    }
+
+    this._log.debug("Setting cluster to " + cluster);
+    this.service.clusterURL = cluster;
+
+    return true;
+  },
 
   _findCluster() {
     let endPointFromIdentityToken = function() {
       // The only reason (in theory ;) that we can end up with a null token
       // is when this.identity._canFetchKeys() returned false.  In turn, this
       // should only happen if the master-password is locked or the credentials
       // storage is screwed, and in those cases we shouldn't have started
       // syncing so shouldn't get here anyway.
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -14,17 +14,16 @@ this.EXPORTED_SYMBOLS = [
 var {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
 
 Cu.import("resource://services-common/async.js");
 Cu.import("resource://gre/modules/JSONFile.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
 Cu.import("resource://services-common/observers.js");
 Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/identity.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/resource.js");
 Cu.import("resource://services-sync/util.js");
 
 XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
   "resource://gre/modules/FxAccounts.jsm");
 
 /*
deleted file mode 100644
--- a/services/sync/modules/identity.js
+++ /dev/null
@@ -1,604 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["IdentityManager"];
-
-var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Promise.jsm");
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://services-common/async.js");
-
-// Lazy import to prevent unnecessary load on startup.
-for (let symbol of ["BulkKeyBundle", "SyncKeyBundle"]) {
-  XPCOMUtils.defineLazyModuleGetter(this, symbol,
-                                    "resource://services-sync/keys.js",
-                                    symbol);
-}
-
-/**
- * Manages "legacy" identity and authentication for Sync.
- * See browserid_identity for the Firefox Accounts based identity manager.
- *
- * The following entities are managed:
- *
- *   account - The main Sync/services account. This is typically an email
- *     address.
- *   username - A normalized version of your account. This is what's
- *     transmitted to the server.
- *   basic password - UTF-8 password used for authenticating when using HTTP
- *     basic authentication.
- *   sync key - The main encryption key used by Sync.
- *   sync key bundle - A representation of your sync key.
- *
- * When changes are made to entities that are stored in the password manager
- * (basic password, sync key), those changes are merely staged. To commit them
- * to the password manager, you'll need to call persistCredentials().
- *
- * This type also manages authenticating Sync's network requests. Sync's
- * network code calls into getRESTRequestAuthenticator and
- * getResourceAuthenticator (depending on the network layer being used). Each
- * returns a function which can be used to add authentication information to an
- * outgoing request.
- *
- * In theory, this type supports arbitrary identity and authentication
- * mechanisms. You can add support for them by monkeypatching the global
- * instance of this type. Specifically, you'll need to redefine the
- * aforementioned network code functions to do whatever your authentication
- * mechanism needs them to do. In addition, you may wish to install custom
- * functions to support your API. Although, that is certainly not required.
- * If you do monkeypatch, please be advised that Sync expects the core
- * attributes to have values. You will need to carry at least account and
- * username forward. If you do not wish to support one of the built-in
- * authentication mechanisms, you'll probably want to redefine currentAuthState
- * and any other function that involves the built-in functionality.
- */
-this.IdentityManager = function IdentityManager() {
-  this._log = Log.repository.getLogger("Sync.Identity");
-  this._log.Level = Log.Level[Svc.Prefs.get("log.logger.identity")];
-
-  this._basicPassword = null;
-  this._basicPasswordAllowLookup = true;
-  this._basicPasswordUpdated = false;
-  this._syncKey = null;
-  this._syncKeyAllowLookup = true;
-  this._syncKeySet = false;
-  this._syncKeyBundle = null;
-}
-IdentityManager.prototype = {
-  _log: null,
-
-  _basicPassword: null,
-  _basicPasswordAllowLookup: true,
-  _basicPasswordUpdated: false,
-
-  _syncKey: null,
-  _syncKeyAllowLookup: true,
-  _syncKeySet: false,
-
-  _syncKeyBundle: null,
-
-  /**
-   * Initialize the identity provider.
-   */
-  initialize() {
-    // Nothing to do for this identity provider.
-  },
-
-  finalize() {
-    // Nothing to do for this identity provider.
-  },
-
-  /**
-   * Called whenever Service.logout() is called.
-   */
-  logout() {
-    // nothing to do for this identity provider.
-  },
-
-  /**
-   * Ensure the user is logged in.  Returns a promise that resolves when
-   * the user is logged in, or is rejected if the login attempt has failed.
-   */
-  ensureLoggedIn() {
-    // nothing to do for this identity provider
-    return Promise.resolve();
-  },
-
-  get account() {
-    return Svc.Prefs.get("account", this.username);
-  },
-
-  /**
-   * 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.
-   *
-   * Set this value to null to clear out identity information.
-   */
-  set account(value) {
-    if (value) {
-      value = value.toLowerCase();
-      Svc.Prefs.set("account", value);
-    } else {
-      Svc.Prefs.reset("account");
-    }
-
-    this.username = this.usernameFromAccount(value);
-  },
-
-  get username() {
-    return Svc.Prefs.get("username", null);
-  },
-
-  /**
-   * Set the username value.
-   *
-   * Changing the username has the side-effect of wiping credentials.
-   */
-  set username(value) {
-    if (value) {
-      value = value.toLowerCase();
-
-      if (value == this.username) {
-        return;
-      }
-
-      Svc.Prefs.set("username", value);
-    } else {
-      Svc.Prefs.reset("username");
-    }
-
-    // If we change the username, we interpret this as a major change event
-    // and wipe out the credentials.
-    this._log.info("Username changed. Removing stored credentials.");
-    this.resetCredentials();
-  },
-
-  /**
-   * Resets/Drops all credentials we hold for the current user.
-   */
-  resetCredentials() {
-    this.basicPassword = null;
-    this.resetSyncKey();
-  },
-
-  /**
-   * Resets/Drops the sync key we hold for the current user.
-   */
-  resetSyncKey() {
-    this.syncKey = null;
-    // syncKeyBundle cleared as a result of setting syncKey.
-  },
-
-  /**
-   * Obtains the HTTP Basic auth password.
-   *
-   * Returns a string if set or null if it is not set.
-   */
-  get basicPassword() {
-    if (this._basicPasswordAllowLookup) {
-      // We need a username to find the credentials.
-      let username = this.username;
-      if (!username) {
-        return null;
-      }
-
-      for (let login of this._getLogins(PWDMGR_PASSWORD_REALM)) {
-        if (login.username.toLowerCase() == username) {
-          // It should already be UTF-8 encoded, but we don't take any chances.
-          this._basicPassword = Utils.encodeUTF8(login.password);
-        }
-      }
-
-      this._basicPasswordAllowLookup = false;
-    }
-
-    return this._basicPassword;
-  },
-
-  /**
-   * Set the HTTP basic password to use.
-   *
-   * Changes will not persist unless persistSyncCredentials() is called.
-   */
-  set basicPassword(value) {
-    // Wiping out value.
-    if (!value) {
-      this._log.info("Basic password has no value. Removing.");
-      this._basicPassword = null;
-      this._basicPasswordUpdated = true;
-      this._basicPasswordAllowLookup = false;
-      return;
-    }
-
-    let username = this.username;
-    if (!username) {
-      throw new Error("basicPassword cannot be set before username.");
-    }
-
-    this._log.info("Basic password being updated.");
-    this._basicPassword = Utils.encodeUTF8(value);
-    this._basicPasswordUpdated = true;
-  },
-
-  /**
-   * Obtain the Sync Key.
-   *
-   * This returns a 26 character "friendly" Base32 encoded string on success or
-   * null if no Sync Key could be found.
-   *
-   * If the Sync Key hasn't been set in this session, this will look in the
-   * password manager for the sync key.
-   */
-  get syncKey() {
-    if (this._syncKeyAllowLookup) {
-      let username = this.username;
-      if (!username) {
-        return null;
-      }
-
-      for (let login of this._getLogins(PWDMGR_PASSPHRASE_REALM)) {
-        if (login.username.toLowerCase() == username) {
-          this._syncKey = login.password;
-        }
-      }
-
-      this._syncKeyAllowLookup = false;
-    }
-
-    return this._syncKey;
-  },
-
-  /**
-   * Set the active Sync Key.
-   *
-   * If being set to null, the Sync Key and its derived SyncKeyBundle are
-   * removed. However, the Sync Key won't be deleted from the password manager
-   * until persistSyncCredentials() is called.
-   *
-   * If a value is provided, it should be a 26 or 32 character "friendly"
-   * Base32 string for which Utils.isPassphrase() returns true.
-   *
-   * A side-effect of setting the Sync Key is that a SyncKeyBundle is
-   * generated. For historical reasons, this will silently error out if the
-   * value is not a proper Sync Key (!Utils.isPassphrase()). This should be
-   * fixed in the future (once service.js is more sane) to throw if the passed
-   * value is not valid.
-   */
-  set syncKey(value) {
-    if (!value) {
-      this._log.info("Sync Key has no value. Deleting.");
-      this._syncKey = null;
-      this._syncKeyBundle = null;
-      this._syncKeyUpdated = true;
-      return;
-    }
-
-    if (!this.username) {
-      throw new Error("syncKey cannot be set before username.");
-    }
-
-    this._log.info("Sync Key being updated.");
-    this._syncKey = value;
-
-    // Clear any cached Sync Key Bundle and regenerate it.
-    this._syncKeyBundle = null;
-
-    this._syncKeyUpdated = true;
-  },
-
-  /**
-   * Obtain the active SyncKeyBundle.
-   *
-   * This returns a SyncKeyBundle representing a key pair derived from the
-   * Sync Key on success. If no Sync Key is present or if the Sync Key is not
-   * valid, this returns null.
-   *
-   * The SyncKeyBundle should be treated as immutable.
-   */
-  get syncKeyBundle() {
-    // We can't obtain a bundle without a username set.
-    if (!this.username) {
-      this._log.warn("Attempted to obtain Sync Key Bundle with no username set!");
-      return null;
-    }
-
-    if (!this.syncKey) {
-      this._log.warn("Attempted to obtain Sync Key Bundle with no Sync Key " +
-                     "set!");
-      return null;
-    }
-
-    if (!this._syncKeyBundle) {
-      try {
-        this._syncKeyBundle = new SyncKeyBundle(this.username, this.syncKey);
-      } catch (ex) {
-        this._log.warn("Failed to create sync bundle", ex);
-        return null;
-      }
-    }
-
-    return this._syncKeyBundle;
-  },
-
-  /**
-   * The current state of the auth credentials.
-   *
-   * This essentially validates that enough credentials are available to use
-   * Sync.
-   */
-  get currentAuthState() {
-    if (!this.username) {
-      return LOGIN_FAILED_NO_USERNAME;
-    }
-
-    if (Utils.mpLocked()) {
-      return STATUS_OK;
-    }
-
-    if (!this.basicPassword) {
-      return LOGIN_FAILED_NO_PASSWORD;
-    }
-
-    if (!this.syncKey) {
-      return LOGIN_FAILED_NO_PASSPHRASE;
-    }
-
-    // If we have a Sync Key but no bundle, bundle creation failed, which
-    // implies a bad Sync Key.
-    if (!this.syncKeyBundle) {
-      return LOGIN_FAILED_INVALID_PASSPHRASE;
-    }
-
-    return STATUS_OK;
-  },
-
-  /**
-   * Verify the current auth state, unlocking the master-password if necessary.
-   *
-   * Returns a promise that resolves with the current auth state after
-   * attempting to unlock.
-   */
-  unlockAndVerifyAuthState() {
-    // Try to fetch the passphrase - this will prompt for MP unlock as a
-    // side-effect...
-    try {
-      this.syncKey;
-    } catch (ex) {
-      this._log.debug("Fetching passphrase threw " + ex +
-                      "; assuming master password locked.");
-      return Promise.resolve(MASTER_PASSWORD_LOCKED);
-    }
-    return Promise.resolve(STATUS_OK);
-  },
-
-  /**
-   * Persist credentials to password store.
-   *
-   * When credentials are updated, they are changed in memory only. This will
-   * need to be called to save them to the underlying password store.
-   *
-   * If the password store is locked (e.g. if the master password hasn't been
-   * entered), this could throw an exception.
-   */
-  persistCredentials: function persistCredentials(force) {
-    if (this._basicPasswordUpdated || force) {
-      if (this._basicPassword) {
-        this._setLogin(PWDMGR_PASSWORD_REALM, this.username,
-                       this._basicPassword);
-      } else {
-        for (let login of this._getLogins(PWDMGR_PASSWORD_REALM)) {
-          Services.logins.removeLogin(login);
-        }
-      }
-
-      this._basicPasswordUpdated = false;
-    }
-
-    if (this._syncKeyUpdated || force) {
-      if (this._syncKey) {
-        this._setLogin(PWDMGR_PASSPHRASE_REALM, this.username, this._syncKey);
-      } else {
-        for (let login of this._getLogins(PWDMGR_PASSPHRASE_REALM)) {
-          Services.logins.removeLogin(login);
-        }
-      }
-
-      this._syncKeyUpdated = false;
-    }
-
-  },
-
-  /**
-   * Deletes the Sync Key from the system.
-   */
-  deleteSyncKey: function deleteSyncKey() {
-    this.syncKey = null;
-    this.persistCredentials();
-  },
-
-  hasBasicCredentials: function hasBasicCredentials() {
-    // Because JavaScript.
-    return this.username && this.basicPassword && true;
-  },
-
-  /**
-   * Pre-fetches any information that might help with migration away from this
-   * identity.  Called after every sync and is really just an optimization that
-   * allows us to avoid a network request for when we actually need the
-   * migration info.
-   */
-  prefetchMigrationSentinel(service) {
-    // Try and fetch the migration sentinel - it will end up in the recordManager
-    // cache.
-    try {
-      service.recordManager.get(service.storageURL + "meta/fxa_credentials");
-    } catch (ex) {
-      if (Async.isShutdownException(ex)) {
-        throw ex;
-      }
-      this._log.warn("Failed to pre-fetch the migration sentinel", ex);
-    }
-  },
-
-  /**
-   * Obtains the array of basic logins from nsiPasswordManager.
-   */
-  _getLogins: function _getLogins(realm) {
-    return Services.logins.findLogins({}, PWDMGR_HOST, null, realm);
-  },
-
-  /**
-   * Set a login in the password manager.
-   *
-   * This has the side-effect of deleting any other logins for the specified
-   * realm.
-   */
-  _setLogin: function _setLogin(realm, username, password) {
-    let exists = false;
-    for (let login of this._getLogins(realm)) {
-      if (login.username == username && login.password == password) {
-        exists = true;
-      } else {
-        this._log.debug("Pruning old login for " + username + " from " + realm);
-        Services.logins.removeLogin(login);
-      }
-    }
-
-    if (exists) {
-      return;
-    }
-
-    this._log.debug("Updating saved password for " + username + " in " +
-                    realm);
-
-    let loginInfo = new Components.Constructor(
-      "@mozilla.org/login-manager/loginInfo;1", Ci.nsILoginInfo, "init");
-    let login = new loginInfo(PWDMGR_HOST, null, realm, username,
-                                password, "", "");
-    Services.logins.addLogin(login);
-  },
-
-  /**
-    * Return credentials hosts for this identity only.
-    */
-  _getSyncCredentialsHosts() {
-    return Utils.getSyncCredentialsHostsLegacy();
-  },
-
-  /**
-   * Deletes Sync credentials from the password manager.
-   */
-  deleteSyncCredentials: function deleteSyncCredentials() {
-    for (let host of this._getSyncCredentialsHosts()) {
-      let logins = Services.logins.findLogins({}, host, "", "");
-      for (let login of 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;
-    // this._syncKeyBundle is nullified as part of _syncKey setter.
-    this._syncKeyAllowLookup = true;
-    this._syncKeyUpdated = false;
-  },
-
-  usernameFromAccount: function usernameFromAccount(value) {
-    // If we encounter characters not allowed by the API (as found for
-    // instance in an email address), hash the value.
-    if (value && value.match(/[^A-Z0-9._-]/i)) {
-      return Utils.sha1Base32(value.toLowerCase()).toLowerCase();
-    }
-
-    return value ? value.toLowerCase() : value;
-  },
-
-  /**
-   * Obtain a function to be used for adding auth to Resource HTTP requests.
-   */
-  getResourceAuthenticator: function getResourceAuthenticator() {
-    if (this.hasBasicCredentials()) {
-      return this._onResourceRequestBasic.bind(this);
-    }
-
-    return null;
-  },
-
-  /**
-   * Helper method to return an authenticator for basic Resource requests.
-   */
-  getBasicResourceAuthenticator:
-    function getBasicResourceAuthenticator(username, password) {
-
-    return function basicAuthenticator(resource) {
-      let value = "Basic " + btoa(username + ":" + password);
-      return {headers: {authorization: value}};
-    };
-  },
-
-  _onResourceRequestBasic: function _onResourceRequestBasic(resource) {
-    let value = "Basic " + btoa(this.username + ":" + this.basicPassword);
-    return {headers: {authorization: value}};
-  },
-
-  _onResourceRequestMAC: function _onResourceRequestMAC(resource, method) {
-    // TODO Get identifier and key from somewhere.
-    let identifier;
-    let key;
-    let result = Utils.computeHTTPMACSHA1(identifier, key, method, resource.uri);
-
-    return {headers: {authorization: result.header}};
-  },
-
-  /**
-   * Obtain a function to be used for adding auth to RESTRequest instances.
-   */
-  getRESTRequestAuthenticator: function getRESTRequestAuthenticator() {
-    if (this.hasBasicCredentials()) {
-      return this.onRESTRequestBasic.bind(this);
-    }
-
-    return null;
-  },
-
-  onRESTRequestBasic: function onRESTRequestBasic(request) {
-    let up = this.username + ":" + this.basicPassword;
-    request.setHeader("authorization", "Basic " + btoa(up));
-  },
-
-  createClusterManager(service) {
-    Cu.import("resource://services-sync/stages/cluster.js");
-    return new ClusterManager(service);
-  },
-
-  offerSyncOptions() {
-    // Do nothing for Sync 1.1.
-    return {accepted: true};
-  },
-
-  // Tell Sync what the login status should be if it saw a 401 fetching
-  // info/collections as part of login verification (typically immediately
-  // after login.)
-  // In our case it means an authoritative "password is incorrect".
-  loginStatusFromVerification404() {
-    return LOGIN_FAILED_LOGIN_REJECTED;
-  }
-
-};
--- a/services/sync/modules/policies.js
+++ b/services/sync/modules/policies.js
@@ -30,37 +30,29 @@ function getThrottledIntervalPreference(
 
 this.SyncScheduler = function SyncScheduler(service) {
   this.service = service;
   this.init();
 }
 SyncScheduler.prototype = {
   _log: Log.repository.getLogger("Sync.SyncScheduler"),
 
-  _fatalLoginStatus: [LOGIN_FAILED_NO_USERNAME,
-                      LOGIN_FAILED_NO_PASSPHRASE,
+  _fatalLoginStatus: [LOGIN_FAILED_NO_PASSPHRASE,
                       LOGIN_FAILED_INVALID_PASSPHRASE,
                       LOGIN_FAILED_LOGIN_REJECTED],
 
   /**
    * The nsITimer object that schedules the next sync. See scheduleNextSync().
    */
   syncTimer: null,
 
   setDefaults: function setDefaults() {
     this._log.trace("Setting SyncScheduler policy values to defaults.");
 
-    let service = Cc["@mozilla.org/weave/service;1"]
-                    .getService(Ci.nsISupports)
-                    .wrappedJSObject;
-
-    let part = service.fxAccountsEnabled ? "fxa" : "sync11";
-    let prefSDInterval = "scheduler." + part + ".singleDeviceInterval";
-    this.singleDeviceInterval = getThrottledIntervalPreference(prefSDInterval);
-
+    this.singleDeviceInterval = getThrottledIntervalPreference("scheduler.fxa.singleDeviceInterval");
     this.idleInterval         = getThrottledIntervalPreference("scheduler.idleInterval");
     this.activeInterval       = getThrottledIntervalPreference("scheduler.activeInterval");
     this.immediateInterval    = getThrottledIntervalPreference("scheduler.immediateInterval");
     this.eolInterval          = getThrottledIntervalPreference("scheduler.eolInterval");
 
     // A user is non-idle on startup by default.
     this.idle = false;
 
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -16,20 +16,20 @@ const CLUSTER_BACKOFF = 5 * 60 * 1000; /
 const PBKDF2_KEY_BYTES = 16;
 
 const CRYPTO_COLLECTION = "crypto";
 const KEYS_WBO = "keys";
 
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://services-common/async.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/clients.js");
-Cu.import("resource://services-sync/identity.js");
 Cu.import("resource://services-sync/policies.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/resource.js");
 Cu.import("resource://services-sync/rest.js");
 Cu.import("resource://services-sync/stages/enginesync.js");
 Cu.import("resource://services-sync/stages/declined.js");
 Cu.import("resource://services-sync/status.js");
 Cu.import("resource://services-sync/telemetry.js");
@@ -149,17 +149,17 @@ Sync11Service.prototype = {
     if (!this._clusterManager) {
       return null;
     }
     return this._clusterManager.getUserBaseURL();
   },
 
   _updateCachedURLs: function _updateCachedURLs() {
     // Nothing to cache yet if we don't have the building blocks
-    if (!this.clusterURL || !this.identity.username) {
+    if (!this.clusterURL) {
       // Also reset all other URLs used by Sync to ensure we aren't accidentally
       // using one cached earlier - if there's no cluster URL any cached ones
       // are invalid.
       this.infoURL = undefined;
       this.storageURL = undefined;
       this.metaURL = undefined;
       this.cryptoKeysURL = undefined;
       return;
@@ -298,24 +298,16 @@ Sync11Service.prototype = {
   },
 
   /**
    * Prepare to initialize the rest of Weave after waiting a little bit
    */
   onStartup: function onStartup() {
     this._migratePrefs();
 
-    // Status is instantiated before us and is the first to grab an instance of
-    // the IdentityManager. We use that instance because IdentityManager really
-    // needs to be a singleton. Ideally, the longer-lived object would spawn
-    // this service instance.
-    if (!Status || !Status._authManager) {
-      throw new Error("Status or Status._authManager not initialized.");
-    }
-
     this.status = Status;
     this.identity = Status._authManager;
     this.collectionKeys = new CollectionKeyManager();
 
     this.errorHandler = new ErrorHandler(this);
 
     this._log = Log.repository.getLogger("Sync.Service");
     this._log.level =
@@ -544,31 +536,19 @@ Sync11Service.prototype = {
     }
     return info;
   },
 
   verifyAndFetchSymmetricKeys: function verifyAndFetchSymmetricKeys(infoResponse) {
 
     this._log.debug("Fetching and verifying -- or generating -- symmetric keys.");
 
-    // Don't allow empty/missing passphrase.
-    // Furthermore, we assume that our sync key is already upgraded,
-    // and fail if that assumption is invalidated.
-
-    if (!this.identity.syncKey) {
-      this.status.login = LOGIN_FAILED_NO_PASSPHRASE;
-      this.status.sync = CREDENTIALS_CHANGED;
-      return false;
-    }
-
     let syncKeyBundle = this.identity.syncKeyBundle;
     if (!syncKeyBundle) {
-      this._log.error("Sync Key Bundle not set. Invalid Sync Key?");
-
-      this.status.login = LOGIN_FAILED_INVALID_PASSPHRASE;
+      this.status.login = LOGIN_FAILED_NO_PASSPHRASE;
       this.status.sync = CREDENTIALS_CHANGED;
       return false;
     }
 
     try {
       if (!infoResponse)
         infoResponse = this._fetchInfo();    // Will throw an exception on failure.
 
@@ -694,17 +674,17 @@ Sync11Service.prototype = {
 
       switch (test.status) {
         case 200:
           // The user is authenticated.
 
           // We have no way of verifying the passphrase right now,
           // so wait until remoteSetup to do so.
           // Just make the most trivial checks.
-          if (!this.identity.syncKey) {
+          if (!this.identity.syncKeyBundle) {
             this._log.warn("No passphrase in verifyLogin.");
             this.status.login = LOGIN_FAILED_NO_PASSPHRASE;
             return false;
           }
 
           // Go ahead and do remote setup, so that we can determine
           // conclusively that our passphrase is correct.
           if (this._remoteSetup(test)) {
@@ -802,40 +782,16 @@ Sync11Service.prototype = {
     }
     let keysChanged = this.handleFetchedKeys(this.identity.syncKeyBundle,
                                              cryptoKeys, true);
     if (keysChanged) {
       this._log.info("Downloaded keys differed, as expected.");
     }
   },
 
-  changePassphrase: function changePassphrase(newphrase) {
-    return this._catch(function doChangePasphrase() {
-      /* Wipe. */
-      this.wipeServer();
-
-      this.logout();
-
-      /* Set this so UI is updated on next run. */
-      this.identity.syncKey = newphrase;
-      this.persistLogin();
-
-      /* We need to re-encrypt everything, so reset. */
-      this.resetClient();
-      this.collectionKeys.clear();
-
-      /* Login and sync. This also generates new keys. */
-      this.sync();
-
-      Svc.Obs.notify("weave:service:change-passphrase", true);
-
-      return true;
-    })();
-  },
-
   startOver: function startOver() {
     this._log.trace("Invoking Service.startOver.");
     Svc.Obs.notify("weave:engine:stop-tracking");
     this.status.resetSync();
 
     // Deletion doesn't make sense if we aren't set up yet!
     if (this.clusterURL != "") {
       // Clear client-specific data from the server, including disabled engines.
@@ -850,17 +806,17 @@ Sync11Service.prototype = {
     } else {
       this._log.debug("Skipping client data removal: no cluster URL.");
     }
 
     // We want let UI consumers of the following notification know as soon as
     // possible, so let's fake for the CLIENT_NOT_CONFIGURED status for now
     // by emptying the passphrase (we still need the password).
     this._log.info("Service.startOver dropping sync key and logging out.");
-    this.identity.resetSyncKey();
+    this.identity.resetSyncKeyBundle();
     this.status.login = LOGIN_FAILED_NO_PASSPHRASE;
     this.logout();
     Svc.Obs.notify("weave:service:start-over");
 
     // Reset all engines and clear keys.
     this.resetClient();
     this.collectionKeys.clear();
     this.status.resetBackoff();
@@ -886,77 +842,51 @@ Sync11Service.prototype = {
       return;
     }
 
     try {
       this.identity.finalize();
       // an observer so the FxA migration code can take some action before
       // the new identity is created.
       Svc.Obs.notify("weave:service:start-over:init-identity");
-      this.identity.username = "";
       this.status.__authManager = null;
       this.identity = Status._authManager;
       this._clusterManager = this.identity.createClusterManager(this);
       Svc.Obs.notify("weave:service:start-over:finish");
     } catch (err) {
       this._log.error("startOver failed to re-initialize the identity manager: " + err);
       // Still send the observer notification so the current state is
       // reflected in the UI.
       Svc.Obs.notify("weave:service:start-over:finish");
     }
   },
 
-  persistLogin: function persistLogin() {
-    try {
-      this.identity.persistCredentials(true);
-    } catch (ex) {
-      this._log.info("Unable to persist credentials: " + ex);
-    }
-  },
-
-  login: function login(username, password, passphrase) {
+  login: function login() {
     function onNotify() {
       this._loggedIn = false;
       if (Services.io.offline) {
         this.status.login = LOGIN_FAILED_NETWORK_ERROR;
         throw "Application is offline, login should not be called";
       }
 
-      let initialStatus = this._checkSetup();
-      if (username) {
-        this.identity.username = username;
-      }
-      if (password) {
-        this.identity.basicPassword = password;
-      }
-      if (passphrase) {
-        this.identity.syncKey = passphrase;
-      }
-
       if (this._checkSetup() == CLIENT_NOT_CONFIGURED) {
         throw "Aborting login, client not configured.";
       }
 
       // Ask the identity manager to explicitly login now.
       this._log.info("Logging in the user.");
       let cb = Async.makeSpinningCallback();
       this.identity.ensureLoggedIn().then(
         () => cb(null),
         err => cb(err || "ensureLoggedIn failed")
       );
 
       // Just let any errors bubble up - they've more context than we do!
       cb.wait();
 
-      // Calling login() with parameters when the client was
-      // previously not configured means setup was completed.
-      if (initialStatus == CLIENT_NOT_CONFIGURED
-          && (username || password || passphrase)) {
-        Svc.Obs.notify("weave:service:setup-complete");
-      }
       this._updateCachedURLs();
 
       this._log.info("User logged in successfully - verifying login.");
       if (!this.verifyLogin()) {
         // verifyLogin sets the failure states here.
         throw "Login failed: " + this.status.login;
       }
 
@@ -1120,40 +1050,30 @@ Sync11Service.prototype = {
     } else if (meta.payload.syncID != this.syncID) {
 
       this._log.info("Sync IDs differ. Local is " + this.syncID + ", remote is " + meta.payload.syncID);
       this.resetClient();
       this.collectionKeys.clear();
       this.syncID = meta.payload.syncID;
       this._log.debug("Clear cached values and take syncId: " + this.syncID);
 
-      if (!this.upgradeSyncKey(meta.payload.syncID)) {
-        this._log.warn("Failed to upgrade sync key. Failing remote setup.");
-        return false;
-      }
-
       if (!this.verifyAndFetchSymmetricKeys(infoResponse)) {
         this._log.warn("Failed to fetch symmetric keys. Failing remote setup.");
         return false;
       }
 
       // bug 545725 - re-verify creds and fail sanely
       if (!this.verifyLogin()) {
         this.status.sync = CREDENTIALS_CHANGED;
         this._log.info("Credentials have changed, aborting sync and forcing re-login.");
         return false;
       }
 
       return true;
     }
-    if (!this.upgradeSyncKey(meta.payload.syncID)) {
-      this._log.warn("Failed to upgrade sync key. Failing remote setup.");
-      return false;
-    }
-
     if (!this.verifyAndFetchSymmetricKeys(infoResponse)) {
       this._log.warn("Failed to fetch symmetric keys. Failing remote setup.");
       return false;
     }
 
     return true;
   },
 
@@ -1368,63 +1288,20 @@ Sync11Service.prototype = {
       this.recordManager.set(collectionURL, cryptoWrapper);
     } catch (ex) {
       this._log.error("Failed to set the migration sentinel: ${}", ex);
       return Promise.resolve(false);
     }
     return Promise.resolve(true);
   },
 
-  /**
-   * If we have a passphrase, rather than a 25-alphadigit sync key,
-   * use the provided sync ID to bootstrap it using PBKDF2.
-   *
-   * Store the new 'passphrase' back into the identity manager.
-   *
-   * We can check this as often as we want, because once it's done the
-   * check will no longer succeed. It only matters that it happens after
-   * we decide to bump the server storage version.
-   */
-  upgradeSyncKey: function upgradeSyncKey(syncID) {
-    let p = this.identity.syncKey;
-
-    if (!p) {
-      return false;
-    }
-
-    // Check whether it's already a key that we generated.
-    if (Utils.isPassphrase(p)) {
-      this._log.info("Sync key is up-to-date: no need to upgrade.");
-      return true;
-    }
-
-    // Otherwise, let's upgrade it.
-    // N.B., we persist the sync key without testing it first...
-
-    let s = btoa(syncID);        // It's what WeaveCrypto expects. *sigh*
-    let k = Utils.derivePresentableKeyFromPassphrase(p, s, PBKDF2_KEY_BYTES);   // Base 32.
-
-    if (!k) {
-      this._log.error("No key resulted from derivePresentableKeyFromPassphrase. Failing upgrade.");
-      return false;
-    }
-
-    this._log.info("Upgrading sync key...");
-    this.identity.syncKey = k;
-    this._log.info("Saving upgraded sync key...");
-    this.persistLogin();
-    this._log.info("Done saving.");
-    return true;
-  },
-
   _freshStart: function _freshStart() {
-    this._log.info("Fresh start. Resetting client and considering key upgrade.");
+    this._log.info("Fresh start. Resetting client.");
     this.resetClient();
     this.collectionKeys.clear();
-    this.upgradeSyncKey(this.syncID);
 
     // Wipe the server.
     this.wipeServer();
 
     // Upload a new meta/global record.
     let meta = new WBORecord("meta", "global");
     meta.payload.syncID = this.syncID;
     meta.payload.storageVersion = STORAGE_VERSION;
@@ -1523,19 +1400,16 @@ Sync11Service.prototype = {
     }
 
     // Fully wipe each engine if it's able to decrypt data
     for (let engine of engines) {
       if (engine.canDecrypt()) {
         engine.wipeClient();
       }
     }
-
-    // Save the password/passphrase just in-case they aren't restored by sync
-    this.persistLogin();
   },
 
   /**
    * Wipe all remote user data by wiping the server then telling each remote
    * client to wipe itself.
    *
    * @param engines [optional]
    *        Array of engine names to wipe. If not given, all engines are used.
deleted file mode 100644
--- a/services/sync/modules/stages/cluster.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/* 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/. */
-
-this.EXPORTED_SYMBOLS = ["ClusterManager"];
-
-var {utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/policies.js");
-Cu.import("resource://services-sync/util.js");
-
-/**
- * Contains code for managing the Sync cluster we are in.
- */
-this.ClusterManager = function ClusterManager(service) {
-  this._log = Log.repository.getLogger("Sync.Service");
-  this._log.level = Log.Level[Svc.Prefs.get("log.logger.service.main")];
-
-  this.service = service;
-}
-ClusterManager.prototype = {
-  get identity() {
-    return this.service.identity;
-  },
-
-  /**
-   * Obtain the cluster for the current user.
-   *
-   * Returns the string URL of the cluster or null on error.
-   */
-  _findCluster: function _findCluster() {
-    this._log.debug("Finding cluster for user " + this.identity.username);
-
-    // This should ideally use UserAPI10Client but the legacy hackiness is
-    // strong with this code.
-    let fail;
-    let url = this.service.userAPIURI + this.identity.username + "/node/weave";
-    let res = this.service.resource(url);
-    try {
-      let node = res.get();
-      switch (node.status) {
-        case 400:
-          this.service.status.login = LOGIN_FAILED_LOGIN_REJECTED;
-          fail = "Find cluster denied: " + this.service.errorHandler.errorStr(node);
-          break;
-        case 404:
-          this._log.debug("Using serverURL as data cluster (multi-cluster support disabled)");
-          return this.service.serverURL;
-        case 0:
-        case 200:
-          if (node == "null") {
-            node = null;
-          }
-          this._log.trace("_findCluster successfully returning " + node);
-          return node;
-        default:
-          this.service.errorHandler.checkServerError(node);
-          fail = "Unexpected response code: " + node.status;
-          break;
-      }
-    } catch (e) {
-      this._log.debug("Network error on findCluster");
-      this.service.status.login = LOGIN_FAILED_NETWORK_ERROR;
-      this.service.errorHandler.checkServerError(e);
-      fail = e;
-    }
-    throw fail;
-  },
-
-  /**
-   * Determine the cluster for the current user and update state.
-   */
-  setCluster: function setCluster() {
-    // Make sure we didn't get some unexpected response for the cluster.
-    let cluster = this._findCluster();
-    this._log.debug("Cluster value = " + cluster);
-    if (cluster == null) {
-      return false;
-    }
-
-    // Convert from the funky "String object with additional properties" that
-    // resource.js returns to a plain-old string.
-    cluster = cluster.toString();
-    // Don't update stuff if we already have the right cluster
-    if (cluster == this.service.clusterURL) {
-      return false;
-    }
-
-    this._log.debug("Setting cluster to " + cluster);
-    this.service.clusterURL = cluster;
-
-    return true;
-  },
-
-  getUserBaseURL: function getUserBaseURL() {
-    // Legacy Sync and FxA Sync construct the userBaseURL differently. Legacy
-    // Sync appends path components onto an empty path, and in FxA Sync, the
-    // token server constructs this for us in an opaque manner. Since the
-    // cluster manager already sets the clusterURL on Service and also has
-    // access to the current identity, we added this functionality here.
-
-    // If the clusterURL hasn't been set, the userBaseURL shouldn't be set
-    // either. Some tests expect "undefined" to be returned here.
-    if (!this.service.clusterURL) {
-      return undefined;
-    }
-    let storageAPI = this.service.clusterURL + SYNC_API_VERSION + "/";
-    return storageAPI + this.identity.username + "/";
-  }
-};
-Object.freeze(ClusterManager.prototype);
--- a/services/sync/modules/status.js
+++ b/services/sync/modules/status.js
@@ -6,35 +6,30 @@ this.EXPORTED_SYMBOLS = ["Status"];
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cr = Components.results;
 var Cu = Components.utils;
 
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://services-sync/identity.js");
 Cu.import("resource://services-sync/browserid_identity.js");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://services-common/async.js");
 
 this.Status = {
   _log: Log.repository.getLogger("Sync.Status"),
   __authManager: null,
   ready: false,
 
   get _authManager() {
     if (this.__authManager) {
       return this.__authManager;
     }
-    let service = Components.classes["@mozilla.org/weave/service;1"]
-                    .getService(Components.interfaces.nsISupports)
-                    .wrappedJSObject;
-    let idClass = service.fxAccountsEnabled ? BrowserIDManager : IdentityManager;
-    this.__authManager = new idClass();
+    this.__authManager = new BrowserIDManager();
     this.__authManager.initialize();
     return this.__authManager;
   },
 
   get service() {
     return this._service;
   },
 
--- a/services/sync/moz.build
+++ b/services/sync/moz.build
@@ -19,17 +19,16 @@ EXTRA_COMPONENTS += [
 EXTRA_JS_MODULES['services-sync'] += [
     'modules/addonsreconciler.js',
     'modules/addonutils.js',
     'modules/bookmark_validator.js',
     'modules/browserid_identity.js',
     'modules/collection_validator.js',
     'modules/engines.js',
     'modules/FxaMigrator.jsm',
-    'modules/identity.js',
     'modules/keys.js',
     'modules/main.js',
     'modules/policies.js',
     'modules/record.js',
     'modules/resource.js',
     'modules/rest.js',
     'modules/service.js',
     'modules/status.js',
@@ -54,17 +53,16 @@ EXTRA_JS_MODULES['services-sync'].engine
     'modules/engines/forms.js',
     'modules/engines/history.js',
     'modules/engines/passwords.js',
     'modules/engines/prefs.js',
     'modules/engines/tabs.js',
 ]
 
 EXTRA_JS_MODULES['services-sync'].stages += [
-    'modules/stages/cluster.js',
     'modules/stages/declined.js',
     'modules/stages/enginesync.js',
 ]
 
 TESTING_JS_MODULES.services.sync += [
     'modules-testing/fakeservices.js',
     'modules-testing/fxa_utils.js',
     'modules-testing/rotaryengine.js',
--- a/services/sync/services-sync.js
+++ b/services/sync/services-sync.js
@@ -14,17 +14,16 @@ pref("services.sync.sendVersionInfo", tr
 
 pref("services.sync.scheduler.eolInterval", 604800); // 1 week
 pref("services.sync.scheduler.idleInterval", 3600);  // 1 hour
 pref("services.sync.scheduler.activeInterval", 600);   // 10 minutes
 pref("services.sync.scheduler.immediateInterval", 90);    // 1.5 minutes
 pref("services.sync.scheduler.idleTime", 300);   // 5 minutes
 
 pref("services.sync.scheduler.fxa.singleDeviceInterval", 3600); // 1 hour
-pref("services.sync.scheduler.sync11.singleDeviceInterval", 86400); // 1 day
 
 pref("services.sync.errorhandler.networkFailureReportTimeout", 1209600); // 2 weeks
 
 pref("services.sync.engine.addons", true);
 pref("services.sync.engine.bookmarks", true);
 pref("services.sync.engine.history", true);
 pref("services.sync.engine.passwords", true);
 pref("services.sync.engine.prefs", true);
deleted file mode 100644
--- a/services/sync/tests/unit/test_identity_manager.js
+++ /dev/null
@@ -1,284 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/identity.js");
-Cu.import("resource://services-sync/util.js");
-
-var identity = new IdentityManager();
-
-function run_test() {
-  initTestLogging("Trace");
-  Log.repository.getLogger("Sync.Identity").level = Log.Level.Trace;
-
-  run_next_test();
-}
-
-add_test(function test_username_from_account() {
-  _("Ensure usernameFromAccount works properly.");
-
-  do_check_eq(identity.usernameFromAccount(null), null);
-  do_check_eq(identity.usernameFromAccount("user"), "user");
-  do_check_eq(identity.usernameFromAccount("User"), "user");
-  do_check_eq(identity.usernameFromAccount("john@doe.com"),
-                                           "7wohs32cngzuqt466q3ge7indszva4of");
-
-  run_next_test();
-});
-
-add_test(function test_account_username() {
-  _("Ensure the account and username attributes work properly.");
-
-  _("Verify initial state");
-  do_check_eq(Svc.Prefs.get("account"), undefined);
-  do_check_eq(Svc.Prefs.get("username"), undefined);
-  do_check_eq(identity.account, null);
-  do_check_eq(identity.username, null);
-
-  _("The 'username' attribute is normalized to lower case, updates preferences and identities.");
-  identity.username = "TarZan";
-  do_check_eq(identity.username, "tarzan");
-  do_check_eq(Svc.Prefs.get("username"), "tarzan");
-  do_check_eq(identity.username, "tarzan");
-
-  _("If not set, the 'account attribute' falls back to the username for backwards compatibility.");
-  do_check_eq(identity.account, "tarzan");
-
-  _("Setting 'username' to a non-truthy value resets the pref.");
-  identity.username = null;
-  do_check_eq(identity.username, null);
-  do_check_eq(identity.account, null);
-  const default_marker = {};
-  do_check_eq(Svc.Prefs.get("username", default_marker), default_marker);
-  do_check_eq(identity.username, null);
-
-  _("The 'account' attribute will set the 'username' if it doesn't contain characters that aren't allowed in the username.");
-  identity.account = "johndoe";
-  do_check_eq(identity.account, "johndoe");
-  do_check_eq(identity.username, "johndoe");
-  do_check_eq(Svc.Prefs.get("username"), "johndoe");
-  do_check_eq(identity.username, "johndoe");
-
-  _("If 'account' contains disallowed characters such as @, 'username' will the base32 encoded SHA1 hash of 'account'");
-  identity.account = "John@Doe.com";
-  do_check_eq(identity.account, "john@doe.com");
-  do_check_eq(identity.username, "7wohs32cngzuqt466q3ge7indszva4of");
-
-  _("Setting 'account' to a non-truthy value resets the pref.");
-  identity.account = null;
-  do_check_eq(identity.account, null);
-  do_check_eq(Svc.Prefs.get("account", default_marker), default_marker);
-  do_check_eq(identity.username, null);
-  do_check_eq(Svc.Prefs.get("username", default_marker), default_marker);
-
-  Svc.Prefs.resetBranch("");
-  run_next_test();
-});
-
-add_test(function test_basic_password() {
-  _("Ensure basic password setting works as expected.");
-
-  identity.account = null;
-  do_check_eq(identity.currentAuthState, LOGIN_FAILED_NO_USERNAME);
-  let thrown = false;
-  try {
-    identity.basicPassword = "foobar";
-  } catch (ex) {
-    thrown = true;
-  }
-
-  do_check_true(thrown);
-  thrown = false;
-
-  identity.account = "johndoe";
-  do_check_eq(identity.currentAuthState, LOGIN_FAILED_NO_PASSWORD);
-  identity.basicPassword = "password";
-  do_check_eq(identity.basicPassword, "password");
-  do_check_eq(identity.currentAuthState, LOGIN_FAILED_NO_PASSPHRASE);
-  do_check_true(identity.hasBasicCredentials());
-
-  identity.account = null;
-
-  run_next_test();
-});
-
-add_test(function test_basic_password_persistence() {
-  _("Ensure credentials are saved and restored to the login manager properly.");
-
-  // Just in case.
-  identity.account = null;
-  identity.deleteSyncCredentials();
-
-  identity.account = "janesmith";
-  identity.basicPassword = "ilovejohn";
-  identity.persistCredentials();
-
-  let im1 = new IdentityManager();
-  do_check_eq(im1._basicPassword, null);
-  do_check_eq(im1.username, "janesmith");
-  do_check_eq(im1.basicPassword, "ilovejohn");
-
-  let im2 = new IdentityManager();
-  do_check_eq(im2._basicPassword, null);
-
-  _("Now remove the password and ensure it is deleted from storage.");
-  identity.basicPassword = null;
-  identity.persistCredentials(); // This should nuke from storage.
-  do_check_eq(im2.basicPassword, null);
-
-  _("Ensure that retrieving an unset but unpersisted removal returns null.");
-  identity.account = "janesmith";
-  identity.basicPassword = "myotherpassword";
-  identity.persistCredentials();
-
-  identity.basicPassword = null;
-  do_check_eq(identity.basicPassword, null);
-
-  // Reset for next test.
-  identity.account = null;
-  identity.persistCredentials();
-
-  run_next_test();
-});
-
-add_test(function test_sync_key() {
-  _("Ensure Sync Key works as advertised.");
-
-  _("Ensure setting a Sync Key before an account throws.");
-  let thrown = false;
-  try {
-    identity.syncKey = "blahblah";
-  } catch (ex) {
-    thrown = true;
-  }
-  do_check_true(thrown);
-  thrown = false;
-
-  identity.account = "johnsmith";
-  identity.basicPassword = "johnsmithpw";
-
-  do_check_eq(identity.syncKey, null);
-  do_check_eq(identity.syncKeyBundle, null);
-
-  _("An invalid Sync Key is silently accepted for historical reasons.");
-  identity.syncKey = "synckey";
-  do_check_eq(identity.syncKey, "synckey");
-
-  _("But the SyncKeyBundle should not be created from bad keys.");
-  do_check_eq(identity.syncKeyBundle, null);
-
-  let syncKey = Utils.generatePassphrase();
-  identity.syncKey = syncKey;
-  do_check_eq(identity.syncKey, syncKey);
-  do_check_neq(identity.syncKeyBundle, null);
-
-  let im = new IdentityManager();
-  im.account = "pseudojohn";
-  do_check_eq(im.syncKey, null);
-  do_check_eq(im.syncKeyBundle, null);
-
-  identity.account = null;
-
-  run_next_test();
-});
-
-add_test(function test_sync_key_changes() {
-  _("Ensure changes to Sync Key have appropriate side-effects.");
-
-  let im = new IdentityManager();
-  let sk1 = Utils.generatePassphrase();
-  let sk2 = Utils.generatePassphrase();
-
-  im.account = "johndoe";
-  do_check_eq(im.syncKey, null);
-  do_check_eq(im.syncKeyBundle, null);
-
-  im.syncKey = sk1;
-  do_check_neq(im.syncKeyBundle, null);
-
-  let ek1 = im.syncKeyBundle.encryptionKeyB64;
-  let hk1 = im.syncKeyBundle.hmacKeyB64;
-
-  // Change the Sync Key and ensure the Sync Key Bundle is updated.
-  im.syncKey = sk2;
-  let ek2 = im.syncKeyBundle.encryptionKeyB64;
-  let hk2 = im.syncKeyBundle.hmacKeyB64;
-
-  do_check_neq(ek1, ek2);
-  do_check_neq(hk1, hk2);
-
-  im.account = null;
-
-  run_next_test();
-});
-
-add_test(function test_current_auth_state() {
-  _("Ensure current auth state is reported properly.");
-
-  let im = new IdentityManager();
-  do_check_eq(im.currentAuthState, LOGIN_FAILED_NO_USERNAME);
-
-  im.account = "johndoe";
-  do_check_eq(im.currentAuthState, LOGIN_FAILED_NO_PASSWORD);
-
-  im.basicPassword = "ilovejane";
-  do_check_eq(im.currentAuthState, LOGIN_FAILED_NO_PASSPHRASE);
-
-  im.syncKey = "foobar";
-  do_check_eq(im.currentAuthState, LOGIN_FAILED_INVALID_PASSPHRASE);
-
-  im.syncKey = null;
-  do_check_eq(im.currentAuthState, LOGIN_FAILED_NO_PASSPHRASE);
-
-  im.syncKey = Utils.generatePassphrase();
-  do_check_eq(im.currentAuthState, STATUS_OK);
-
-  im.account = null;
-
-  run_next_test();
-});
-
-add_test(function test_sync_key_persistence() {
-  _("Ensure Sync Key persistence works as expected.");
-
-  identity.account = "pseudojohn";
-  identity.password = "supersecret";
-
-  let syncKey = Utils.generatePassphrase();
-  identity.syncKey = syncKey;
-
-  identity.persistCredentials();
-
-  let im = new IdentityManager();
-  im.account = "pseudojohn";
-  do_check_eq(im.syncKey, syncKey);
-  do_check_neq(im.syncKeyBundle, null);
-
-  let kb1 = identity.syncKeyBundle;
-  let kb2 = im.syncKeyBundle;
-
-  do_check_eq(kb1.encryptionKeyB64, kb2.encryptionKeyB64);
-  do_check_eq(kb1.hmacKeyB64, kb2.hmacKeyB64);
-
-  identity.account = null;
-  identity.persistCredentials();
-
-  let im2 = new IdentityManager();
-  im2.account = "pseudojohn";
-  do_check_eq(im2.syncKey, null);
-
-  im2.account = null;
-
-  _("Ensure deleted but not persisted value is retrieved.");
-  identity.account = "someoneelse";
-  identity.syncKey = Utils.generatePassphrase();
-  identity.persistCredentials();
-  identity.syncKey = null;
-  do_check_eq(identity.syncKey, null);
-
-  // Clean up.
-  identity.account = null;
-  identity.persistCredentials();
-
-  run_next_test();
-});
--- a/services/sync/tests/unit/test_load_modules.js
+++ b/services/sync/tests/unit/test_load_modules.js
@@ -11,25 +11,23 @@ const modules = [
   "engines/clients.js",
   "engines/extension-storage.js",
   "engines/forms.js",
   "engines/history.js",
   "engines/passwords.js",
   "engines/prefs.js",
   "engines/tabs.js",
   "engines.js",
-  "identity.js",
   "keys.js",
   "main.js",
   "policies.js",
   "record.js",
   "resource.js",
   "rest.js",
   "service.js",
-  "stages/cluster.js",
   "stages/declined.js",
   "stages/enginesync.js",
   "status.js",
   "util.js",
 ];
 
 const testingModules = [
   "fakeservices.js",
--- a/services/sync/tests/unit/xpcshell.ini
+++ b/services/sync/tests/unit/xpcshell.ini
@@ -49,17 +49,16 @@ tags = addons
 [test_resource_ua.js]
 [test_syncstoragerequest.js]
 
 # Generic Sync types.
 [test_browserid_identity.js]
 [test_collection_inc_get.js]
 [test_collection_getBatched.js]
 [test_collections_recovery.js]
-[test_identity_manager.js]
 [test_keys.js]
 [test_records_crypto.js]
 [test_records_wbo.js]
 
 # Engine APIs.
 [test_engine.js]
 [test_engine_abort.js]
 [test_enginemanager.js]
--- a/tools/lint/eslint/modules.json
+++ b/tools/lint/eslint/modules.json
@@ -30,17 +30,16 @@
   "clients.js": ["ClientEngine", "ClientsRec"],
   "CloudSyncAdapters.jsm": ["Adapters"],
   "CloudSyncBookmarks.jsm": ["Bookmarks"],
   "CloudSyncBookmarksFolderCache.jsm": ["FolderCache"],
   "CloudSyncEventSource.jsm": ["EventSource"],
   "CloudSyncLocal.jsm": ["Local"],
   "CloudSyncPlacesWrapper.jsm": ["PlacesWrapper"],
   "CloudSyncTabs.jsm": ["Tabs"],
-  "cluster.js": ["ClusterManager"],
   "collection_validator.js": ["CollectionValidator", "CollectionProblemData"],
   "Console.jsm": ["console", "ConsoleAPI"],
   "Constants.jsm": ["Roles", "Events", "Relations", "Filters", "States", "Prefilters"],
   "ContactDB.jsm": ["ContactDB", "DB_NAME", "STORE_NAME", "SAVED_GETALL_STORE_NAME", "REVISION_STORE", "DB_VERSION"],
   "content-server.jsm": ["init"],
   "content.jsm": ["registerContentFrame"],
   "ContentCrashHandlers.jsm": ["TabCrashHandler", "PluginCrashReporter", "UnsubmittedCrashHandler"],
   "ContentObservers.jsm": [],
@@ -100,17 +99,16 @@
   "GMPUtils.jsm": ["GMP_PLUGIN_IDS", "GMPPrefs", "GMPUtils", "OPEN_H264_ID", "WIDEVINE_ID"],
   "hawkclient.js": ["HawkClient"],
   "hawkrequest.js": ["HAWKAuthenticatedRESTRequest", "deriveHawkCredentials"],
   "HelperApps.jsm": ["App", "HelperApps"],
   "history.js": ["HistoryEngine", "HistoryRec"],
   "history.jsm": ["HistoryEntry", "DumpHistory"],
   "Http.jsm": ["httpRequest", "percentEncode"],
   "httpd.js": ["HTTP_400", "HTTP_401", "HTTP_402", "HTTP_403", "HTTP_404", "HTTP_405", "HTTP_406", "HTTP_407", "HTTP_408", "HTTP_409", "HTTP_410", "HTTP_411", "HTTP_412", "HTTP_413", "HTTP_414", "HTTP_415", "HTTP_417", "HTTP_500", "HTTP_501", "HTTP_502", "HTTP_503", "HTTP_504", "HTTP_505", "HttpError", "HttpServer"],
-  "identity.js": ["IdentityManager"],
   "import_module.jsm": ["MODULE_IMPORTED", "MODULE_URI", "SUBMODULE_IMPORTED", "same_scope", "SUBMODULE_IMPORTED_TO_SCOPE"],
   "import_sub_module.jsm": ["SUBMODULE_IMPORTED", "test_obj"],
   "InlineSpellChecker.jsm": ["InlineSpellChecker", "SpellCheckHelper"],
   "JNI.jsm": ["JNI", "android_log"],
   "Jsbeautify.jsm": ["jsBeautify"],
   "jsdebugger.jsm": ["addDebuggerToGlobal"],
   "json2.js": ["JSON"],
   "keys.js": ["BulkKeyBundle", "SyncKeyBundle"],