feat: URL navigation in auth (#1603)

* bump to react 18 and install react-router-dom

* Upgrade to react 18 root

* update vite

* add cs api's

* convert state/auth to ts

* add client config context

* add auto discovery context

* add spec version context

* add auth flow context

* add background dot pattern css

* add promise utils

* init url based routing

* update auth route server path as effect

* add auth server hook

* always use server from discovery info in context

* login - WIP

* upgrade jotai to v2

* add atom with localStorage util

* add multi account sessions atom

* add default IGNORE res to auto discovery

* add error type in async callback hook

* handle password login error

* fix async callback hook

* allow password login

* Show custom server not allowed error in mxId login

* add sso login component

* add token login

* fix hardcoded m.login.password in login func

* update server input on url change

* Improve sso login labels

* update folds

* fix async callback batching state update in safari

* wrap async callback set state in queueMicrotask

* wip

* wip - register

* arrange auth file structure

* add error codes

* extract filed error component form password login

* add register util function

* handle register flow - WIP

* update unsupported auth flow method reasons

* improve password input styles

* Improve UIA flow next stage calculation
complete stages can have any order so we will look for first stage which is not in completed

* process register UIA flow stages

* Extract register UIA stages component

* improve register error messages

* add focus trap & step count in UIA stages

* add reset password path and path utils

* add path with origin hook

* fix sso redirect url

* rename register token query param to token

* restyle auth screen header

* add reset password component - WIP

* add reset password form

* add netlify rewrites

* fix netlify file indentation

* test netlify redirect

* fix vite to include netlify toml

* add more netlify redirects

* add splat to public and assets path

* fix vite base name

* add option to use hash router in config and remove appVersion

* add splash screen component

* add client config loading and error screen

* fix server picker bug

* fix reset password email input type

* make auth page small screen responsive

* fix typo in reset password screen
This commit is contained in:
Ajay Bura 2024-01-21 23:50:56 +11:00 committed by GitHub
commit 20db27fa7e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
103 changed files with 4775 additions and 546 deletions

View file

@ -0,0 +1,125 @@
import to from 'await-to-js';
import {
IAuthData,
MatrixClient,
MatrixError,
RegisterRequest,
RegisterResponse,
} from 'matrix-js-sdk';
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { updateLocalStore } from '../../../../client/action/auth';
import { ROOT_PATH } from '../../paths';
import { ErrorCode } from '../../../cs-errorcode';
export enum RegisterError {
UserTaken = 'UserTaken',
UserInvalid = 'UserInvalid',
UserExclusive = 'UserExclusive',
PasswordWeak = 'PasswordWeak',
PasswordShort = 'PasswordShort',
InvalidRequest = 'InvalidRequest',
Forbidden = 'Forbidden',
RateLimited = 'RateLimited',
Unknown = 'Unknown',
}
export type CustomRegisterResponse = {
baseUrl: string;
response: RegisterResponse;
};
export type RegisterResult = [IAuthData, undefined] | [undefined, CustomRegisterResponse];
export const register = async (
mx: MatrixClient,
requestData: RegisterRequest
): Promise<RegisterResult> => {
const [err, res] = await to<RegisterResponse, MatrixError>(mx.registerRequest(requestData));
if (err) {
if (err.httpStatus === 401) {
const authData = err.data as IAuthData;
return [authData, undefined];
}
if (err.errcode === ErrorCode.M_USER_IN_USE) {
throw new MatrixError({
errcode: RegisterError.UserTaken,
});
}
if (err.errcode === ErrorCode.M_INVALID_USERNAME) {
throw new MatrixError({
errcode: RegisterError.UserInvalid,
});
}
if (err.errcode === ErrorCode.M_EXCLUSIVE) {
throw new MatrixError({
errcode: RegisterError.UserExclusive,
});
}
if (err.errcode === ErrorCode.M_WEAK_PASSWORD) {
throw new MatrixError({
errcode: RegisterError.PasswordWeak,
error: err.data.error,
});
}
if (err.errcode === ErrorCode.M_PASSWORD_TOO_SHORT) {
throw new MatrixError({
errcode: RegisterError.PasswordShort,
error: err.data.error,
});
}
if (err.httpStatus === 429) {
throw new MatrixError({
errcode: RegisterError.RateLimited,
});
}
if (err.httpStatus === 400) {
throw new MatrixError({
errcode: RegisterError.InvalidRequest,
});
}
if (err.httpStatus === 403) {
throw new MatrixError({
errcode: RegisterError.Forbidden,
});
}
throw new MatrixError({
errcode: RegisterError.Unknown,
error: err.data.error,
});
}
return [
undefined,
{
baseUrl: mx.baseUrl,
response: res,
},
];
};
export const useRegisterComplete = (data?: CustomRegisterResponse) => {
const navigate = useNavigate();
useEffect(() => {
if (data) {
const { response, baseUrl } = data;
const userId = response.user_id;
const accessToken = response.access_token;
const deviceId = response.device_id;
if (accessToken && deviceId) {
updateLocalStore(accessToken, deviceId, userId, baseUrl);
// TODO: add after register redirect url
navigate(ROOT_PATH, { replace: true });
} else {
// TODO: navigate to login with userId
navigate(ROOT_PATH, { replace: true });
}
}
}, [data, navigate]);
};