From 83e5b400c363f91c6cd05254ae1bf9bf0bb1c930 Mon Sep 17 00:00:00 2001 From: Anton Liashkevich Date: Thu, 30 Jul 2026 19:03:06 -0400 Subject: [PATCH] Fail fast on empty auth credentials; log real device instance creation errors Previously, if the server approved a device but sent no AppId/AppSecret (e.g. device already marked authorized server-side but the client's local secret store was cleared), the client silently accepted the approval and only failed later in send_authenticate with a vague "AppId not set", causing an infinite reconnect loop instead of surfacing a clear error. await_authorization now falls back to cached credentials and fails immediately if none are available, routing into the existing error-state path. Also, add_device_instance previously swallowed the real error from create_device_instance behind a generic "Failed to create device instance" status. It's now logged alongside the generic client-facing message for easier diagnosis. Co-Authored-By: Claude Sonnet 5 --- .../src/orchestrator/auth_request_handler.rs | 12 ++++++--- .../control_channel/await_authorization.rs | 25 +++++++++++++++---- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/wallguard-server/src/orchestrator/auth_request_handler.rs b/wallguard-server/src/orchestrator/auth_request_handler.rs index d08e567c..23b7bb1a 100644 --- a/wallguard-server/src/orchestrator/auth_request_handler.rs +++ b/wallguard-server/src/orchestrator/auth_request_handler.rs @@ -26,6 +26,11 @@ macro_rules! fail_with_status { let _ = $outbound.send(Err(tonic::Status::internal($msg))).await; return; }}; + ($outbound:expr, $msg:expr, $err:expr) => {{ + log::error!("{}: {}", $msg, $err.to_str()); + let _ = $outbound.send(Err(tonic::Status::internal($msg))).await; + return; + }}; } pub struct AuthReqHandler { @@ -237,12 +242,13 @@ impl AuthReqHandler { ..Default::default() }; - let Ok(instance_id) = context + let instance_id = match context .datastore .create_device_instance(token, &device_instance) .await - else { - fail_with_status!(outbound, "Failed to create device instance") + { + Ok(instance_id) => instance_id, + Err(err) => fail_with_status!(outbound, "Failed to create device instance", err), }; let instance = Arc::new(Mutex::new(Instance::new( diff --git a/wallguard/src/control_channel/await_authorization.rs b/wallguard/src/control_channel/await_authorization.rs index b46f2224..c1cb6e14 100644 --- a/wallguard/src/control_channel/await_authorization.rs +++ b/wallguard/src/control_channel/await_authorization.rs @@ -54,12 +54,27 @@ pub async fn await_authorization( match message { server_message::Message::DeviceAuthorizedMessage(data) => { - if let Some(app_id) = data.app_id { - Storage::set_value(Secret::AppId, &app_id).await?; - } + let app_id = match data.app_id { + Some(app_id) => { + Storage::set_value(Secret::AppId, &app_id).await?; + Some(app_id) + } + None => Storage::get_value(Secret::AppId).await, + }; + + let app_secret = match data.app_secret { + Some(app_secret) => { + Storage::set_value(Secret::AppSecret, &app_secret).await?; + Some(app_secret) + } + None => Storage::get_value(Secret::AppSecret).await, + }; - if let Some(app_secret) = data.app_secret { - Storage::set_value(Secret::AppSecret, &app_secret).await?; + if app_id.is_none() || app_secret.is_none() { + return Err( + "Server approved device without providing credentials, and none are cached locally", + ) + .handle_err(location!()); } Ok(Verdict::Approved)