You've already forked matrix-js-sdk
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:
@@ -55,6 +55,12 @@ const MSISDN_STAGE_TYPE = "m.login.msisdn";
|
|||||||
* promise which resolves to the successful response or rejects with a
|
* promise which resolves to the successful response or rejects with a
|
||||||
* MatrixError.
|
* 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
|
* @param {function(string, object?)} opts.stateUpdated
|
||||||
* called when the status of the UI auth changes, ie. when the state of
|
* 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.
|
* 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._matrixClient = opts.matrixClient;
|
||||||
this._data = opts.authData || {};
|
this._data = opts.authData || {};
|
||||||
this._requestCallback = opts.doRequest;
|
this._requestCallback = opts.doRequest;
|
||||||
|
this._setBusyCallback = opts.setBusy;
|
||||||
// startAuthStage included for backwards compat
|
// startAuthStage included for backwards compat
|
||||||
this._stateUpdatedCallback = opts.stateUpdated || opts.startAuthStage;
|
this._stateUpdatedCallback = opts.stateUpdated || opts.startAuthStage;
|
||||||
this._resolveFunc = null;
|
this._resolveFunc = null;
|
||||||
@@ -117,7 +124,9 @@ function InteractiveAuth(opts) {
|
|||||||
this._chosenFlow = null;
|
this._chosenFlow = null;
|
||||||
this._currentStage = 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 = {
|
InteractiveAuth.prototype = {
|
||||||
@@ -138,7 +147,10 @@ InteractiveAuth.prototype = {
|
|||||||
// if we have no flows, try a request (we'll have
|
// if we have no flows, try a request (we'll have
|
||||||
// just a session ID in _data if resuming)
|
// just a session ID in _data if resuming)
|
||||||
if (!this._data.flows) {
|
if (!this._data.flows) {
|
||||||
this._doRequest(this._data);
|
this._setBusyCallback(true);
|
||||||
|
this._doRequest(this._data).finally(() => {
|
||||||
|
this._setBusyCallback(false);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this._startNextAuthStage();
|
this._startNextAuthStage();
|
||||||
}
|
}
|
||||||
@@ -152,7 +164,9 @@ InteractiveAuth.prototype = {
|
|||||||
*/
|
*/
|
||||||
poll: async function() {
|
poll: async function() {
|
||||||
if (!this._data.session) return;
|
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 = {};
|
let authDict = {};
|
||||||
if (this._currentStage == EMAIL_STAGE_TYPE) {
|
if (this._currentStage == EMAIL_STAGE_TYPE) {
|
||||||
@@ -173,12 +187,7 @@ InteractiveAuth.prototype = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._polling = true;
|
this.submitAuthDict(authDict, true);
|
||||||
try {
|
|
||||||
await this.submitAuthDict(authDict, true);
|
|
||||||
} finally {
|
|
||||||
this._polling = false;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -235,13 +244,37 @@ InteractiveAuth.prototype = {
|
|||||||
throw new Error("submitAuthDict() called before attemptAuth()");
|
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.
|
// use the sessionid from the last request.
|
||||||
const auth = {
|
const auth = {
|
||||||
session: this._data.session,
|
session: this._data.session,
|
||||||
};
|
};
|
||||||
utils.extend(auth, authData);
|
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);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user