From 51c30b89a48bf14c8d0c3cd0377c9e00fd42a6f0 Mon Sep 17 00:00:00 2001 From: Matthew Mauer Date: Wed, 15 Jan 2025 18:17:46 -0500 Subject: [PATCH 1/3] catch rate-limiting errors and fix other error-parsing for api key validation --- src/apis/api_key_service_api.rs | 25 ++++++++++++++++++++--- src/propelauth/api_key.rs | 35 ++++++++++++++++++++++++--------- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/apis/api_key_service_api.rs b/src/apis/api_key_service_api.rs index 0e338e2..9068117 100644 --- a/src/apis/api_key_service_api.rs +++ b/src/apis/api_key_service_api.rs @@ -49,7 +49,13 @@ pub struct ValidateApiKeyParams { pub enum ApiKeyError { BadRequest(crate::models::BadUpdateOrgRequest), InvalidIntegrationAPIKey, - InvalidAPIKey, + InvalidAPIKey { + message: String, + }, + RateLimited { + wait_seconds: f64, + user_facing_error: String, + }, InvalidPersonalAPIKey, InvalidOrgAPIKey, NotFound, @@ -58,6 +64,19 @@ pub enum ApiKeyError { UnexpectedExceptionWithSDK, } +#[derive(Debug, Clone, Deserialize)] +#[serde(untagged)] +pub enum ApiKeyValidationErrorResponse { + InvalidEndUserApiKey { + api_key_id: String, + }, + EndUserApiKeyRateLimited { + wait_seconds: f64, + error_code: String, + user_facing_error: String, + }, +} + pub async fn fetch_current_api_keys( configuration: &configuration::Configuration, params: ApiKeyQueryParams, @@ -340,7 +359,7 @@ pub async fn delete_api_key( pub async fn validate_api_key( configuration: &configuration::Configuration, params: ValidateApiKeyParams, -) -> Result> { +) -> Result> { if hex::decode(¶ms.api_key_token).is_err() { return Err(Error::Params("Invalid API key ID format".to_string())); } @@ -371,7 +390,7 @@ pub async fn validate_api_key( if !status.is_client_error() && !status.is_server_error() { serde_json::from_str(&content).map_err(Error::from) } else { - let entity: Option = serde_json::from_str(&content).ok(); + let entity: Option = serde_json::from_str(&content).ok(); let error = ResponseContent { status, content, diff --git a/src/propelauth/api_key.rs b/src/propelauth/api_key.rs index 2e679a4..2a00aa2 100644 --- a/src/propelauth/api_key.rs +++ b/src/propelauth/api_key.rs @@ -1,4 +1,4 @@ -use crate::apis::api_key_service_api::{ApiKeyError, ApiKeyQueryParams, CreateApiKeyParams, UpdateApiKeyParams, ValidateApiKeyParams}; +use crate::apis::api_key_service_api::{ApiKeyError, ApiKeyQueryParams, ApiKeyValidationErrorResponse, CreateApiKeyParams, UpdateApiKeyParams, ValidateApiKeyParams}; use crate::apis::configuration::Configuration; use crate::models::{CreateApiKeyResponse, FetchApiKeyResponse, FetchApiKeysPagedResponse, ValidateApiKeyResponse}; use crate::models::validate_api_key_response::{ValidateOrgApiKeyResponse, ValidatePersonalApiKeyResponse}; @@ -62,7 +62,7 @@ impl ApiKeyService<'_> { ApiKeyError::UnexpectedExceptionWithSDK, |status_code, _| match status_code.as_u16() { 401 => ApiKeyError::InvalidIntegrationAPIKey, - 404 => ApiKeyError::InvalidAPIKey, + 404 => ApiKeyError::NotFound, _ => ApiKeyError::UnknownError, }, ) @@ -94,7 +94,7 @@ impl ApiKeyService<'_> { ApiKeyError::UnexpectedExceptionWithSDK, |status_code, _| match status_code.as_u16() { 401 => ApiKeyError::InvalidIntegrationAPIKey, - 404 => ApiKeyError::InvalidAPIKey, + 404 => ApiKeyError::NotFound, _ => ApiKeyError::UnknownError, }, ) @@ -112,7 +112,7 @@ impl ApiKeyService<'_> { ApiKeyError::UnexpectedExceptionWithSDK, |status_code, _| match status_code.as_u16() { 401 => ApiKeyError::InvalidIntegrationAPIKey, - 404 => ApiKeyError::InvalidAPIKey, + 404 => ApiKeyError::NotFound, _ => ApiKeyError::UnknownError, }, ) @@ -121,17 +121,34 @@ impl ApiKeyService<'_> { Ok(()) } - pub async fn validate_api_key(&self, params: ValidateApiKeyParams) -> Result { + pub async fn validate_api_key( + &self, + params: ValidateApiKeyParams, + ) -> Result { crate::apis::api_key_service_api::validate_api_key(&self.config, params) .await .map_err(|err| { map_autogenerated_error( err, ApiKeyError::UnexpectedExceptionWithSDK, - |status_code, _| match status_code.as_u16() { - 401 => ApiKeyError::InvalidIntegrationAPIKey, - 404 => ApiKeyError::NotFound, - _ => ApiKeyError::UnknownError, + |status_code, error_response_body| match error_response_body { + Some(ApiKeyValidationErrorResponse::InvalidEndUserApiKey { + api_key_id, + }) => ApiKeyError::InvalidAPIKey { + message: api_key_id, + }, + Some(ApiKeyValidationErrorResponse::EndUserApiKeyRateLimited { + wait_seconds, + user_facing_error, + .. + }) => ApiKeyError::RateLimited { + wait_seconds, + user_facing_error, + }, + None => match status_code.as_u16() { + 401 => ApiKeyError::InvalidIntegrationAPIKey, + _ => ApiKeyError::UnknownError, + }, }, ) }) From 3e9b4328ee6cc78df3a05e436df54fc71ddd1066 Mon Sep 17 00:00:00 2001 From: Matthew Mauer Date: Wed, 15 Jan 2025 18:21:45 -0500 Subject: [PATCH 2/3] add back 404 case --- src/propelauth/api_key.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/propelauth/api_key.rs b/src/propelauth/api_key.rs index 2a00aa2..0705042 100644 --- a/src/propelauth/api_key.rs +++ b/src/propelauth/api_key.rs @@ -147,6 +147,7 @@ impl ApiKeyService<'_> { }, None => match status_code.as_u16() { 401 => ApiKeyError::InvalidIntegrationAPIKey, + 404 => ApiKeyError::NotFound, _ => ApiKeyError::UnknownError, }, }, From 71faf14c8312276e5799031f034da1ccde013309 Mon Sep 17 00:00:00 2001 From: Matthew Mauer Date: Tue, 21 Jan 2025 11:39:04 -0500 Subject: [PATCH 3/3] fix error handling of invalid / non-hex api key inputs --- src/apis/api_key_service_api.rs | 6 +----- src/propelauth/api_key.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/apis/api_key_service_api.rs b/src/apis/api_key_service_api.rs index 9068117..4a1a656 100644 --- a/src/apis/api_key_service_api.rs +++ b/src/apis/api_key_service_api.rs @@ -68,7 +68,7 @@ pub enum ApiKeyError { #[serde(untagged)] pub enum ApiKeyValidationErrorResponse { InvalidEndUserApiKey { - api_key_id: String, + api_key_token: String, }, EndUserApiKeyRateLimited { wait_seconds: f64, @@ -360,10 +360,6 @@ pub async fn validate_api_key( configuration: &configuration::Configuration, params: ValidateApiKeyParams, ) -> Result> { - if hex::decode(¶ms.api_key_token).is_err() { - return Err(Error::Params("Invalid API key ID format".to_string())); - } - let client = &configuration.client; let uri = format!( diff --git a/src/propelauth/api_key.rs b/src/propelauth/api_key.rs index 0705042..d22b31a 100644 --- a/src/propelauth/api_key.rs +++ b/src/propelauth/api_key.rs @@ -125,6 +125,12 @@ impl ApiKeyService<'_> { &self, params: ValidateApiKeyParams, ) -> Result { + if hex::decode(¶ms.api_key_token).is_err() { + return Err(ApiKeyError::InvalidAPIKey { + message: "Invalid API key format.".to_string() + }); + } + crate::apis::api_key_service_api::validate_api_key(&self.config, params) .await .map_err(|err| { @@ -133,9 +139,9 @@ impl ApiKeyService<'_> { ApiKeyError::UnexpectedExceptionWithSDK, |status_code, error_response_body| match error_response_body { Some(ApiKeyValidationErrorResponse::InvalidEndUserApiKey { - api_key_id, + api_key_token, }) => ApiKeyError::InvalidAPIKey { - message: api_key_id, + message: api_key_token, }, Some(ApiKeyValidationErrorResponse::EndUserApiKeyRateLimited { wait_seconds,