mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-30 04:17:31 +09:00
Import Tycho weave client
This commit is contained in:
parent
e4ac0e17f8
commit
c53787dfdb
183 changed files with 7272 additions and 16759 deletions
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["BrowserIDManager", "AuthenticationError"];
|
||||
this.EXPORTED_SYMBOLS = ["BrowserIDManager"];
|
||||
|
||||
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/async.js");
|
||||
|
|
@ -39,13 +39,12 @@ XPCOMUtils.defineLazyGetter(this, 'log', function() {
|
|||
});
|
||||
|
||||
// FxAccountsCommon.js doesn't use a "namespace", so create one here.
|
||||
var fxAccountsCommon = {};
|
||||
let fxAccountsCommon = {};
|
||||
Cu.import("resource://gre/modules/FxAccountsCommon.js", fxAccountsCommon);
|
||||
|
||||
const OBSERVER_TOPICS = [
|
||||
fxAccountsCommon.ONLOGIN_NOTIFICATION,
|
||||
fxAccountsCommon.ONLOGOUT_NOTIFICATION,
|
||||
fxAccountsCommon.ON_ACCOUNT_STATE_CHANGE_NOTIFICATION,
|
||||
];
|
||||
|
||||
const PREF_SYNC_SHOW_CUSTOMIZATION = "services.sync-setup.ui.showCustomizationDialog";
|
||||
|
|
@ -66,9 +65,8 @@ function deriveKeyBundle(kB) {
|
|||
some other error object (which should do the right thing when toString() is
|
||||
called on it)
|
||||
*/
|
||||
function AuthenticationError(details, source) {
|
||||
function AuthenticationError(details) {
|
||||
this.details = details;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
AuthenticationError.prototype = {
|
||||
|
|
@ -106,6 +104,12 @@ this.BrowserIDManager.prototype = {
|
|||
// we don't consider the lack of a keybundle as a failure state.
|
||||
_shouldHaveSyncKeyBundle: false,
|
||||
|
||||
get readyToAuthenticate() {
|
||||
// We are finished initializing when we *should* have a sync key bundle,
|
||||
// although we might not actually have one due to auth failures etc.
|
||||
return this._shouldHaveSyncKeyBundle;
|
||||
},
|
||||
|
||||
get needsCustomization() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref(PREF_SYNC_SHOW_CUSTOMIZATION);
|
||||
|
|
@ -114,34 +118,11 @@ this.BrowserIDManager.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
hashedUID() {
|
||||
if (!this._token) {
|
||||
throw new Error("hashedUID: Don't have token");
|
||||
}
|
||||
return this._token.hashed_fxa_uid
|
||||
},
|
||||
|
||||
deviceID() {
|
||||
return this._signedInUser && this._signedInUser.deviceId;
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
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.
|
||||
});
|
||||
return this.initializeWithCurrentIdentity();
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -149,7 +130,7 @@ this.BrowserIDManager.prototype = {
|
|||
* the user is logged in, or is rejected if the login attempt has failed.
|
||||
*/
|
||||
ensureLoggedIn: function() {
|
||||
if (!this._shouldHaveSyncKeyBundle && this.whenReadyToAuthenticate) {
|
||||
if (!this._shouldHaveSyncKeyBundle) {
|
||||
// We are already in the process of logging in.
|
||||
return this.whenReadyToAuthenticate.promise;
|
||||
}
|
||||
|
|
@ -163,7 +144,7 @@ this.BrowserIDManager.prototype = {
|
|||
// re-entering of credentials by the user is necessary we don't take any
|
||||
// further action - an observer will fire when the user does that.
|
||||
if (Weave.Status.login == LOGIN_FAILED_LOGIN_REJECTED) {
|
||||
return Promise.reject(new Error("User needs to re-authenticate"));
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
// So - we've a previous auth problem and aren't currently attempting to
|
||||
|
|
@ -179,6 +160,7 @@ this.BrowserIDManager.prototype = {
|
|||
}
|
||||
this.resetCredentials();
|
||||
this._signedInUser = null;
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
offerSyncOptions: function () {
|
||||
|
|
@ -202,7 +184,7 @@ this.BrowserIDManager.prototype = {
|
|||
|
||||
// Reset the world before we do anything async.
|
||||
this.whenReadyToAuthenticate = Promise.defer();
|
||||
this.whenReadyToAuthenticate.promise.catch(err => {
|
||||
this.whenReadyToAuthenticate.promise.then(null, (err) => {
|
||||
this._log.error("Could not authenticate", err);
|
||||
});
|
||||
|
||||
|
|
@ -258,14 +240,14 @@ this.BrowserIDManager.prototype = {
|
|||
Services.obs.notifyObservers(null, "weave:service:setup-complete", null);
|
||||
Weave.Utils.nextTick(Weave.Service.sync, Weave.Service);
|
||||
}
|
||||
}).catch(authErr => {
|
||||
// report what failed...
|
||||
this._log.error("Background fetch for key bundle failed", authErr);
|
||||
}).then(null, err => {
|
||||
this._shouldHaveSyncKeyBundle = true; // but we probably don't have one...
|
||||
this.whenReadyToAuthenticate.reject(authErr);
|
||||
this.whenReadyToAuthenticate.reject(err);
|
||||
// report what failed...
|
||||
this._log.error("Background fetch for key bundle failed", err);
|
||||
});
|
||||
// and we are done - the fetch continues on in the background...
|
||||
}).catch(err => {
|
||||
}).then(null, err => {
|
||||
this._log.error("Processing logged in account", err);
|
||||
});
|
||||
},
|
||||
|
|
@ -301,8 +283,7 @@ this.BrowserIDManager.prototype = {
|
|||
// reauth with the server - in that case we will also get here, but
|
||||
// should have the same identity.
|
||||
// initializeWithCurrentIdentity will throw and log if these constraints
|
||||
// aren't met (indirectly, via _updateSignedInUser()), so just go ahead
|
||||
// and do the init.
|
||||
// aren't met, so just go ahead and do the init.
|
||||
this.initializeWithCurrentIdentity(true);
|
||||
break;
|
||||
|
||||
|
|
@ -311,13 +292,6 @@ this.BrowserIDManager.prototype = {
|
|||
// startOver will cause this instance to be thrown away, so there's
|
||||
// nothing else to do.
|
||||
break;
|
||||
|
||||
case fxAccountsCommon.ON_ACCOUNT_STATE_CHANGE_NOTIFICATION:
|
||||
// throw away token and fetch a new one
|
||||
this.resetCredentials();
|
||||
this._ensureValidToken().catch(err =>
|
||||
this._log.error("Error while fetching a new token", err));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -413,9 +387,6 @@ this.BrowserIDManager.prototype = {
|
|||
resetCredentials: function() {
|
||||
this.resetSyncKey();
|
||||
this._token = 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;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -503,12 +474,7 @@ this.BrowserIDManager.prototype = {
|
|||
// If we still can't get keys it probably means the user authenticated
|
||||
// without unlocking the MP or cleared the saved logins, so we've now
|
||||
// lost them - the user will need to reauth before continuing.
|
||||
let result;
|
||||
if (this._canFetchKeys()) {
|
||||
result = STATUS_OK;
|
||||
} else {
|
||||
result = LOGIN_FAILED_LOGIN_REJECTED;
|
||||
}
|
||||
let result = this._canFetchKeys() ? STATUS_OK : LOGIN_FAILED_LOGIN_REJECTED;
|
||||
log.debug("unlockAndVerifyAuthState re-fetched credentials and is returning", result);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -540,27 +506,14 @@ this.BrowserIDManager.prototype = {
|
|||
return true;
|
||||
},
|
||||
|
||||
// Get our tokenServerURL - a private helper. Returns a string.
|
||||
get _tokenServerUrl() {
|
||||
// We used to support services.sync.tokenServerURI but this was a
|
||||
// pain-point for people using non-default servers as Sync may auto-reset
|
||||
// all services.sync prefs. So if that still exists, it wins.
|
||||
let url = Svc.Prefs.get("tokenServerURI"); // Svc.Prefs "root" is services.sync
|
||||
if (!url) {
|
||||
url = Services.prefs.getCharPref("identity.sync.tokenserver.uri");
|
||||
}
|
||||
while (url.endsWith("/")) { // trailing slashes cause problems...
|
||||
url = url.slice(0, -1);
|
||||
}
|
||||
return url;
|
||||
},
|
||||
|
||||
// Refresh the sync token for our user. Returns a promise that resolves
|
||||
// with a token (which may be null in one sad edge-case), or rejects with an
|
||||
// error.
|
||||
_fetchTokenForUser: function() {
|
||||
// tokenServerURI is mis-named - convention is uri means nsISomething...
|
||||
let tokenServerURI = this._tokenServerUrl;
|
||||
let tokenServerURI = Svc.Prefs.get("tokenServerURI");
|
||||
if (tokenServerURI.endsWith("/")) { // trailing slashes cause problems...
|
||||
tokenServerURI = tokenServerURI.slice(0, -1);
|
||||
}
|
||||
let log = this._log;
|
||||
let client = this._tokenServerClient;
|
||||
let fxa = this._fxaService;
|
||||
|
|
@ -589,7 +542,7 @@ this.BrowserIDManager.prototype = {
|
|||
);
|
||||
}
|
||||
|
||||
let getToken = assertion => {
|
||||
let getToken = (tokenServerURI, assertion) => {
|
||||
log.debug("Getting a token");
|
||||
let deferred = Promise.defer();
|
||||
let cb = function (err, token) {
|
||||
|
|
@ -617,18 +570,7 @@ this.BrowserIDManager.prototype = {
|
|||
return fxa.whenVerified(this._signedInUser)
|
||||
.then(() => maybeFetchKeys())
|
||||
.then(() => getAssertion())
|
||||
.then(assertion => getToken(assertion))
|
||||
.catch(err => {
|
||||
// If we get a 401 fetching the token it may be that our certificate
|
||||
// needs to be regenerated.
|
||||
if (!err.response || err.response.status !== 401) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
log.warn("Token server returned 401, refreshing certificate and retrying token fetch");
|
||||
return fxa.invalidateCertificate()
|
||||
.then(() => getAssertion())
|
||||
.then(assertion => getToken(assertion))
|
||||
})
|
||||
.then(assertion => getToken(tokenServerURI, assertion))
|
||||
.then(token => {
|
||||
// TODO: Make it be only 80% of the duration, so refresh the token
|
||||
// before it actually expires. This is to avoid sync storage errors
|
||||
|
|
@ -640,18 +582,15 @@ this.BrowserIDManager.prototype = {
|
|||
}
|
||||
return token;
|
||||
})
|
||||
.catch(err => {
|
||||
.then(null, err => {
|
||||
// TODO: unify these errors - we need to handle errors thrown by
|
||||
// both tokenserverclient and hawkclient.
|
||||
// A tokenserver error thrown based on a bad response.
|
||||
if (err.response && err.response.status === 401) {
|
||||
err = new AuthenticationError(err, "tokenserver");
|
||||
err = new AuthenticationError(err);
|
||||
// A hawkclient error.
|
||||
} else if (err.code && err.code === 401) {
|
||||
err = new AuthenticationError(err, "hawkclient");
|
||||
// An FxAccounts.jsm error.
|
||||
} else if (err.message == fxAccountsCommon.ERROR_AUTH_ERROR) {
|
||||
err = new AuthenticationError(err, "fxaccounts");
|
||||
err = new AuthenticationError(err);
|
||||
}
|
||||
|
||||
// TODO: write tests to make sure that different auth error cases are handled here
|
||||
|
|
@ -673,6 +612,7 @@ this.BrowserIDManager.prototype = {
|
|||
// that there is no authentication dance still under way.
|
||||
this._shouldHaveSyncKeyBundle = true;
|
||||
Weave.Status.login = this._authFailureReason;
|
||||
Services.obs.notifyObservers(null, "weave:ui:login:error", null);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
|
|
@ -684,19 +624,12 @@ this.BrowserIDManager.prototype = {
|
|||
this._log.debug("_ensureValidToken already has one");
|
||||
return Promise.resolve();
|
||||
}
|
||||
const notifyStateChanged =
|
||||
() => Services.obs.notifyObservers(null, "weave:service:login:change", null);
|
||||
// reset this._token as a safety net to reduce the possibility of us
|
||||
// repeatedly attempting to use an invalid token if _fetchTokenForUser throws.
|
||||
this._token = null;
|
||||
return this._fetchTokenForUser().then(
|
||||
token => {
|
||||
this._token = token;
|
||||
notifyStateChanged();
|
||||
},
|
||||
error => {
|
||||
notifyStateChanged();
|
||||
throw error
|
||||
}
|
||||
);
|
||||
},
|
||||
|
|
@ -719,16 +652,9 @@ this.BrowserIDManager.prototype = {
|
|||
_getAuthenticationHeader: function(httpObject, method) {
|
||||
let cb = Async.makeSpinningCallback();
|
||||
this._ensureValidToken().then(cb, cb);
|
||||
// Note that in failure states we return null, causing the request to be
|
||||
// made without authorization headers, thereby presumably causing a 401,
|
||||
// which causes Sync to log out. If we throw, this may not happen as
|
||||
// expected.
|
||||
try {
|
||||
cb.wait();
|
||||
} catch (ex) {
|
||||
if (Async.isShutdownException(ex)) {
|
||||
throw ex;
|
||||
}
|
||||
this._log.error("Failed to fetch a token for authentication", ex);
|
||||
return null;
|
||||
}
|
||||
|
|
@ -764,17 +690,8 @@ this.BrowserIDManager.prototype = {
|
|||
|
||||
createClusterManager: function(service) {
|
||||
return new BrowserIDClusterManager(service);
|
||||
},
|
||||
}
|
||||
|
||||
// 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 almost certainly means a transient error fetching a token
|
||||
// (and hitting this will cause us to logout, which will correctly handle an
|
||||
// authoritative login issue.)
|
||||
loginStatusFromVerification404() {
|
||||
return LOGIN_FAILED_NETWORK_ERROR;
|
||||
},
|
||||
};
|
||||
|
||||
/* An implementation of the ClusterManager for this identity
|
||||
|
|
@ -820,7 +737,7 @@ BrowserIDClusterManager.prototype = {
|
|||
// it's likely a 401 was received using the existing token - in which
|
||||
// case we just discard the existing token and fetch a new one.
|
||||
if (this.service.clusterURL) {
|
||||
log.debug("_findCluster has a pre-existing clusterURL, so discarding the current token");
|
||||
log.debug("_findCluster found existing clusterURL, so discarding the current token");
|
||||
this.identity._token = null;
|
||||
}
|
||||
return this.identity._ensureValidToken();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue