| import { apiRequest } from './client' |
| import { setActiveUser, setToken } from '../auth/session' |
| import { |
| serializeAssertion, serializeRegistration, toCreationOptions, toRequestOptions, |
| isWebAuthnSupported, PasskeyCancelled, PasskeyUnsupported, |
| } from '../auth/passkey' |
| import type { DemoSeedResponse, EnrollResponse } from '../types' |
|
|
| |
| |
| export async function demoSeed(userId: string): Promise<DemoSeedResponse> { |
| const r = await apiRequest<DemoSeedResponse>('/demo/seed', { body: { user_id: userId } }) |
| if (r.token) setToken(r.token) |
| setActiveUser({ userId: r.user_id, via: 'demo' }) |
| return r |
| } |
|
|
| export async function enrollUnified( |
| userId: string, |
| faceImage: string, |
| fingerprintImage?: string, |
| ): Promise<EnrollResponse> { |
| const body: Record<string, string> = { user_id: userId, face_image: faceImage } |
| if (fingerprintImage) body.fingerprint_image = fingerprintImage |
| const r = await apiRequest<EnrollResponse>('/unified/enroll', { body }) |
| if (r.token) setToken(r.token) |
| return r |
| } |
|
|
| |
| export async function registerPasskey(userId: string): Promise<boolean> { |
| if (!isWebAuthnSupported()) throw new PasskeyUnsupported('WebAuthn not supported') |
| const options = await apiRequest<Record<string, unknown>>('/webauthn/register/begin', { |
| body: { user_id: userId }, |
| }) |
| let cred: PublicKeyCredential | null |
| try { |
| cred = (await navigator.credentials.create(toCreationOptions(options))) as PublicKeyCredential | null |
| } catch (e) { |
| throw new PasskeyCancelled((e as Error)?.name ?? 'cancelled') |
| } |
| if (!cred) throw new PasskeyCancelled('no credential') |
| const r = await apiRequest<{ success: boolean }>('/webauthn/register/complete', { |
| body: { user_id: userId, credential: serializeRegistration(cred) }, |
| }) |
| return !!r.success |
| } |
|
|
| export async function authenticatePasskey(userId: string): Promise<boolean> { |
| if (!isWebAuthnSupported()) throw new PasskeyUnsupported('WebAuthn not supported') |
| const options = await apiRequest<Record<string, unknown>>('/webauthn/authenticate/begin', { |
| body: { user_id: userId }, |
| }) |
| let cred: PublicKeyCredential | null |
| try { |
| cred = (await navigator.credentials.get(toRequestOptions(options))) as PublicKeyCredential | null |
| } catch (e) { |
| throw new PasskeyCancelled((e as Error)?.name ?? 'cancelled') |
| } |
| if (!cred) throw new PasskeyCancelled('no credential') |
| const r = await apiRequest<{ success: boolean }>('/webauthn/authenticate/complete', { |
| body: { user_id: userId, credential: serializeAssertion(cred) }, |
| }) |
| |
| |
| |
| if (r.success) setActiveUser({ userId, via: 'passkey' }) |
| return !!r.success |
| } |
|
|