@@ -369,6 +369,65 @@ async function _portCredentials() {
369369 }
370370}
371371
372+ const FALLBACK_SALT = 'fallback-salt-2f309322-b32d-4d59-85b4-2baef666a9f4' ;
373+ let currentSalt ;
374+
375+ /**
376+ * Attempt to get or create the trusted key (salt) from the credential store.
377+ * Returns the salt string on success, or null if getCredential throws.
378+ */
379+ async function _getTrustedKeyInternal ( ) {
380+ try {
381+ let salt = await getCredential ( SIGNATURE_SALT_KEY ) ;
382+ if ( ! salt ) {
383+ // Generate and store new salt
384+ salt = crypto . randomUUID ( ) ;
385+ await setCredential ( SIGNATURE_SALT_KEY , salt ) ;
386+ }
387+ return salt ;
388+ } catch ( error ) {
389+ console . error ( "Error in _getTrustedKeyInternal:" , error ) ;
390+ return null ;
391+ }
392+ }
393+
394+ const MAX_SALT_RETRIES = 2 ;
395+
396+ /**
397+ * Get per-user trusted key (salt) for signature generation, creating and persisting one if it doesn't exist.
398+ * Used for signing cached data to prevent tampering.
399+ */
400+ async function getTrustedKey ( ) {
401+ if ( currentSalt ) {
402+ return currentSalt ;
403+ }
404+
405+ if ( Phoenix . isNativeApp ) {
406+ // Native app: use credential store with retries
407+ let salt = await _getTrustedKeyInternal ( ) ;
408+ const Metrics = window . Metrics ;
409+ for ( let i = 0 ; i < MAX_SALT_RETRIES && ! salt ; i ++ ) {
410+ console . warn ( `Retrying _getTrustedKeyInternal (attempt ${ i + 2 } )` ) ;
411+ Metrics && Metrics . countEvent ( Metrics . EVENT_TYPE . AUTH , "saltGet" , "retry" ) ;
412+ salt = await _getTrustedKeyInternal ( ) ;
413+ }
414+ if ( salt ) {
415+ currentSalt = salt ;
416+ return salt ;
417+ }
418+ // All retries exhausted, fall back
419+ console . error ( "All salt retrieval attempts failed, using fallback salt" ) ;
420+ Metrics && Metrics . countEvent ( Metrics . EVENT_TYPE . AUTH , "saltGet" , "Err" ) ;
421+ currentSalt = FALLBACK_SALT ;
422+ return FALLBACK_SALT ;
423+ }
424+
425+ // In browser app, there is no way to securely store salt without extensions being able to
426+ // read it. Return a static salt for basic integrity checking.
427+ currentSalt = FALLBACK_SALT ;
428+ return FALLBACK_SALT ;
429+ }
430+
372431/**
373432 * Generates an SHA-256 hash signature of the provided data string combined with a salt.
374433 *
@@ -418,7 +477,8 @@ window.KernalModeTrust = {
418477 dismantleKeyring,
419478 generateDataSignature,
420479 validateDataSignature,
421- reinstallCreds
480+ reinstallCreds,
481+ getTrustedKey
422482} ;
423483// Pass the trust ring reference to phoenix-builder (MCP) before it is
424484// nuked from window. The builder needs dismantleKeyring() for reload.
0 commit comments