From 493b867044ba3942b9c7accea41efbc81a6d6b54 Mon Sep 17 00:00:00 2001 From: Rafabd1 Date: Sat, 14 Mar 2026 01:31:14 -0300 Subject: [PATCH] fix: add error handling in message receive loop (#9) - Treat decryption errors as fatal - close session immediately on ratchet decrypt failures - Emit decryption_error event with user-visible error message when decryption fails - Log decryption attempt context (counter value) in debug builds for troubleshooting - Improve error messages to include ratchet counter information for debugging - Close session and emit session_closed event when decryption errors occur This fixes issue #9 where decryption errors in the receive loop were silently ignored, allowing the session to continue in an inconsistent state. Now decryption failures are treated as fatal security events that immediately terminate the session. --- src-tauri/src/commands/session.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src-tauri/src/commands/session.rs b/src-tauri/src/commands/session.rs index 9bb7c40..8f23302 100644 --- a/src-tauri/src/commands/session.rs +++ b/src-tauri/src/commands/session.rs @@ -436,9 +436,17 @@ async fn receive_loop(app: AppHandle, mut reader: tokio::io::ReadHalf { if let Err(e) = handle_incoming_message(&app, &frame).await { + // Decryption errors are fatal - close session and notify user + let error_msg = format!("Decryption failed: {}", e); + let _ = app.emit("decryption_error", error_msg); + + let state = app.state::(); + *state.session.lock().await = None; + let _ = app.emit("session_closed", ()); + #[cfg(debug_assertions)] - log::warn!("message handling error: {}", e); - let _ = e; + log::warn!("decryption error - closing session: {}", e); + break; } } Err(e) => { @@ -478,7 +486,12 @@ async fn handle_incoming_message(app: &AppHandle, frame: &[u8]) -> anyhow::Resul let plaintext_buf = { let mut sess = state.session.lock().await; let session = sess.as_mut().ok_or_else(|| anyhow::anyhow!("no session"))?; - session.ratchet.decrypt(&ct, wire.n)? + // Log decryption attempt with context for debugging + #[cfg(debug_assertions)] + log::debug!("attempting to decrypt message with counter={}", wire.n); + + session.ratchet.decrypt(&ct, wire.n) + .map_err(|e| anyhow::anyhow!("ratchet decrypt failed (counter={}): {}", wire.n, e))? }; let mut content = String::from_utf8(plaintext_buf.as_bytes().to_vec())?;