From 02491143223170ade6052cbd948bacc49950cf45 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Mon, 20 Jan 2025 20:01:21 +0100 Subject: [PATCH] save auth context --- src/frontend/src/functions/auth.tsx | 48 +++++++++---------- .../AccountSettings/SecurityContent.tsx | 24 +++++++--- src/frontend/src/states/ApiState.tsx | 8 +++- src/frontend/src/states/states.tsx | 24 ++++++++++ 4 files changed, 71 insertions(+), 33 deletions(-) diff --git a/src/frontend/src/functions/auth.tsx b/src/frontend/src/functions/auth.tsx index 655a507723..175ecc14b8 100644 --- a/src/frontend/src/functions/auth.tsx +++ b/src/frontend/src/functions/auth.tsx @@ -5,7 +5,7 @@ import type { AxiosRequestConfig } from 'axios'; import type { Location, NavigateFunction } from 'react-router-dom'; import { api, setApiDefaults } from '../App'; import { ApiEndpoints } from '../enums/ApiEndpoints'; -import { apiUrl } from '../states/ApiState'; +import { apiUrl, useServerApiState } from '../states/ApiState'; import { useLocalState } from '../states/LocalState'; import { useUserState } from '../states/UserState'; import { type Provider, fetchGlobalStates } from '../states/states'; @@ -66,6 +66,7 @@ export const doBasicLogin = async ( ) => { const { host } = useLocalState.getState(); const { clearUserState, setToken, fetchUserState } = useUserState.getState(); + const { setAuthContext } = useServerApiState.getState(); if (username.length == 0 || password.length == 0) { return; @@ -90,6 +91,7 @@ export const doBasicLogin = async ( } ) .then((response) => { + setAuthContext(response.data?.data); if (response.status == 200 && response.data?.meta?.is_authenticated) { setToken(response.data.meta.access_token); loginDone = true; @@ -98,6 +100,7 @@ export const doBasicLogin = async ( }) .catch((err) => { if (err?.response?.status == 401) { + setAuthContext(err.response.data?.data); const mfa_flow = err.response.data.data.flows.find( (flow: any) => flow.id == 'mfa_authenticate' ); @@ -173,32 +176,23 @@ export function handleReset( values: { email: string } ) { ensureCsrf(); - api - .post( - apiUrl(ApiEndpoints.user_reset), - values - /*{ - headers: { Authorization: '' } + api.post(apiUrl(ApiEndpoints.user_reset), values).then((val) => { + if (val.status === 200) { + notifications.show({ + title: t`Mail delivery successful`, + message: t`Check your inbox for a reset link. This only works if you have an account. Check in spam too.`, + color: 'green', + autoClose: false + }); + navigate('/login'); + } else { + notifications.show({ + title: t`Reset failed`, + message: t`Check your input and try again.`, + color: 'red' + }); } - */ - ) - .then((val) => { - if (val.status === 200) { - notifications.show({ - title: t`Mail delivery successful`, - message: t`Check your inbox for a reset link. This only works if you have an account. Check in spam too.`, - color: 'green', - autoClose: false - }); - navigate('/login'); - } else { - notifications.show({ - title: t`Reset failed`, - message: t`Check your input and try again.`, - color: 'red' - }); - } - }); + }); } export function handleMfaLogin( @@ -207,9 +201,11 @@ export function handleMfaLogin( values: { code: string } ) { const { setToken } = useUserState.getState(); + const { setAuthContext } = useServerApiState.getState(); authApi(apiUrl(ApiEndpoints.auth_login_2fa), undefined, 'post', { code: values.code }).then((response) => { + setAuthContext(response.data?.data); setToken(response.data.meta.access_token); followRedirect(navigate, location?.state); }); diff --git a/src/frontend/src/pages/Index/Settings/AccountSettings/SecurityContent.tsx b/src/frontend/src/pages/Index/Settings/AccountSettings/SecurityContent.tsx index 0099f5cf75..745e102bdc 100644 --- a/src/frontend/src/pages/Index/Settings/AccountSettings/SecurityContent.tsx +++ b/src/frontend/src/pages/Index/Settings/AccountSettings/SecurityContent.tsx @@ -574,7 +574,9 @@ async function runActionWithFallback( action: () => Promise, getReauthText: (props: any) => any ) { + const { setAuthContext } = useServerApiState.getState(); const rslt = await action().catch((err) => { + setAuthContext(err.response.data?.data); // check if we need to re-authenticate if (err.status == 401) { if ( @@ -603,9 +605,14 @@ async function runActionWithFallback( name: 'TOTP', description: t`Enter your TOTP or recovery code` }) - }).then(() => { - action(); - }); + }) + .then((response) => { + setAuthContext(response.data?.data); + action(); + }) + .catch((err) => { + setAuthContext(err.response.data?.data); + }); } else if (rslt == ResultType.reauth) { authApi(apiUrl(ApiEndpoints.auth_reauthenticate), undefined, 'post', { password: await getReauthText({ @@ -613,9 +620,14 @@ async function runActionWithFallback( name: 'password', description: t`Enter your password` }) - }).then(() => { - action(); - }); + }) + .then((response) => { + setAuthContext(response.data?.data); + action(); + }) + .catch((err) => { + setAuthContext(err.response.data?.data); + }); } } diff --git a/src/frontend/src/states/ApiState.tsx b/src/frontend/src/states/ApiState.tsx index 757baad1c7..0df04318c6 100644 --- a/src/frontend/src/states/ApiState.tsx +++ b/src/frontend/src/states/ApiState.tsx @@ -4,13 +4,15 @@ import { createJSONStorage, persist } from 'zustand/middleware'; import { api } from '../App'; import { emptyServerAPI } from '../defaults/defaults'; import { ApiEndpoints } from '../enums/ApiEndpoints'; -import type { AuthConfig, ServerAPIProps } from './states'; +import type { AuthConfig, AuthContext, ServerAPIProps } from './states'; interface ServerApiStateProps { server: ServerAPIProps; setServer: (newServer: ServerAPIProps) => void; fetchServerApiState: () => void; auth_config?: AuthConfig; + auth_context?: AuthContext; + setAuthContext: (auth_context: AuthContext) => void; sso_enabled: () => boolean; registration_enabled: () => boolean; sso_registration_enabled: () => boolean; @@ -47,6 +49,10 @@ export const useServerApiState = create()( }); }, auth_config: undefined, + auth_context: undefined, + setAuthContext(auth_context) { + set({ auth_context }); + }, sso_enabled: () => { const data = get().auth_config?.socialaccount.providers; return !(data === undefined || data.length == 0); diff --git a/src/frontend/src/states/states.tsx b/src/frontend/src/states/states.tsx index 5fceab9662..ea632d95a5 100644 --- a/src/frontend/src/states/states.tsx +++ b/src/frontend/src/states/states.tsx @@ -50,6 +50,30 @@ export interface ServerAPIProps { django_admin: null | string; } +export interface AuthContext { + status: number; + data: { flows: Flow[] }; + meta: { is_authenticated: boolean }; +} + +export enum FlowEnum { + VerifyEmail = 'verify_email', + Login = 'login', + Signup = 'signup', + ProviderRedirect = 'provider_redirect', + ProviderSignup = 'provider_signup', + ProviderToken = 'provider_token', + MfaAuthenticate = 'mfa_authenticate', + Reauthenticate = 'reauthenticate', + MfaReauthenticate = 'mfa_reauthenticate' +} + +export interface Flow { + id: FlowEnum; + providers?: string[]; + is_pending?: boolean[]; +} + export interface AuthConfig { account: { authentication_method: string;