commit db8aac076f6056cb69665d1d090adc629bc32892
parent 3f144dbf7e4a4b2e0cc7c27e26d7545f1a9d43d2
Author: MTRNord <mtrnord1@gmail.com>
Date: Fri, 28 Apr 2023 22:33:57 +0200
fix: Improve login flow
Diffstat:
2 files changed, 41 insertions(+), 21 deletions(-)
diff --git a/src/app/api/api.ts b/src/app/api/api.ts
@@ -22,8 +22,6 @@ interface IAuthState {
logged_in: boolean;
}
const initialAuthState: IAuthState = {
- host: undefined,
- accessToken: undefined,
logged_in: false,
}
export const auth = createReducer(initialAuthState, (builder) => builder
@@ -86,6 +84,7 @@ export const matrixApi = createApi({
try {
const { data, meta } = await queryFulfilled;
const response = (meta as { request: Request, response: Response }).response;
+
if (response.status === 200) {
dispatch(setLoggedIn(true))
dispatch(setAccessToken(data.access_token))
@@ -118,4 +117,4 @@ const rawBaseQuery = (baseUrl: string) => fetchBaseQuery({
// Export hooks for usage in functional components, which are
// auto-generated based on the defined endpoints
-export const { useGetLoginFlowsQuery, useDoLoginMutation, useLazyGetWellKnownQuery } = matrixApi
+export const { useLazyGetLoginFlowsQuery, useDoLoginMutation, useLazyGetWellKnownQuery } = matrixApi
diff --git a/src/components/login/login.tsx b/src/components/login/login.tsx
@@ -1,36 +1,57 @@
-import { useDeferredValue, useState } from 'react';
+import { useState } from 'react';
import { useAppDispatch } from '../../app/hooks';
-import { setHost, useDoLoginMutation, useLazyGetWellKnownQuery } from '../../app/api/api';
+import { setHost, useDoLoginMutation, useLazyGetLoginFlowsQuery, useLazyGetWellKnownQuery } from '../../app/api/api';
import Button from '../button/button';
import Header from '../header/header';
import Input from '../input/basic/input';
import { Navigate } from 'react-router-dom';
+import { IRateLimitError } from '../../app/api/apiTypes';
export function Login() {
- const [login, { isLoading: loginPending, error: loginError }] = useDoLoginMutation();
- const [triggerWellKnown, _result, _lastPromiseInfo] = useLazyGetWellKnownQuery();
- const deferredLoginError = useDeferredValue(loginError);
+ const [login, { isLoading: loginPending, isSuccess, error: loginErrorRaw }] = useDoLoginMutation();
+ const [triggerWellKnown] = useLazyGetWellKnownQuery();
+ const [triggerLoginFlows] = useLazyGetLoginFlowsQuery();
+ const [loginError, setLoginError] = useState(loginErrorRaw);
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
- const [loginPendingLast, setLoginPendingLast] = useState(false);
const dispatch = useAppDispatch();
- if (loginPendingLast !== loginPending) {
+ if (isSuccess) {
return <Navigate to="/" />;
}
const startLogin = async () => {
dispatch(setHost(`https://${username.split(':')[1]}`));
- await triggerWellKnown(undefined);
- login({
- type: 'm.login.password',
- identifier: {
- type: 'm.id.user',
+ const { isError, error } = await triggerWellKnown(undefined);
+ if (isError) {
+ setLoginError(error);
+ return;
+ }
+ const { data } = await triggerLoginFlows(undefined, true);
+ if ((data?.flows?.filter((flow) => flow.type === 'm.login.password')?.length || 0) > 0) {
+ const payload = await login({
+ type: 'm.login.password',
+ identifier: {
+ type: 'm.id.user',
+ user: username,
+ },
user: username,
- },
- user: username,
- password: password
- })
- setLoginPendingLast(true);
+ password: password
+ });
+ if ('error' in payload) {
+ if (JSON.stringify(payload.error).includes('M_LIMIT_EXCEEDED')) {
+ setLoginError({ status: "CUSTOM_ERROR", error: 'Too many attempts, try again later' });
+ return;
+ }
+ if (JSON.stringify(payload.error).includes('M_FORBIDDEN')) {
+ setLoginError({ status: "CUSTOM_ERROR", error: (payload.error as any).data.error });
+ return;
+ }
+ setLoginError(payload.error);
+ return;
+ }
+ } else {
+ setLoginError({ status: "CUSTOM_ERROR", error: 'No password login flow found' });
+ }
}
// TODO: We need to make sure that we do well-known before login
return (
@@ -39,7 +60,7 @@ export function Login() {
startLogin();
}}>
<Header>Login</Header>
- {deferredLoginError ? <h2 className='text-red-500 font-normal text-sm'>{'error' in deferredLoginError ? deferredLoginError.error : ('data' in deferredLoginError ? JSON.stringify(deferredLoginError.data) : deferredLoginError.message)}</h2> : <div className='min-h-[1.25rem]'></div>}
+ {loginError ? <h2 className='text-red-500 font-normal text-sm'>{'error' in loginError ? loginError.error : ('data' in loginError ? JSON.stringify(loginError.data) : loginError.message)}</h2> : <div className='min-h-[1.25rem]'></div>}
<Input
readonly={loginPending}
value={username}