mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	chore(backend): bump allauth version (#9714)
* bump allauth * add trust * add device trust handling * fix style * Update api_version.py --------- Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
This commit is contained in:
		| @@ -1,12 +1,15 @@ | ||||
| """InvenTree API version information.""" | ||||
|  | ||||
| # InvenTree API version | ||||
| INVENTREE_API_VERSION = 343 | ||||
| INVENTREE_API_VERSION = 344 | ||||
|  | ||||
| """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" | ||||
|  | ||||
|  | ||||
| INVENTREE_API_TEXT = """ | ||||
| v344 -> 2025-06-02 : https://github.com/inventree/InvenTree/pull/9714 | ||||
|     - Updates alauth version and adds device trust as a factor | ||||
|  | ||||
| v343 -> 2025-06-02 : https://github.com/inventree/InvenTree/pull/9717 | ||||
|     - Add ISO currency codes to the description text for currency options | ||||
|  | ||||
|   | ||||
| @@ -1327,6 +1327,7 @@ ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True | ||||
|  | ||||
| HEADLESS_ONLY = True | ||||
| HEADLESS_TOKEN_STRATEGY = 'InvenTree.auth_overrides.DRFTokenStrategy' | ||||
| HEADLESS_CLIENTS = 'browser' | ||||
| MFA_ENABLED = get_boolean_setting( | ||||
|     'INVENTREE_MFA_ENABLED', 'mfa_enabled', True | ||||
| )  # TODO re-implement | ||||
| @@ -1336,6 +1337,7 @@ MFA_SUPPORTED_TYPES = get_setting( | ||||
|     ['totp', 'recovery_codes'], | ||||
|     typecast=list, | ||||
| ) | ||||
| MFA_TRUST_ENABLED = True | ||||
|  | ||||
| LOGOUT_REDIRECT_URL = get_setting( | ||||
|     'INVENTREE_LOGOUT_REDIRECT_URL', 'logout_redirect_url', 'index' | ||||
|   | ||||
| @@ -423,8 +423,8 @@ django==4.2.21 \ | ||||
|     #   djangorestframework | ||||
|     #   djangorestframework-simplejwt | ||||
|     #   drf-spectacular | ||||
| django-allauth[mfa, openid, saml, socialaccount]==65.4.1 \ | ||||
|     --hash=sha256:60b32aef7dbbcc213319aa4fd8f570e985266ea1162ae6ef7a26a24efca85c8c | ||||
| django-allauth[mfa, openid, saml, socialaccount]==65.9.0 \ | ||||
|     --hash=sha256:a06bca9974df44321e94c33bcf770bb6f924d1a44b57defbce4d7ec54a55483e | ||||
|     # via -r src/backend/requirements.in | ||||
| django-cleanup==9.0.0 \ | ||||
|     --hash=sha256:19f8b0e830233f9f0f683b17181f414672a0f48afe3ea3cc80ba47ae40ad880c \ | ||||
|   | ||||
| @@ -30,6 +30,7 @@ export enum ApiEndpoints { | ||||
|   auth_recovery = 'auth/v1/account/authenticators/recovery-codes', | ||||
|   auth_mfa_reauthenticate = 'auth/v1/auth/2fa/reauthenticate', | ||||
|   auth_totp = 'auth/v1/account/authenticators/totp', | ||||
|   auth_trust = 'auth/v1/auth/2fa/trust', | ||||
|   auth_reauthenticate = 'auth/v1/auth/reauthenticate', | ||||
|   auth_email = 'auth/v1/account/email', | ||||
|   auth_email_verify = 'auth/v1/auth/email/verify', | ||||
|   | ||||
| @@ -13,7 +13,8 @@ export enum FlowEnum { | ||||
|   ProviderToken = 'provider_token', | ||||
|   MfaAuthenticate = 'mfa_authenticate', | ||||
|   Reauthenticate = 'reauthenticate', | ||||
|   MfaReauthenticate = 'mfa_reauthenticate' | ||||
|   MfaReauthenticate = 'mfa_reauthenticate', | ||||
|   MfaTrust = 'mfa_trust' | ||||
| } | ||||
|  | ||||
| export interface Flow { | ||||
|   | ||||
| @@ -262,26 +262,19 @@ export function handleReset( | ||||
| export function handleMfaLogin( | ||||
|   navigate: NavigateFunction, | ||||
|   location: Location<any>, | ||||
|   values: { code: string }, | ||||
|   values: { code: string; remember?: boolean }, | ||||
|   setError: (message: string | undefined) => void | ||||
| ) { | ||||
|   const { setAuthenticated, fetchUserState } = useUserState.getState(); | ||||
|   const { setAuthContext } = useServerApiState.getState(); | ||||
|  | ||||
|   authApi(apiUrl(ApiEndpoints.auth_login_2fa), undefined, 'post', { | ||||
|     code: values.code | ||||
|   }) | ||||
|     .then((response) => { | ||||
|       setError(undefined); | ||||
|       setAuthContext(response.data?.data); | ||||
|       setAuthenticated(); | ||||
|  | ||||
|       fetchUserState().finally(() => { | ||||
|         observeProfile(); | ||||
|         followRedirect(navigate, location?.state); | ||||
|       }); | ||||
|       handleSuccessFullAuth(response, navigate, location, setError); | ||||
|     }) | ||||
|     .catch((err) => { | ||||
|       // Already logged in, but with a different session | ||||
|       if (err?.response?.status == 409) { | ||||
|         notifications.show({ | ||||
|           title: t`Already logged in`, | ||||
| @@ -289,6 +282,19 @@ export function handleMfaLogin( | ||||
|           color: 'red', | ||||
|           autoClose: false | ||||
|         }); | ||||
|         // MFA trust flow pending | ||||
|       } else if (err?.response?.status == 401) { | ||||
|         const mfa_trust = err.response.data.data.flows.find( | ||||
|           (flow: any) => flow.id == FlowEnum.MfaTrust | ||||
|         ); | ||||
|         if (mfa_trust?.is_pending) { | ||||
|           setAuthContext(err.response.data.data); | ||||
|           authApi(apiUrl(ApiEndpoints.auth_trust), undefined, 'post', { | ||||
|             trust: values.remember ?? false | ||||
|           }).then((response) => { | ||||
|             handleSuccessFullAuth(response, navigate, location, setError); | ||||
|           }); | ||||
|         } | ||||
|       } else { | ||||
|         const errors = err.response?.data?.errors; | ||||
|         let msg = t`An error occurred`; | ||||
| @@ -351,6 +357,35 @@ export const checkLoginState = async ( | ||||
|   } | ||||
| }; | ||||
|  | ||||
| function handleSuccessFullAuth( | ||||
|   response?: any, | ||||
|   navigate?: NavigateFunction, | ||||
|   location?: Location<any>, | ||||
|   setError?: (message: string | undefined) => void | ||||
| ) { | ||||
|   const { setAuthenticated, fetchUserState } = useUserState.getState(); | ||||
|   const { setAuthContext } = useServerApiState.getState(); | ||||
|  | ||||
|   if (setError) { | ||||
|     // If an error function is provided, clear any previous errors | ||||
|     setError(undefined); | ||||
|   } | ||||
|  | ||||
|   if (response.data?.data) { | ||||
|     setAuthContext(response.data?.data); | ||||
|   } | ||||
|   setAuthenticated(); | ||||
|  | ||||
|   fetchUserState().finally(() => { | ||||
|     observeProfile(); | ||||
|     fetchGlobalStates(navigate); | ||||
|  | ||||
|     if (navigate) { | ||||
|       followRedirect(navigate, location?.state); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the value of the CSRF cookie, if available | ||||
|  */ | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { t } from '@lingui/core/macro'; | ||||
| import { Trans } from '@lingui/react/macro'; | ||||
| import { Button, TextInput } from '@mantine/core'; | ||||
| import { Button, Checkbox, TextInput } from '@mantine/core'; | ||||
| import { useForm } from '@mantine/form'; | ||||
| import { useState } from 'react'; | ||||
| import { useLocation, useNavigate } from 'react-router-dom'; | ||||
| @@ -8,7 +8,7 @@ import { handleMfaLogin } from '../../functions/auth'; | ||||
| import { Wrapper } from './Layout'; | ||||
|  | ||||
| export default function Mfa() { | ||||
|   const simpleForm = useForm({ initialValues: { code: '' } }); | ||||
|   const simpleForm = useForm({ initialValues: { code: '', remember: false } }); | ||||
|   const navigate = useNavigate(); | ||||
|   const location = useLocation(); | ||||
|   const [loginError, setLoginError] = useState<string | undefined>(undefined); | ||||
| @@ -23,6 +23,12 @@ export default function Mfa() { | ||||
|         {...simpleForm.getInputProps('code')} | ||||
|         error={loginError} | ||||
|       /> | ||||
|       <Checkbox | ||||
|         label={t`Remember this device`} | ||||
|         name='remember' | ||||
|         description={t`If enabled, you will not be asked for MFA on this device for 30 days.`} | ||||
|         {...simpleForm.getInputProps('remember', { type: 'checkbox' })} | ||||
|       /> | ||||
|       <Button | ||||
|         type='submit' | ||||
|         onClick={() => | ||||
|   | ||||
		Reference in New Issue
	
	Block a user