mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-13 18:45:40 +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