diff --git a/src/server/connection.rs b/src/server/connection.rs index b67062e8b..c6d67e5fc 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -323,6 +323,7 @@ pub struct Connection { tx_to_cm: mpsc::UnboundedSender, authorized: bool, require_2fa: Option, + awaiting_2fa: bool, keyboard: bool, clipboard: bool, audio: bool, @@ -509,6 +510,7 @@ impl Connection { tx_video: Some(tx_video), }, require_2fa: crate::auth_2fa::get_2fa(None), + awaiting_2fa: false, // Defer display enumeration until login succeeds. Monitor login replaces this // with the primary index returned with the refreshed display snapshot. display_idx: 0, @@ -1678,10 +1680,12 @@ impl Connection { }); } }); + self.awaiting_2fa = true; self.send_login_error(crate::client::REQUIRE_2FA).await; // Keep the connection alive so the client can continue with 2FA. return true; } + self.awaiting_2fa = false; if let Some(keep_alive) = self.prepare_terminal_login_for_authorization().await { return keep_alive; } @@ -2559,6 +2563,7 @@ impl Connection { } // After handling CloseReason messages, proceed to process other message types if let Some(message::Union::LoginRequest(lr)) = msg.union { + self.awaiting_2fa = false; self.handle_login_request_without_validation(&lr).await; if self.authorized { return true; @@ -2791,6 +2796,11 @@ impl Connection { } } } else if let Some(message::Union::Auth2fa(tfa)) = msg.union { + // A 2FA response may arrive after click authorization has completed. + // Ignore it unless this connection is still waiting for the response. + if !self.awaiting_2fa { + return true; + } let (failure, res) = self.check_failure(1).await; if !res { return true;