@micha.bigler/ui-core-micha 1.3.1 → 1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/authApi.js +13 -11
- package/dist/components/MFAComponent.js +1 -1
- package/dist/pages/LoginPage.js +19 -1
- package/package.json +1 -1
- package/src/auth/authApi.jsx +16 -15
- package/src/components/MFAComponent.jsx +2 -1
- package/src/pages/LoginPage.jsx +18 -1
package/dist/auth/authApi.js
CHANGED
|
@@ -373,30 +373,32 @@ export async function authenticateWithMFA({ code, credential }) {
|
|
|
373
373
|
// Authentication: password (MODIFIZIERT)
|
|
374
374
|
// -----------------------------
|
|
375
375
|
export async function loginWithPassword(email, password) {
|
|
376
|
-
var _a;
|
|
376
|
+
var _a, _b;
|
|
377
377
|
try {
|
|
378
378
|
await axios.post(`${HEADLESS_BASE}/auth/login`, { email, password }, { withCredentials: true });
|
|
379
379
|
}
|
|
380
380
|
catch (error) {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
381
|
+
const status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
|
|
382
|
+
const data = (_b = error.response) === null || _b === void 0 ? void 0 : _b.data;
|
|
383
|
+
// --- SKEPTISCHER CHECK: MFA NÖTIG? ---
|
|
384
|
+
// Wenn Allauth 401 mit flow="mfa_authenticate" sendet, ist das KEIN Fehler,
|
|
385
|
+
// sondern die Aufforderung für Schritt 2.
|
|
386
|
+
if (status === 401 && (data === null || data === void 0 ? void 0 : data.flow) === 'mfa_authenticate') {
|
|
386
387
|
return {
|
|
387
388
|
needsMfa: true,
|
|
388
|
-
availableTypes:
|
|
389
|
+
availableTypes: data.types || [], // z.B. ["webauthn", "totp"]
|
|
389
390
|
};
|
|
390
391
|
}
|
|
391
|
-
//
|
|
392
|
-
if (
|
|
393
|
-
//
|
|
392
|
+
// --- "Already Logged In" Handling ---
|
|
393
|
+
if (status === 409) {
|
|
394
|
+
// User ist schon eingeloggt, wir machen einfach weiter
|
|
394
395
|
}
|
|
395
396
|
else {
|
|
397
|
+
// Echter Fehler (z.B. falsches Passwort oder Serverfehler)
|
|
396
398
|
throw new Error(extractErrorMessage(error));
|
|
397
399
|
}
|
|
398
400
|
}
|
|
399
|
-
// Wenn wir hier landen, war
|
|
401
|
+
// Wenn wir hier landen, war der Login direkt erfolgreich (kein MFA)
|
|
400
402
|
const user = await fetchCurrentUser();
|
|
401
403
|
return { user, needsMfa: false };
|
|
402
404
|
}
|
|
@@ -5,7 +5,7 @@ import { QRCodeSVG } from 'qrcode.react';
|
|
|
5
5
|
import { Box, Typography, Button, TextField, Card, CardContent, Alert, CircularProgress, Stack, Divider, IconButton, Tooltip, } from '@mui/material';
|
|
6
6
|
import DeleteIcon from '@mui/icons-material/Delete';
|
|
7
7
|
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
|
8
|
-
import { authApi } from '../authApi';
|
|
8
|
+
import { authApi } from '../auth/authApi';
|
|
9
9
|
const MFAComponent = () => {
|
|
10
10
|
const [authenticators, setAuthenticators] = useState([]);
|
|
11
11
|
const [loading, setLoading] = useState(true);
|
package/dist/pages/LoginPage.js
CHANGED
|
@@ -76,7 +76,25 @@ export function LoginPage() {
|
|
|
76
76
|
};
|
|
77
77
|
// ... (Social & Sign Up Handler bleiben gleich) ...
|
|
78
78
|
const handleSocialLogin = (provider) => authApi.startSocialLogin(provider);
|
|
79
|
-
const handlePasskeyLoginInitial = async () => {
|
|
79
|
+
const handlePasskeyLoginInitial = async () => {
|
|
80
|
+
var _a, _b;
|
|
81
|
+
setError('');
|
|
82
|
+
setSubmitting(true);
|
|
83
|
+
try {
|
|
84
|
+
// Wir rufen die existierende Passkey-Login Funktion auf
|
|
85
|
+
const { user } = await authApi.loginWithPasskey();
|
|
86
|
+
login(user);
|
|
87
|
+
navigate('/');
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
setError(((_b = (_a = err === null || err === void 0 ? void 0 : err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.detail) ||
|
|
91
|
+
(err === null || err === void 0 ? void 0 : err.message) ||
|
|
92
|
+
'Passkey login failed.');
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
setSubmitting(false);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
80
98
|
const handleSignUp = () => navigate('/signup');
|
|
81
99
|
const handleForgotPassword = () => navigate('/reset-request-password');
|
|
82
100
|
return (_jsxs(NarrowPage, { title: "Login", children: [_jsx(Helmet, { children: _jsx("title", { children: "Login" }) }), error && _jsx(Alert, { severity: "error", sx: { mb: 2 }, children: error }), step === 'credentials' && (_jsx(LoginForm, { onSubmit: handleSubmitCredentials, onForgotPassword: handleForgotPassword, onSocialLogin: handleSocialLogin, onPasskeyLogin: handlePasskeyLoginInitial, onSignUp: handleSignUp, disabled: submitting })), step === 'mfa' && (_jsxs(Box, { children: [_jsx(Typography, { variant: "body1", gutterBottom: true, children: "Two-Factor Authentication required." }), _jsxs(Stack, { spacing: 2, sx: { mt: 2 }, children: [mfaTypes.includes('webauthn') && (_jsx(Button, { variant: "outlined", onClick: handleMfaPasskey, fullWidth: true, children: "Use Passkey / Security Key" })), (mfaTypes.includes('totp') || mfaTypes.includes('recovery_codes')) && (_jsxs("form", { onSubmit: handleMfaTotpSubmit, children: [_jsx(TextField, { label: "Authenticator Code (or Recovery Code)", value: totpCode, onChange: (e) => setTotpCode(e.target.value), fullWidth: true, autoFocus: true, disabled: submitting, sx: { mb: 2 } }), _jsx(Button, { type: "submit", variant: "contained", fullWidth: true, disabled: submitting, children: "Verify" })] })), _jsx(Button, { size: "small", onClick: () => setStep('credentials'), children: "Back to Login" })] })] }))] }));
|
package/package.json
CHANGED
package/src/auth/authApi.jsx
CHANGED
|
@@ -489,31 +489,32 @@ export async function loginWithPassword(email, password) {
|
|
|
489
489
|
await axios.post(
|
|
490
490
|
`${HEADLESS_BASE}/auth/login`,
|
|
491
491
|
{ email, password },
|
|
492
|
-
{ withCredentials: true }
|
|
492
|
+
{ withCredentials: true },
|
|
493
493
|
);
|
|
494
494
|
} catch (error) {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
495
|
+
const status = error.response?.status;
|
|
496
|
+
const data = error.response?.data;
|
|
497
|
+
|
|
498
|
+
// --- SKEPTISCHER CHECK: MFA NÖTIG? ---
|
|
499
|
+
// Wenn Allauth 401 mit flow="mfa_authenticate" sendet, ist das KEIN Fehler,
|
|
500
|
+
// sondern die Aufforderung für Schritt 2.
|
|
501
|
+
if (status === 401 && data?.flow === 'mfa_authenticate') {
|
|
502
502
|
return {
|
|
503
503
|
needsMfa: true,
|
|
504
|
-
availableTypes:
|
|
504
|
+
availableTypes: data.types || [], // z.B. ["webauthn", "totp"]
|
|
505
505
|
};
|
|
506
506
|
}
|
|
507
|
-
|
|
508
|
-
//
|
|
509
|
-
if (
|
|
510
|
-
|
|
507
|
+
|
|
508
|
+
// --- "Already Logged In" Handling ---
|
|
509
|
+
if (status === 409) {
|
|
510
|
+
// User ist schon eingeloggt, wir machen einfach weiter
|
|
511
511
|
} else {
|
|
512
|
-
|
|
512
|
+
// Echter Fehler (z.B. falsches Passwort oder Serverfehler)
|
|
513
|
+
throw new Error(extractErrorMessage(error));
|
|
513
514
|
}
|
|
514
515
|
}
|
|
515
516
|
|
|
516
|
-
// Wenn wir hier landen, war
|
|
517
|
+
// Wenn wir hier landen, war der Login direkt erfolgreich (kein MFA)
|
|
517
518
|
const user = await fetchCurrentUser();
|
|
518
519
|
return { user, needsMfa: false };
|
|
519
520
|
}
|
|
@@ -17,7 +17,8 @@ import {
|
|
|
17
17
|
} from '@mui/material';
|
|
18
18
|
import DeleteIcon from '@mui/icons-material/Delete';
|
|
19
19
|
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
|
20
|
-
import { authApi } from '../authApi';
|
|
20
|
+
import { authApi } from '../auth/authApi';
|
|
21
|
+
|
|
21
22
|
|
|
22
23
|
const MFAComponent = () => {
|
|
23
24
|
const [authenticators, setAuthenticators] = useState([]);
|
package/src/pages/LoginPage.jsx
CHANGED
|
@@ -77,7 +77,24 @@ export function LoginPage() {
|
|
|
77
77
|
|
|
78
78
|
// ... (Social & Sign Up Handler bleiben gleich) ...
|
|
79
79
|
const handleSocialLogin = (provider) => authApi.startSocialLogin(provider);
|
|
80
|
-
const handlePasskeyLoginInitial = async () => {
|
|
80
|
+
const handlePasskeyLoginInitial = async () => {
|
|
81
|
+
setError('');
|
|
82
|
+
setSubmitting(true);
|
|
83
|
+
try {
|
|
84
|
+
// Wir rufen die existierende Passkey-Login Funktion auf
|
|
85
|
+
const { user } = await authApi.loginWithPasskey();
|
|
86
|
+
login(user);
|
|
87
|
+
navigate('/');
|
|
88
|
+
} catch (err) {
|
|
89
|
+
setError(
|
|
90
|
+
err?.response?.data?.detail ||
|
|
91
|
+
err?.message ||
|
|
92
|
+
'Passkey login failed.',
|
|
93
|
+
);
|
|
94
|
+
} finally {
|
|
95
|
+
setSubmitting(false);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
81
98
|
const handleSignUp = () => navigate('/signup');
|
|
82
99
|
const handleForgotPassword = () => navigate('/reset-request-password');
|
|
83
100
|
|