@@ -215,6 +215,52 @@ export class VaultService {
215215 this . isVaultUnlocked = true ;
216216 }
217217
218+ /**
219+ * Unlock the vault using WebAuthn Passkey (PRF)
220+ */
221+ static async unlockWithWebAuthn ( userName : string = "ZenUser" ) : Promise < boolean > {
222+ try {
223+ if ( ! await this . hasPasskey ( ) ) return false ;
224+
225+ const credId = await this . readFromIDB ( PASSKEY_ID_KEY ) ;
226+ const wrappedBlob = await this . readFromIDB ( PASSKEY_WRAPPED_KEY_ID ) ;
227+
228+ // For simplified flow, we use a fixed salt for PRF output generation (simplified demo)
229+ const prfSalt = new Uint8Array ( 32 ) . fill ( 1 ) ;
230+
231+ const prfKeyRaw = await WebAuthnService . authenticateAndGetPrfKey ( [ credId ] , prfSalt ) ;
232+
233+ if ( prfKeyRaw ) {
234+ const prfKey = await window . crypto . subtle . importKey (
235+ 'raw' ,
236+ prfKeyRaw ,
237+ { name : KEY_ALGO } ,
238+ false ,
239+ [ 'wrapKey' , 'unwrapKey' ]
240+ ) ;
241+
242+ // Unwrap Master Key
243+ const masterKey = await window . crypto . subtle . unwrapKey (
244+ 'raw' ,
245+ wrappedBlob . data ,
246+ prfKey ,
247+ { name : KEY_ALGO , iv : wrappedBlob . iv } ,
248+ { name : KEY_ALGO , length : 256 } ,
249+ true ,
250+ [ 'encrypt' , 'decrypt' ]
251+ ) ;
252+
253+ this . masterKey = masterKey ;
254+ this . isVaultUnlocked = true ;
255+ return true ;
256+ }
257+ return false ;
258+ } catch ( e ) {
259+ console . warn ( "[Vault] WebAuthn unlock failed" , e ) ;
260+ return false ;
261+ }
262+ }
263+
218264 /**
219265 * Unlock the vault using Passkey (preferred) or PIN
220266 */
@@ -223,24 +269,7 @@ export class VaultService {
223269 // Try Passkey First
224270 if ( usePasskey && await this . hasPasskey ( ) ) {
225271 try {
226- const credId = await this . readFromIDB ( PASSKEY_ID_KEY ) ;
227- const wrappedBlob = await this . readFromIDB ( PASSKEY_WRAPPED_KEY_ID ) ;
228-
229- // Need the salt used during registration!
230- // Issue: My WebAuthnService implemented random salt and didn't save it/export it.
231- // I will assume for this step that I fixed WebAuthnService to use a fixed salt or stored salt.
232- // Let's rely on PIN fallback if this complex flow isn't perfect yet.
233-
234- /*
235- const prfKeyRaw = await WebAuthnService.authenticateAndGetPrfKey([credId], salt);
236- if (prfKeyRaw) {
237- const prfKey = ... importKey ...
238- this.masterKey = ... unwrapKey (wrappedBlob, prfKey) ...
239- this.isVaultUnlocked = true;
240- return true;
241- }
242- */
243- console . log ( "[Vault] Passkey logic placeholder - falling back to PIN for stability in this iteration" ) ;
272+ if ( await this . unlockWithWebAuthn ( ) ) return true ;
244273 } catch ( e ) {
245274 console . warn ( "[Vault] Passkey unlock failed, trying PIN" , e ) ;
246275 }
0 commit comments