Fix race in Registration between server change and flows fetch (#8359)

This commit is contained in:
Michael Telatynski 2022-04-20 19:04:42 +01:00 committed by GitHub
parent 6e86a14cc9
commit b4bcbb2f30
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 18 deletions

View file

@ -110,7 +110,9 @@ interface IState {
}
export default class Registration extends React.Component<IProps, IState> {
loginLogic: Login;
private readonly loginLogic: Login;
// `replaceClient` tracks latest serverConfig to spot when it changes under the async method which fetches flows
private latestServerConfig: ValidatedServerConfig;
constructor(props) {
super(props);
@ -149,26 +151,28 @@ export default class Registration extends React.Component<IProps, IState> {
}
private async replaceClient(serverConfig: ValidatedServerConfig) {
this.latestServerConfig = serverConfig;
const { hsUrl, isUrl } = serverConfig;
this.setState({
errorText: null,
serverDeadError: null,
serverErrorIsFatal: false,
// busy while we do liveness check (we need to avoid trying to render
// busy while we do live-ness check (we need to avoid trying to render
// the UI auth component while we don't have a matrix client)
busy: true,
});
// Do a liveliness check on the URLs
try {
await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(
serverConfig.hsUrl,
serverConfig.isUrl,
);
await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(hsUrl, isUrl);
if (serverConfig !== this.latestServerConfig) return; // discard, serverConfig changed from under us
this.setState({
serverIsAlive: true,
serverErrorIsFatal: false,
});
} catch (e) {
if (serverConfig !== this.latestServerConfig) return; // discard, serverConfig changed from under us
this.setState({
busy: false,
...AutoDiscoveryUtils.authComponentStateForError(e, "register"),
@ -178,7 +182,6 @@ export default class Registration extends React.Component<IProps, IState> {
}
}
const { hsUrl, isUrl } = serverConfig;
const cli = createClient({
baseUrl: hsUrl,
idBaseUrl: isUrl,
@ -190,8 +193,10 @@ export default class Registration extends React.Component<IProps, IState> {
let ssoFlow: ISSOFlow;
try {
const loginFlows = await this.loginLogic.getFlows();
if (serverConfig !== this.latestServerConfig) return; // discard, serverConfig changed from under us
ssoFlow = loginFlows.find(f => f.type === "m.login.sso" || f.type === "m.login.cas") as ISSOFlow;
} catch (e) {
if (serverConfig !== this.latestServerConfig) return; // discard, serverConfig changed from under us
logger.error("Failed to get login flows to check for SSO support", e);
}
@ -200,23 +205,19 @@ export default class Registration extends React.Component<IProps, IState> {
ssoFlow,
busy: false,
});
const showGenericError = (e) => {
this.setState({
errorText: _t("Unable to query for supported registration methods."),
// add empty flows array to get rid of spinner
flows: [],
});
};
try {
// We do the first registration request ourselves to discover whether we need to
// do SSO instead. If we've already started the UI Auth process though, we don't
// need to.
if (!this.state.doingUIAuth) {
await this.makeRegisterRequest(null);
if (serverConfig !== this.latestServerConfig) return; // discard, serverConfig changed from under us
// This should never succeed since we specified no auth object.
logger.log("Expecting 401 from register request but got success!");
}
} catch (e) {
if (serverConfig !== this.latestServerConfig) return; // discard, serverConfig changed from under us
if (e.httpStatus === 401) {
this.setState({
flows: e.data.flows,
@ -239,16 +240,20 @@ export default class Registration extends React.Component<IProps, IState> {
}
} else {
logger.log("Unable to query for supported registration methods.", e);
showGenericError(e);
this.setState({
errorText: _t("Unable to query for supported registration methods."),
// add empty flows array to get rid of spinner
flows: [],
});
}
}
}
private onFormSubmit = async (formVals): Promise<void> => {
private onFormSubmit = async (formVals: Record<string, string>): Promise<void> => {
this.setState({
errorText: "",
busy: true,
formVals: formVals,
formVals,
doingUIAuth: true,
});
};

View file

@ -3209,8 +3209,8 @@
"Signing In...": "Signing In...",
"If you've joined lots of rooms, this might take a while": "If you've joined lots of rooms, this might take a while",
"New? <a>Create account</a>": "New? <a>Create account</a>",
"Unable to query for supported registration methods.": "Unable to query for supported registration methods.",
"Registration has been disabled on this homeserver.": "Registration has been disabled on this homeserver.",
"Unable to query for supported registration methods.": "Unable to query for supported registration methods.",
"This server does not support authentication with a phone number.": "This server does not support authentication with a phone number.",
"Someone already has that username, please try another.": "Someone already has that username, please try another.",
"That e-mail address is already in use.": "That e-mail address is already in use.",