@micha.bigler/ui-core-micha 1.4.32 → 1.4.33

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,7 +1,7 @@
1
- // src/utils/authService.js
2
- import { getPasskeyRegistrationOptions, completePasskeyRegistration, getPasskeyLoginOptions, completePasskeyLogin, fetchCurrentUser } from '../auth/authApi';
1
+ import { getPasskeyRegistrationOptions, completePasskeyRegistration, getPasskeyLoginOptions, completePasskeyLogin, fetchCurrentUser, authenticateWithMFA } from '../auth/authApi';
3
2
  import { ensureWebAuthnSupport, serializeCredential } from '../utils/webauthn';
4
3
  import { normaliseApiError } from '../utils/auth-errors';
4
+ import apiClient from '../auth/apiClient';
5
5
  export async function registerPasskey(name = 'Passkey') {
6
6
  ensureWebAuthnSupport();
7
7
  // 1. Get Options from Server
@@ -9,11 +9,10 @@ export async function registerPasskey(name = 'Passkey') {
9
9
  // 2. Call Browser API
10
10
  let credential;
11
11
  try {
12
- // Note: Parse JSON to Options needs a helper if creationOptions is raw JSON strings
13
- // modern browsers/allauth usually provide correct types, but check your library version
14
- // For standard Allauth headless, you might need window.PublicKeyCredential.parseCreationOptionsFromJSON
15
- const pubKey = window.PublicKeyCredential.parseCreationOptionsFromJSON(creationOptions);
16
- credential = await navigator.credentials.create({ publicKey: pubKey });
12
+ // FIX: options enthält bereits die korrekte Struktur für create()
13
+ const options = window.PublicKeyCredential.parseCreationOptionsFromJSON(creationOptions);
14
+ // FIX: Kein manuelles { publicKey: ... } Wrapping mehr!
15
+ credential = await navigator.credentials.create(options);
17
16
  }
18
17
  catch (err) {
19
18
  if (err.name === 'NotAllowedError') {
@@ -27,19 +26,20 @@ export async function registerPasskey(name = 'Passkey') {
27
26
  }
28
27
  export async function loginWithPasskey() {
29
28
  ensureWebAuthnSupport();
30
- // 1. Get Challenge (für passwordless Login)
29
+ // 1. Get Challenge
31
30
  const requestOptions = await getPasskeyLoginOptions();
32
31
  // 2. Browser Sign
33
32
  let assertion;
34
33
  try {
35
- const pubKey = window.PublicKeyCredential.parseRequestOptionsFromJSON(requestOptions);
36
- assertion = await navigator.credentials.get({ publicKey: pubKey });
34
+ // FIX: options enthält bereits die korrekte Struktur für get()
35
+ const options = window.PublicKeyCredential.parseRequestOptionsFromJSON(requestOptions);
36
+ // FIX: Kein manuelles { publicKey: ... } Wrapping mehr!
37
+ assertion = await navigator.credentials.get(options);
37
38
  }
38
39
  catch (err) {
39
40
  if (err.name === 'NotAllowedError') {
40
41
  throw normaliseApiError(new Error('Auth.PASSKEY_CANCELLED'), 'Auth.PASSKEY_CANCELLED');
41
42
  }
42
- // Wenn der Browser sagt "No credentials found", werfen wir das weiter
43
43
  throw err;
44
44
  }
45
45
  // 3. Complete
@@ -48,10 +48,44 @@ export async function loginWithPasskey() {
48
48
  // 4. Reload User
49
49
  return fetchCurrentUser();
50
50
  }
51
+ /**
52
+ * WebAuthn als 2. Faktor nutzen (wenn Passwort schon eingegeben wurde).
53
+ */
54
+ export async function authenticateMfaWithPasskey() {
55
+ var _a;
56
+ ensureWebAuthnSupport();
57
+ let requestOptions;
58
+ try {
59
+ const res = await apiClient.get('/api/auth/browser/v1/auth/2fa/authenticate');
60
+ const data = ((_a = res.data) === null || _a === void 0 ? void 0 : _a.data) || res.data;
61
+ requestOptions = data.request_options || data;
62
+ }
63
+ catch (err) {
64
+ throw normaliseApiError(err, 'Auth.MFA_CHALLENGE_FAILED');
65
+ }
66
+ if (!requestOptions) {
67
+ throw new Error('No WebAuthn challenge received for MFA.');
68
+ }
69
+ // 2. Browser Sign
70
+ let assertion;
71
+ try {
72
+ const options = window.PublicKeyCredential.parseRequestOptionsFromJSON(requestOptions);
73
+ // FIX: Kein manuelles Wrapping
74
+ assertion = await navigator.credentials.get(options);
75
+ }
76
+ catch (err) {
77
+ if (err.name === 'NotAllowedError') {
78
+ throw normaliseApiError(new Error('Auth.PASSKEY_CANCELLED'), 'Auth.PASSKEY_CANCELLED');
79
+ }
80
+ throw err;
81
+ }
82
+ // 3. Authenticate via existing API function
83
+ const credentialJson = serializeCredential(assertion);
84
+ return authenticateWithMFA({ credential: credentialJson });
85
+ }
51
86
  export function startSocialLogin(provider) {
52
87
  if (typeof window === 'undefined') {
53
88
  throw normaliseApiError(new Error('Auth.SOCIAL_LOGIN_NOT_IN_BROWSER'), 'Auth.SOCIAL_LOGIN_NOT_IN_BROWSER');
54
89
  }
55
- // Browser-Redirect ist ein Side-Effect -> Service Layer
56
90
  window.location.href = `/accounts/${provider}/login/?process=login`;
57
91
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@micha.bigler/ui-core-micha",
3
- "version": "1.4.32",
3
+ "version": "1.4.33",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "private": false,
@@ -1,11 +1,18 @@
1
- // src/utils/authService.js
2
- import { getPasskeyRegistrationOptions, completePasskeyRegistration, getPasskeyLoginOptions, completePasskeyLogin, fetchCurrentUser } from '../auth/authApi';
1
+ import {
2
+ getPasskeyRegistrationOptions,
3
+ completePasskeyRegistration,
4
+ getPasskeyLoginOptions,
5
+ completePasskeyLogin,
6
+ fetchCurrentUser,
7
+ authenticateWithMFA
8
+ } from '../auth/authApi';
3
9
 
4
10
  import {
5
11
  ensureWebAuthnSupport,
6
12
  serializeCredential
7
13
  } from '../utils/webauthn';
8
14
  import { normaliseApiError } from '../utils/auth-errors';
15
+ import apiClient from '../auth/apiClient';
9
16
 
10
17
  export async function registerPasskey(name = 'Passkey') {
11
18
  ensureWebAuthnSupport();
@@ -16,11 +23,10 @@ export async function registerPasskey(name = 'Passkey') {
16
23
  // 2. Call Browser API
17
24
  let credential;
18
25
  try {
19
- // Note: Parse JSON to Options needs a helper if creationOptions is raw JSON strings
20
- // modern browsers/allauth usually provide correct types, but check your library version
21
- // For standard Allauth headless, you might need window.PublicKeyCredential.parseCreationOptionsFromJSON
22
- const pubKey = window.PublicKeyCredential.parseCreationOptionsFromJSON(creationOptions);
23
- credential = await navigator.credentials.create({ publicKey: pubKey });
26
+ // FIX: options enthält bereits die korrekte Struktur für create()
27
+ const options = window.PublicKeyCredential.parseCreationOptionsFromJSON(creationOptions);
28
+ // FIX: Kein manuelles { publicKey: ... } Wrapping mehr!
29
+ credential = await navigator.credentials.create(options);
24
30
  } catch (err) {
25
31
  if (err.name === 'NotAllowedError') {
26
32
  throw normaliseApiError(new Error('Auth.PASSKEY_CANCELLED'), 'Auth.PASSKEY_CANCELLED');
@@ -36,19 +42,20 @@ export async function registerPasskey(name = 'Passkey') {
36
42
  export async function loginWithPasskey() {
37
43
  ensureWebAuthnSupport();
38
44
 
39
- // 1. Get Challenge (für passwordless Login)
45
+ // 1. Get Challenge
40
46
  const requestOptions = await getPasskeyLoginOptions();
41
47
 
42
48
  // 2. Browser Sign
43
49
  let assertion;
44
50
  try {
45
- const pubKey = window.PublicKeyCredential.parseRequestOptionsFromJSON(requestOptions);
46
- assertion = await navigator.credentials.get({ publicKey: pubKey });
51
+ // FIX: options enthält bereits die korrekte Struktur für get()
52
+ const options = window.PublicKeyCredential.parseRequestOptionsFromJSON(requestOptions);
53
+ // FIX: Kein manuelles { publicKey: ... } Wrapping mehr!
54
+ assertion = await navigator.credentials.get(options);
47
55
  } catch (err) {
48
56
  if (err.name === 'NotAllowedError') {
49
57
  throw normaliseApiError(new Error('Auth.PASSKEY_CANCELLED'), 'Auth.PASSKEY_CANCELLED');
50
58
  }
51
- // Wenn der Browser sagt "No credentials found", werfen wir das weiter
52
59
  throw err;
53
60
  }
54
61
 
@@ -59,6 +66,44 @@ export async function loginWithPasskey() {
59
66
  // 4. Reload User
60
67
  return fetchCurrentUser();
61
68
  }
69
+
70
+ /**
71
+ * WebAuthn als 2. Faktor nutzen (wenn Passwort schon eingegeben wurde).
72
+ */
73
+ export async function authenticateMfaWithPasskey() {
74
+ ensureWebAuthnSupport();
75
+
76
+ let requestOptions;
77
+ try {
78
+ const res = await apiClient.get('/api/auth/browser/v1/auth/2fa/authenticate');
79
+ const data = res.data?.data || res.data;
80
+ requestOptions = data.request_options || data;
81
+ } catch (err) {
82
+ throw normaliseApiError(err, 'Auth.MFA_CHALLENGE_FAILED');
83
+ }
84
+
85
+ if (!requestOptions) {
86
+ throw new Error('No WebAuthn challenge received for MFA.');
87
+ }
88
+
89
+ // 2. Browser Sign
90
+ let assertion;
91
+ try {
92
+ const options = window.PublicKeyCredential.parseRequestOptionsFromJSON(requestOptions);
93
+ // FIX: Kein manuelles Wrapping
94
+ assertion = await navigator.credentials.get(options);
95
+ } catch (err) {
96
+ if (err.name === 'NotAllowedError') {
97
+ throw normaliseApiError(new Error('Auth.PASSKEY_CANCELLED'), 'Auth.PASSKEY_CANCELLED');
98
+ }
99
+ throw err;
100
+ }
101
+
102
+ // 3. Authenticate via existing API function
103
+ const credentialJson = serializeCredential(assertion);
104
+ return authenticateWithMFA({ credential: credentialJson });
105
+ }
106
+
62
107
  export function startSocialLogin(provider) {
63
108
  if (typeof window === 'undefined') {
64
109
  throw normaliseApiError(
@@ -66,6 +111,5 @@ export function startSocialLogin(provider) {
66
111
  'Auth.SOCIAL_LOGIN_NOT_IN_BROWSER'
67
112
  );
68
113
  }
69
- // Browser-Redirect ist ein Side-Effect -> Service Layer
70
114
  window.location.href = `/accounts/${provider}/login/?process=login`;
71
- }
115
+ }