1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-29 16:43:09 +03:00

Don't overlap auth submissions with polls

Wait for polls to complete before submitting auth dicts, otherwise
we risk the requests overlapping and both returning a 200.

Also introduces a setBusy interface to interactive-auth to explicitly
set the busy status, since otherwise it doesn't get set until the
request actually starts.
This commit is contained in:
David Baker
2019-06-10 15:18:46 +01:00
parent 7080458f7e
commit 654e8b41fa

View File

@@ -55,6 +55,12 @@ const MSISDN_STAGE_TYPE = "m.login.msisdn";
* promise which resolves to the successful response or rejects with a
* MatrixError.
*
* @param {function(bool): module:client.Promise} opts.setBusy
* called whenever the interactive auth logic is busy submitting
* information provided by the user. After this has been called with
* true the UI should indicate that a request is in progress until it
* is called again with false.
*
* @param {function(string, object?)} opts.stateUpdated
* called when the status of the UI auth changes, ie. when the state of
* an auth stage changes of when the auth flow moves to a new stage.
@@ -101,6 +107,7 @@ function InteractiveAuth(opts) {
this._matrixClient = opts.matrixClient;
this._data = opts.authData || {};
this._requestCallback = opts.doRequest;
this._setBusyCallback = opts.setBusy;
// startAuthStage included for backwards compat
this._stateUpdatedCallback = opts.stateUpdated || opts.startAuthStage;
this._resolveFunc = null;
@@ -117,7 +124,9 @@ function InteractiveAuth(opts) {
this._chosenFlow = null;
this._currentStage = null;
this._polling = false;
// if we are currently trying to submit an auth dict (which includes polling)
// the promise the will resolve/reject when it completes
this._submitPromise = false;
}
InteractiveAuth.prototype = {
@@ -138,7 +147,10 @@ InteractiveAuth.prototype = {
// if we have no flows, try a request (we'll have
// just a session ID in _data if resuming)
if (!this._data.flows) {
this._doRequest(this._data);
this._setBusyCallback(true);
this._doRequest(this._data).finally(() => {
this._setBusyCallback(false);
});
} else {
this._startNextAuthStage();
}
@@ -152,7 +164,9 @@ InteractiveAuth.prototype = {
*/
poll: async function() {
if (!this._data.session) return;
if (this._polling) return;
// if we currently have a request in flight, there's no point making
// another just to check what the status is
if (this._submitPromise) return;
let authDict = {};
if (this._currentStage == EMAIL_STAGE_TYPE) {
@@ -173,12 +187,7 @@ InteractiveAuth.prototype = {
}
}
this._polling = true;
try {
await this.submitAuthDict(authDict, true);
} finally {
this._polling = false;
}
this.submitAuthDict(authDict, true);
},
/**
@@ -235,13 +244,37 @@ InteractiveAuth.prototype = {
throw new Error("submitAuthDict() called before attemptAuth()");
}
if (!background && this._setBusyCallback) {
this._setBusyCallback(true);
}
// if we're currently trying a request, wait for it to finish
// as otherwise we can get multiple 200 responses which can mean
// things like multiple logins for register requests.
// (but discard any expections as we only care when its done,
// not whether it worked or not)
while (this._submitPromise) {
try {
await this._submitPromise;
} catch (e) {
}
}
// use the sessionid from the last request.
const auth = {
session: this._data.session,
};
utils.extend(auth, authData);
await this._doRequest(auth, background);
try {
// NB. the 'background' flag is deprecated by the setBusy
// callback and is here for backwards compat
this._submitPromise = this._doRequest(auth, background);
await this._submitPromise;
} finally {
this._submitPromise = null;
if (!background) this._setBusyCallback(false);
}
},
/**