mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1296767 part 3 - Make BrowserID the only Sync identity manager. r=markh
MozReview-Commit-ID: IC7kRjgtPp8 --HG-- extra : rebase_source : ec10c24400afa4b1c1fd3840f31a9d57d498ec8a
This commit is contained in:
parent
eb0c42bf7a
commit
49552f7919
@ -374,9 +374,10 @@ var gSyncUI = {
|
||||
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();
|
||||
|
@ -220,7 +220,6 @@ var gSyncSetup = {
|
||||
feedback = server;
|
||||
break;
|
||||
case Weave.LOGIN_FAILED_LOGIN_REJECTED:
|
||||
case Weave.LOGIN_FAILED_NO_USERNAME:
|
||||
case Weave.LOGIN_FAILED_NO_PASSWORD:
|
||||
feedback = password;
|
||||
break;
|
||||
|
@ -102,22 +102,16 @@ WeaveService.prototype = {
|
||||
*
|
||||
* @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().
|
||||
@ -142,10 +136,9 @@ WeaveService.prototype = {
|
||||
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.
|
||||
|
@ -27,7 +27,6 @@ this.EXPORTED_SYMBOLS = [
|
||||
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");
|
||||
@ -170,11 +169,6 @@ this.makeIdentityConfig = function(overrides) {
|
||||
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",
|
||||
}
|
||||
};
|
||||
|
||||
@ -183,10 +177,6 @@ this.makeIdentityConfig = function(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;
|
||||
@ -260,44 +250,30 @@ this.configureIdentity = async function(identityOverrides, 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(),
|
||||
@ -323,9 +299,9 @@ this.encryptPayload = function encryptPayload(cleartext) {
|
||||
}
|
||||
|
||||
// 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|.
|
||||
@ -339,15 +315,6 @@ this.add_identity_test = function(test, testFunction) {
|
||||
}
|
||||
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;
|
||||
|
@ -13,13 +13,11 @@ 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.
|
||||
@ -89,8 +87,6 @@ this.BrowserIDManager = function BrowserIDManager() {
|
||||
};
|
||||
|
||||
this.BrowserIDManager.prototype = {
|
||||
__proto__: IdentityManager.prototype,
|
||||
|
||||
_fxaService: null,
|
||||
_tokenServerClient: null,
|
||||
// https://docs.services.mozilla.com/token/apis.html
|
||||
@ -138,19 +134,6 @@ this.BrowserIDManager.prototype = {
|
||||
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.
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@ -225,14 +208,13 @@ this.BrowserIDManager.prototype = {
|
||||
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
|
||||
@ -365,65 +347,43 @@ this.BrowserIDManager.prototype = {
|
||||
return this._fxaService.localtimeOffsetMsec;
|
||||
},
|
||||
|
||||
usernameFromAccount(val) {
|
||||
// we don't differentiate between "username" and "account"
|
||||
return val;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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");
|
||||
},
|
||||
|
||||
/**
|
||||
* 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.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";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
set syncKey(value) {
|
||||
throw "syncKey setter should be not used in BrowserIDManager";
|
||||
},
|
||||
|
||||
get syncKeyBundle() {
|
||||
return this._syncKeyBundle;
|
||||
},
|
||||
|
||||
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.resetSyncKey();
|
||||
this.resetSyncKeyBundle();
|
||||
this._token = null;
|
||||
this._hashedUID = null;
|
||||
// The cluster URL comes from the token, so resetting it to empty will
|
||||
@ -432,12 +392,10 @@ this.BrowserIDManager.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* 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;
|
||||
},
|
||||
|
||||
@ -458,6 +416,18 @@ this.BrowserIDManager.prototype = {
|
||||
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.
|
||||
*
|
||||
@ -472,6 +442,7 @@ this.BrowserIDManager.prototype = {
|
||||
" 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.
|
||||
@ -801,11 +772,39 @@ this.BrowserIDManager.prototype = {
|
||||
*/
|
||||
|
||||
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() {
|
||||
|
@ -19,7 +19,6 @@ 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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
@ -35,8 +35,7 @@ this.SyncScheduler = function SyncScheduler(service) {
|
||||
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],
|
||||
|
||||
@ -48,14 +47,7 @@ SyncScheduler.prototype = {
|
||||
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");
|
||||
|
@ -21,10 +21,10 @@ 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");
|
||||
@ -154,7 +154,7 @@ Sync11Service.prototype = {
|
||||
|
||||
_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.
|
||||
@ -303,14 +303,6 @@ Sync11Service.prototype = {
|
||||
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();
|
||||
@ -549,21 +541,9 @@ Sync11Service.prototype = {
|
||||
|
||||
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;
|
||||
}
|
||||
@ -699,7 +679,7 @@ Sync11Service.prototype = {
|
||||
// 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;
|
||||
@ -807,30 +787,6 @@ Sync11Service.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
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");
|
||||
@ -855,7 +811,7 @@ Sync11Service.prototype = {
|
||||
// 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");
|
||||
@ -891,7 +847,6 @@ Sync11Service.prototype = {
|
||||
// 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);
|
||||
@ -904,15 +859,7 @@ Sync11Service.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
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) {
|
||||
@ -920,17 +867,6 @@ Sync11Service.prototype = {
|
||||
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.";
|
||||
}
|
||||
@ -946,12 +882,6 @@ Sync11Service.prototype = {
|
||||
// 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.");
|
||||
@ -1125,11 +1055,6 @@ Sync11Service.prototype = {
|
||||
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;
|
||||
@ -1144,11 +1069,6 @@ Sync11Service.prototype = {
|
||||
|
||||
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;
|
||||
@ -1373,53 +1293,10 @@ Sync11Service.prototype = {
|
||||
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();
|
||||
@ -1528,9 +1405,6 @@ Sync11Service.prototype = {
|
||||
engine.wipeClient();
|
||||
}
|
||||
}
|
||||
|
||||
// Save the password/passphrase just in-case they aren't restored by sync
|
||||
this.persistLogin();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -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);
|
@ -11,7 +11,6 @@ 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");
|
||||
@ -25,11 +24,7 @@ this.Status = {
|
||||
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;
|
||||
},
|
||||
|
@ -24,7 +24,6 @@ EXTRA_JS_MODULES['services-sync'] += [
|
||||
'modules/collection_validator.js',
|
||||
'modules/engines.js',
|
||||
'modules/FxaMigrator.jsm',
|
||||
'modules/identity.js',
|
||||
'modules/keys.js',
|
||||
'modules/main.js',
|
||||
'modules/policies.js',
|
||||
@ -59,7 +58,6 @@ EXTRA_JS_MODULES['services-sync'].engines += [
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES['services-sync'].stages += [
|
||||
'modules/stages/cluster.js',
|
||||
'modules/stages/declined.js',
|
||||
'modules/stages/enginesync.js',
|
||||
]
|
||||
|
@ -19,7 +19,6 @@ 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
|
||||
|
||||
|
@ -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();
|
||||
});
|
@ -16,7 +16,6 @@ const modules = [
|
||||
"engines/prefs.js",
|
||||
"engines/tabs.js",
|
||||
"engines.js",
|
||||
"identity.js",
|
||||
"keys.js",
|
||||
"main.js",
|
||||
"policies.js",
|
||||
@ -24,7 +23,6 @@ const modules = [
|
||||
"resource.js",
|
||||
"rest.js",
|
||||
"service.js",
|
||||
"stages/cluster.js",
|
||||
"stages/declined.js",
|
||||
"stages/enginesync.js",
|
||||
"status.js",
|
||||
|
@ -54,7 +54,6 @@ tags = addons
|
||||
[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]
|
||||
|
@ -35,7 +35,6 @@
|
||||
"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"],
|
||||
@ -105,7 +104,6 @@
|
||||
"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"],
|
||||
|
Loading…
Reference in New Issue
Block a user