diff --git a/ak-agent-desktop/src-tauri/src/cmd/version.rs b/ak-agent-desktop/src-tauri/src/cmd/version.rs index 2f7037dff..0be488ec6 100644 --- a/ak-agent-desktop/src-tauri/src/cmd/version.rs +++ b/ak-agent-desktop/src-tauri/src/cmd/version.rs @@ -1,6 +1,7 @@ use ak_platform::{ generated::ping::ping_client::PingClient, grpc::grpc_endpoint, + http::ReqwestResponseError, paths::{SysdSocketID, sysd_socket_path}, string::PlatformString, }; @@ -89,10 +90,11 @@ async fn latest_version() -> Option { .get(VERSION_URL) .send() .await? - .error_for_status()? + .error_with_response() + .await? .json() .await?; - reqwest::Result::Ok(info.stable) + eyre::Ok(info.stable) } .await .inspect_err(|e| tracing::debug!("version check failed: {e:?}")) diff --git a/ak-agent/src/grpc/agent_auth.rs b/ak-agent/src/grpc/agent_auth.rs index e97577c94..769c27c6b 100644 --- a/ak-agent/src/grpc/agent_auth.rs +++ b/ak-agent/src/grpc/agent_auth.rs @@ -8,6 +8,7 @@ use ak_platform::{ agent_auth_server::AgentAuth, current_token_request::Type, }, }, + http::ReqwestResponseError, net::server::{creds::ProcCredentials, proc_info::process_user}, oauth2_http, string::PlatformString, @@ -141,9 +142,10 @@ impl AgentAuth for AgentGRPCServer { Ok(r) => r, Err(e) => return Err(Status::from_error(e.into())), }; - if !req.status().is_success() { - return Err(Status::internal("Invalid status code for whoami request")); - } + let req = req + .error_with_response() + .await + .map_err(|e| Status::internal(format!("whoami request failed: {e}")))?; Ok(Response::new(WhoAmIResponse { header: Some(ResponseHeader { successful: true }), @@ -368,12 +370,10 @@ impl AgentGRPCServer { .body(body) .send() .await - .map_err(|e| Status::from_error(e.into()))?; - - if !res.status().is_success() { - let body = res.text().await.unwrap_or_default(); - return Err(Status::internal(format!("token exchange failed: {body}"))); - } + .map_err(|e| Status::from_error(e.into()))? + .error_with_response() + .await + .map_err(|e| Status::internal(format!("token exchange failed: {e}")))?; let new_token: OAuthTokenResponse = res.json().await.map_err(|e| Status::from_error(e.into()))?; diff --git a/ak-agent/src/ssh/txn.rs b/ak-agent/src/ssh/txn.rs index 8331ab897..f1b23bb7a 100644 --- a/ak-agent/src/ssh/txn.rs +++ b/ak-agent/src/ssh/txn.rs @@ -1,7 +1,9 @@ use std::sync::Arc; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use ak_platform::{net::server::creds::ProcCredentials, string::PlatformString}; +use ak_platform::{ + http::ReqwestResponseError, net::server::creds::ProcCredentials, string::PlatformString, +}; use ak_platform_authz::AuthorizeAction; use authentik_client::apis::endpoints_api::endpoints_agents_connectors_auth_fed_create; use eyre::{Result, WrapErr, bail}; @@ -170,7 +172,8 @@ impl SSHAgentTransaction { .get(userinfo_url) .send() .await? - .error_for_status()?; + .error_with_response() + .await?; Ok(response.json::().await?.preferred_username) } diff --git a/ak-agent/src/token/profile.rs b/ak-agent/src/token/profile.rs index c6e062938..658cd145c 100644 --- a/ak-agent/src/token/profile.rs +++ b/ak-agent/src/token/profile.rs @@ -2,13 +2,14 @@ use std::sync::Arc; use std::time::Duration; use ak_meta::user_agent; +use ak_platform::http::ReqwestResponseError; use ak_platform::shared::AuthentikClaims; use chrono::{TimeDelta, Utc}; use jsonwebtoken::{DecodingKey, Validation, decode, decode_header, jwk::JwkSet}; use tokio::sync::{Notify, RwLock}; use ak_platform::storage::cfgmgr::ConfigManager; -use eyre::{Result, bail}; +use eyre::{Result, WrapErr}; use crate::config::ConfigV1; use crate::token::Token; @@ -249,14 +250,15 @@ impl ProfileTokenManager { req = req.header("DPoP", proof); } - let res = req.body(body).send().await?; - - if !res.status().is_success() { - let body = res.text().await?; - bail!("token renewal failed: {body}"); - } - - let new_token: Token = res.json().await?; + let new_token: Token = req + .body(body) + .send() + .await? + .error_with_response() + .await + .wrap_err("token renewal failed")? + .json() + .await?; { let mut config = self.cfg.write().await; diff --git a/ak-cli/src/auth/claude.rs b/ak-cli/src/auth/claude.rs index 424151a51..52f5decc9 100644 --- a/ak-cli/src/auth/claude.rs +++ b/ak-cli/src/auth/claude.rs @@ -2,6 +2,7 @@ use ak_platform::{ client::user::{AnyService, Client}, generated::{agent::RequestHeader, agent_auth::TokenExchangeRequest}, grpc::assert_response_valid, + http::ReqwestResponseError, }; use chrono::{TimeDelta, Utc}; use eyre::{Result, WrapErr}; @@ -102,7 +103,8 @@ pub async fn get_credentials( }) .send() .await? - .error_for_status()? + .error_with_response() + .await? .json() .await?; diff --git a/ak-platform-e2e/src/lib.rs b/ak-platform-e2e/src/lib.rs index 1c4137f5e..62b42e041 100644 --- a/ak-platform-e2e/src/lib.rs +++ b/ak-platform-e2e/src/lib.rs @@ -1,6 +1,7 @@ use std::{env, path::PathBuf, time::Duration}; use ak_flow_executor::executor::FlowExecutor; +use ak_platform::http::ReqwestResponseError; use ak_platform::log::{LevelFilter, LogBuilder}; use ak_platform::oauth::device_flow::{poll_for_device_token, request_device_authorization}; use ak_platform::string::PlatformString; @@ -226,7 +227,8 @@ pub async fn cleanup_hosts() -> Result<()> { .send() .await .wrap_err("failed to list devices")? - .error_for_status() + .error_with_response() + .await .wrap_err("failed to list devices")? .json() .await diff --git a/ak-platform/src/http.rs b/ak-platform/src/http.rs new file mode 100644 index 000000000..2189ce6c1 --- /dev/null +++ b/ak-platform/src/http.rs @@ -0,0 +1,20 @@ +use eyre::Error; +use reqwest::Response; + +pub trait ReqwestResponseError { + fn error_with_response(self) -> impl std::future::Future> + Send + where + Self: Sized; +} + +impl ReqwestResponseError for Response { + async fn error_with_response(self) -> Result { + let status = self.status(); + if status.is_client_error() || status.is_server_error() { + let body = self.text().await?; + Err(eyre::eyre!("Error in HTTP request: {} {}", status, body)) + } else { + Ok(self) + } + } +} diff --git a/ak-platform/src/lib.rs b/ak-platform/src/lib.rs index 79e4c8db6..6b91f96bb 100644 --- a/ak-platform/src/lib.rs +++ b/ak-platform/src/lib.rs @@ -3,6 +3,7 @@ pub mod config; pub mod dpop; pub mod generated; pub mod grpc; +pub mod http; pub mod log; pub mod net; pub mod oauth;