Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Fix race in Registration between server change and flows fetch (#8359)
Browse files Browse the repository at this point in the history
  • Loading branch information
t3chguy authored Apr 20, 2022
1 parent 6e86a14 commit b4bcbb2
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 18 deletions.
39 changes: 22 additions & 17 deletions src/components/structures/auth/Registration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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"),
Expand All @@ -178,7 +182,6 @@ export default class Registration extends React.Component<IProps, IState> {
}
}

const { hsUrl, isUrl } = serverConfig;
const cli = createClient({
baseUrl: hsUrl,
idBaseUrl: isUrl,
Expand All @@ -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);
}

Expand All @@ -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,
Expand All @@ -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,
});
};
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down

0 comments on commit b4bcbb2

Please sign in to comment.