From e1f62c949d5f28e10882ad6d9daa05b1888bc9bd Mon Sep 17 00:00:00 2001 From: NimBold Date: Wed, 24 Jun 2026 22:00:12 +0330 Subject: [PATCH] fix(backend): hydrate session token without triggering keychain prompts This fixes a severe issue where 'hydrate_pairing_token' was hardcoded to fetch from the keychain on startup and via the 'hydrate_extension_pairing_token' command. This caused multiple macOS keychain prompts to appear back-to-back before the app even loaded. We now correctly check the user's 'keychainAccessGranted' preference from the DB payload and skip keychain operations entirely if they haven't explicitly granted access yet. --- src-tauri/src/db.rs | 14 ++++++++++++++ src-tauri/src/lib.rs | 9 +++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src-tauri/src/db.rs b/src-tauri/src/db.rs index 718a4c3..cb749b4 100644 --- a/src-tauri/src/db.rs +++ b/src-tauri/src/db.rs @@ -549,6 +549,20 @@ pub fn load_settings(connection: &Connection) -> Result, String> .map_err(|error| format!("failed to load settings: {error}")) } +pub fn is_keychain_access_granted(connection: &Connection) -> Result { + let Some(settings) = load_settings(connection)? else { + return Ok(false); + }; + let document: Value = serde_json::from_str(&settings) + .map_err(|error| format!("failed to decode settings: {error}"))?; + let granted = document + .get("state") + .and_then(|s| s.get("keychainAccessGranted")) + .and_then(|v| v.as_bool()) + .unwrap_or(false); + Ok(granted) +} + pub fn save_settings(connection: &Connection, data: &str) -> Result<(), String> { connection .execute( diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 6320e21..7226593 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -3069,7 +3069,8 @@ fn hydrate_extension_pairing_token( app_state: tauri::State<'_, AppState>, ) -> Result { let mut connection = database.lock()?; - match crate::db::hydrate_pairing_token(&mut connection, false) { + let skip_keychain = !crate::db::is_keychain_access_granted(&connection).unwrap_or(false); + match crate::db::hydrate_pairing_token(&mut connection, skip_keychain) { Ok((token, token_changed)) => { if let Ok(mut pairing_token) = app_state.extension_pairing_token.write() { *pairing_token = token.clone(); @@ -3077,7 +3078,7 @@ fn hydrate_extension_pairing_token( Ok(PairingTokenHydration { token, token_changed, - persistent: true, + persistent: !skip_keychain, error: None, }) } @@ -3893,7 +3894,6 @@ pub fn run() { log::info!("Memory: {} MB total", sys.total_memory() / 1024 / 1024); log::info!("App Version: {}", env!("CARGO_PKG_VERSION")); log::info!("=========================="); - build_main_tray(app.handle()) .map_err(|error| format!("failed to create tray menu: {error}"))?; @@ -3901,7 +3901,8 @@ pub fn run() { .map_err(|error| format!("failed to initialize persistence: {error}"))?; let initial_pairing_token = { let mut connection = database.lock()?; - match crate::db::hydrate_pairing_token(&mut connection, false) { + let skip_keychain = !crate::db::is_keychain_access_granted(&connection).unwrap_or(false); + match crate::db::hydrate_pairing_token(&mut connection, skip_keychain) { Ok((token, _)) => token, Err(error) => { log::warn!(