UNPKG

capacitor-biometric-authentication

Version:

Framework-agnostic biometric authentication library. Works with React, Vue, Angular, or vanilla JS. No providers required!

181 lines (160 loc) 5.42 kB
import { WebAuthnCreateOptions, WebAuthnGetOptions } from '../definitions'; import { toArrayBuffer, generateChallenge, } from './encoding'; // Re-export encoding utilities for backward compatibility export { toArrayBuffer, arrayBufferToBase64, arrayBufferToBase64URL, base64ToArrayBuffer, base64URLToArrayBuffer, generateChallenge, generateSessionId, } from './encoding'; /** * Merge user-provided WebAuthn create options with defaults */ export function mergeCreateOptions( userOptions?: WebAuthnCreateOptions, defaults?: Partial<PublicKeyCredentialCreationOptions> ): PublicKeyCredentialCreationOptions { const challenge = toArrayBuffer(userOptions?.challenge) || generateChallenge(); const options: PublicKeyCredentialCreationOptions = { challenge, rp: { name: userOptions?.rp?.name || defaults?.rp?.name || window.location.hostname, id: userOptions?.rp?.id || defaults?.rp?.id || window.location.hostname, }, user: { id: toArrayBuffer(userOptions?.user?.id) || (defaults?.user?.id instanceof ArrayBuffer || defaults?.user?.id instanceof Uint8Array ? toArrayBuffer(defaults.user.id) : undefined) || crypto.getRandomValues(new Uint8Array(16)).buffer, name: userOptions?.user?.name || defaults?.user?.name || `user@${window.location.hostname}`, displayName: userOptions?.user?.displayName || defaults?.user?.displayName || 'User', }, pubKeyCredParams: userOptions?.pubKeyCredParams || defaults?.pubKeyCredParams || [ { alg: -7, type: 'public-key' }, // ES256 { alg: -257, type: 'public-key' }, // RS256 ], timeout: userOptions?.timeout || defaults?.timeout || 60000, attestation: userOptions?.attestation || defaults?.attestation || 'none', }; // Add optional properties if provided if (userOptions?.authenticatorSelection || defaults?.authenticatorSelection) { options.authenticatorSelection = { ...defaults?.authenticatorSelection, ...userOptions?.authenticatorSelection, }; } if (userOptions?.attestationFormats) { (options as { attestationFormats?: string[] }).attestationFormats = userOptions.attestationFormats; } if (userOptions?.excludeCredentials) { options.excludeCredentials = userOptions.excludeCredentials.map((cred) => ({ ...cred, id: toArrayBuffer(cred.id)!, })); } if (userOptions?.extensions) { options.extensions = userOptions.extensions; } if (userOptions?.hints) { (options as { hints?: string[] }).hints = userOptions.hints; } return options; } /** * Merge user-provided WebAuthn get options with defaults */ export function mergeGetOptions( userOptions?: WebAuthnGetOptions, defaults?: Partial<PublicKeyCredentialRequestOptions> ): PublicKeyCredentialRequestOptions { const challenge = toArrayBuffer(userOptions?.challenge) || generateChallenge(); const options: PublicKeyCredentialRequestOptions = { challenge, timeout: userOptions?.timeout || defaults?.timeout || 60000, }; // Add optional properties if provided if (userOptions?.rpId || defaults?.rpId) { options.rpId = userOptions?.rpId || defaults?.rpId; } if (userOptions?.allowCredentials || defaults?.allowCredentials) { const userCreds = userOptions?.allowCredentials || []; const defaultCreds = defaults?.allowCredentials || []; options.allowCredentials = [...userCreds, ...defaultCreds].map((cred) => ({ type: 'public-key' as PublicKeyCredentialType, id: toArrayBuffer(cred.id as string | ArrayBuffer | Uint8Array)!, transports: cred.transports, })) as PublicKeyCredentialDescriptor[]; } if (userOptions?.userVerification || defaults?.userVerification) { options.userVerification = userOptions?.userVerification || defaults?.userVerification; } if (userOptions?.extensions || defaults?.extensions) { options.extensions = { ...defaults?.extensions, ...userOptions?.extensions, }; } if (userOptions?.hints) { (options as { hints?: string[] }).hints = userOptions.hints; } return options; } /** * Store credential ID in localStorage for future authentication */ export function storeCredentialId(credentialId: string, userId?: string): void { const key = userId ? `biometric_auth_cred_${userId}` : 'biometric_auth_cred_default'; const existingCreds = getStoredCredentialIds(userId); if (!existingCreds.includes(credentialId)) { existingCreds.push(credentialId); localStorage.setItem(key, JSON.stringify(existingCreds)); } } /** * Get stored credential IDs from localStorage */ export function getStoredCredentialIds(userId?: string): string[] { const key = userId ? `biometric_auth_cred_${userId}` : 'biometric_auth_cred_default'; try { const stored = localStorage.getItem(key); return stored ? JSON.parse(stored) : []; } catch { return []; } } /** * Clear stored credential IDs */ export function clearStoredCredentialIds(userId?: string): void { if (userId) { localStorage.removeItem(`biometric_auth_cred_${userId}`); } else { // Clear all credential keys const keys = Object.keys(localStorage).filter((key) => key.startsWith('biometric_auth_cred_') ); keys.forEach((key) => localStorage.removeItem(key)); } }