@micha.bigler/ui-core-micha 1.4.31 → 1.4.32
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.
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// src/auth/components/MfaLoginComponent.jsx
|
|
3
2
|
import React, { useState } from 'react';
|
|
4
3
|
import { Box, Typography, TextField, Button, Stack, Alert, Divider, Dialog, DialogTitle, DialogContent, DialogActions, } from '@mui/material';
|
|
5
4
|
import { useTranslation } from 'react-i18next';
|
|
@@ -44,11 +43,22 @@ export function MfaLoginComponent({ availableTypes, identifier, onSuccess, onCan
|
|
|
44
43
|
setInfoKey(null);
|
|
45
44
|
setSubmitting(true);
|
|
46
45
|
try {
|
|
47
|
-
|
|
46
|
+
// Use standard passkey login (starts a fresh session flow).
|
|
47
|
+
// This allows users to bypass the password MFA step if they have a valid passkey.
|
|
48
|
+
const user = await loginWithPasskey();
|
|
48
49
|
onSuccess({ user, method: 'webauthn' });
|
|
49
50
|
}
|
|
50
51
|
catch (err) {
|
|
51
|
-
|
|
52
|
+
// Detailed error handling
|
|
53
|
+
if (err.code === 'Auth.PASSKEY_CANCELLED') {
|
|
54
|
+
// User cancelled - show specific key or just ignore
|
|
55
|
+
setErrorKey('Auth.PASSKEY_CANCELLED');
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// eslint-disable-next-line no-console
|
|
59
|
+
console.error(err);
|
|
60
|
+
setErrorKey('Auth.PASSKEY_FAILED');
|
|
61
|
+
}
|
|
52
62
|
}
|
|
53
63
|
finally {
|
|
54
64
|
setSubmitting(false);
|
|
@@ -27,7 +27,7 @@ export async function registerPasskey(name = 'Passkey') {
|
|
|
27
27
|
}
|
|
28
28
|
export async function loginWithPasskey() {
|
|
29
29
|
ensureWebAuthnSupport();
|
|
30
|
-
// 1. Get Challenge
|
|
30
|
+
// 1. Get Challenge (für passwordless Login)
|
|
31
31
|
const requestOptions = await getPasskeyLoginOptions();
|
|
32
32
|
// 2. Browser Sign
|
|
33
33
|
let assertion;
|
|
@@ -36,7 +36,11 @@ export async function loginWithPasskey() {
|
|
|
36
36
|
assertion = await navigator.credentials.get({ publicKey: pubKey });
|
|
37
37
|
}
|
|
38
38
|
catch (err) {
|
|
39
|
-
|
|
39
|
+
if (err.name === 'NotAllowedError') {
|
|
40
|
+
throw normaliseApiError(new Error('Auth.PASSKEY_CANCELLED'), 'Auth.PASSKEY_CANCELLED');
|
|
41
|
+
}
|
|
42
|
+
// Wenn der Browser sagt "No credentials found", werfen wir das weiter
|
|
43
|
+
throw err;
|
|
40
44
|
}
|
|
41
45
|
// 3. Complete
|
|
42
46
|
const credentialJson = serializeCredential(assertion);
|
package/package.json
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// src/auth/components/MfaLoginComponent.jsx
|
|
2
1
|
import React, { useState } from 'react';
|
|
3
2
|
import {
|
|
4
3
|
Box,
|
|
@@ -14,10 +13,10 @@ import {
|
|
|
14
13
|
DialogActions,
|
|
15
14
|
} from '@mui/material';
|
|
16
15
|
import { useTranslation } from 'react-i18next';
|
|
17
|
-
import { authenticateWithMFA, fetchCurrentUser, requestMfaSupportHelp
|
|
18
|
-
import { loginWithPasskey
|
|
16
|
+
import { authenticateWithMFA, fetchCurrentUser, requestMfaSupportHelp } from '../auth/authApi';
|
|
17
|
+
import { loginWithPasskey } from '../utils/authService';
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
export function MfaLoginComponent({ availableTypes, identifier, onSuccess, onCancel }) {
|
|
21
20
|
const { t } = useTranslation();
|
|
22
21
|
const [code, setCode] = useState('');
|
|
23
22
|
const [submitting, setSubmitting] = useState(false);
|
|
@@ -62,10 +61,20 @@ import { loginWithPasskey } from '../utils/authService';
|
|
|
62
61
|
setInfoKey(null);
|
|
63
62
|
setSubmitting(true);
|
|
64
63
|
try {
|
|
65
|
-
|
|
64
|
+
// Use standard passkey login (starts a fresh session flow).
|
|
65
|
+
// This allows users to bypass the password MFA step if they have a valid passkey.
|
|
66
|
+
const user = await loginWithPasskey();
|
|
66
67
|
onSuccess({ user, method: 'webauthn' });
|
|
67
68
|
} catch (err) {
|
|
68
|
-
|
|
69
|
+
// Detailed error handling
|
|
70
|
+
if (err.code === 'Auth.PASSKEY_CANCELLED') {
|
|
71
|
+
// User cancelled - show specific key or just ignore
|
|
72
|
+
setErrorKey('Auth.PASSKEY_CANCELLED');
|
|
73
|
+
} else {
|
|
74
|
+
// eslint-disable-next-line no-console
|
|
75
|
+
console.error(err);
|
|
76
|
+
setErrorKey('Auth.PASSKEY_FAILED');
|
|
77
|
+
}
|
|
69
78
|
} finally {
|
|
70
79
|
setSubmitting(false);
|
|
71
80
|
}
|
|
@@ -236,4 +245,3 @@ import { loginWithPasskey } from '../utils/authService';
|
|
|
236
245
|
|
|
237
246
|
};
|
|
238
247
|
|
|
239
|
-
|
package/src/utils/authService.js
CHANGED
|
@@ -36,7 +36,7 @@ export async function registerPasskey(name = 'Passkey') {
|
|
|
36
36
|
export async function loginWithPasskey() {
|
|
37
37
|
ensureWebAuthnSupport();
|
|
38
38
|
|
|
39
|
-
// 1. Get Challenge
|
|
39
|
+
// 1. Get Challenge (für passwordless Login)
|
|
40
40
|
const requestOptions = await getPasskeyLoginOptions();
|
|
41
41
|
|
|
42
42
|
// 2. Browser Sign
|
|
@@ -45,7 +45,11 @@ export async function loginWithPasskey() {
|
|
|
45
45
|
const pubKey = window.PublicKeyCredential.parseRequestOptionsFromJSON(requestOptions);
|
|
46
46
|
assertion = await navigator.credentials.get({ publicKey: pubKey });
|
|
47
47
|
} catch (err) {
|
|
48
|
-
|
|
48
|
+
if (err.name === 'NotAllowedError') {
|
|
49
|
+
throw normaliseApiError(new Error('Auth.PASSKEY_CANCELLED'), 'Auth.PASSKEY_CANCELLED');
|
|
50
|
+
}
|
|
51
|
+
// Wenn der Browser sagt "No credentials found", werfen wir das weiter
|
|
52
|
+
throw err;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
// 3. Complete
|
|
@@ -55,7 +59,6 @@ export async function loginWithPasskey() {
|
|
|
55
59
|
// 4. Reload User
|
|
56
60
|
return fetchCurrentUser();
|
|
57
61
|
}
|
|
58
|
-
|
|
59
62
|
export function startSocialLogin(provider) {
|
|
60
63
|
if (typeof window === 'undefined') {
|
|
61
64
|
throw normaliseApiError(
|