UNPKG

ndwallet-core

Version:

Core cryptographic library for NDWallet browser environments

115 lines (114 loc) 4.13 kB
/** * Dynamically load browser dependencies */ export async function loadBrowserDependencies() { console.log('Loading browser dependencies...'); const { startRegistration, startAuthentication } = await import('@simplewebauthn/browser'); return { startRegistration, startAuthentication }; } /** * Check if the WebAuthn PRF extension is supported by the browser * @returns Promise resolving to a boolean indicating if PRF is supported */ export async function isPrfExtensionSupported() { try { // Check if PublicKeyCredential is available if (typeof window === 'undefined' || !window.PublicKeyCredential) { return false; } // Check if the PRF extension is supported // @ts-ignore - isUserVerifyingPlatformAuthenticatorAvailable is not in the type definitions return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(); } catch (error) { console.error('Error checking PRF extension support:', error); return false; } } /** * Generate WebAuthn registration options with PRF extension * @param baseOptions - Base registration options from the server * @param salt - Salt for PRF extension (optional, will generate if not provided) * @returns Modified options with PRF extension */ export function addPrfExtensionToRegistrationOptions(baseOptions, salt) { // Generate a random salt if not provided const prfSalt = salt || crypto.getRandomValues(new Uint8Array(32)); // Create a copy of the options const options = JSON.parse(JSON.stringify(baseOptions)); // Add PRF extension if (!options.extensions) { options.extensions = {}; } options.extensions.prf = { eval: { first: prfSalt } }; return options; } /** * Generate WebAuthn authentication options with PRF extension * @param baseOptions - Base authentication options from the server * @param salt - Salt for PRF extension (must be the same as used during registration) * @returns Modified options with PRF extension */ export function addPrfExtensionToAuthenticationOptions(baseOptions, salt) { // Create a copy of the options const options = JSON.parse(JSON.stringify(baseOptions)); // Add PRF extension if (!options.extensions) { options.extensions = {}; } options.extensions.prf = { eval: { first: salt } }; return options; } /** * Extract PRF output from WebAuthn response * @param response - WebAuthn response from registration or authentication * @returns PRF output as Uint8Array or null if not available */ function _extractPrfOutput(response) { try { const prf = response.clientExtensionResults?.prf; if (!prf || !prf.results || !prf.results.first) { console.log('PRF extension not available in response:', prf); return null; } return prf.results.first; } catch (error) { console.error('Error extracting PRF output:', error); return null; } } /** * Derive a master key using the WebAuthn PRF extension * @param response - WebAuthn response from registration or authentication * @returns Promise resolving to a CryptoKey that can be used for key derivation * @throws {Error} If PRF extension is not supported or response is invalid */ export async function deriveMasterKeyFromPrf(response) { try { // Extract PRF output const prfOutput = _extractPrfOutput(response); if (!prfOutput) { throw new Error('No PRF output found in response. Make sure PRF extension was requested and is supported.'); } // Import as a CryptoKey for key derivation return await crypto.subtle.importKey('raw', prfOutput, { name: 'HKDF' }, false, ['deriveKey']); } catch (error) { console.error('Error deriving master key from PRF:', error); if (error instanceof Error) { throw error; } else { throw new Error(`Failed to derive master key from PRF: ${String(error)}`); } } }