From 963e25956521ba4c2ac3bad937e3f53933d905c5 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Fri, 27 Jun 2025 22:06:16 +1200 Subject: [PATCH] dont allow secret key for IAW flow --- server/src/http/error.rs | 2 +- server/src/http/extractors.rs | 59 +++++++++--------- thirdweb-core/src/iaw/mod.rs | 114 ++++++++++++++++++++-------------- 3 files changed, 95 insertions(+), 80 deletions(-) diff --git a/server/src/http/error.rs b/server/src/http/error.rs index a80f914..827cba7 100644 --- a/server/src/http/error.rs +++ b/server/src/http/error.rs @@ -68,7 +68,7 @@ impl ApiEngineError { }, EngineError::VaultError { .. } => StatusCode::INTERNAL_SERVER_ERROR, EngineError::IawError { error } => match error { - thirdweb_core::iaw::IAWError::ApiError(_) => StatusCode::INTERNAL_SERVER_ERROR, + thirdweb_core::iaw::IAWError::ApiError { .. } => StatusCode::INTERNAL_SERVER_ERROR, thirdweb_core::iaw::IAWError::SerializationError { .. } => StatusCode::BAD_REQUEST, thirdweb_core::iaw::IAWError::NetworkError { .. } => StatusCode::BAD_REQUEST, thirdweb_core::iaw::IAWError::AuthError(_) => StatusCode::UNAUTHORIZED, diff --git a/server/src/http/extractors.rs b/server/src/http/extractors.rs index 7c458d4..200cc73 100644 --- a/server/src/http/extractors.rs +++ b/server/src/http/extractors.rs @@ -99,46 +99,43 @@ where .get("x-wallet-access-token") .and_then(|v| v.to_str().ok()) { - // Extract ThirdwebAuth for billing purposes - let thirdweb_auth = if let Some(secret_key) = parts + // Try client ID and service key combination + let client_id = parts .headers - .get("x-thirdweb-secret-key") + .get("x-thirdweb-client-id") .and_then(|v| v.to_str().ok()) - { - ThirdwebAuth::SecretKey(secret_key.to_string()) - } else { - // Try client ID and service key combination - let client_id = parts - .headers - .get("x-thirdweb-client-id") - .and_then(|v| v.to_str().ok()) - .ok_or_else(|| { - ApiEngineError(EngineError::ValidationError { - message: "Missing x-thirdweb-client-id header when using IAW".to_string(), - }) - })?; - - let service_key = parts - .headers - .get("x-thirdweb-service-key") - .and_then(|v| v.to_str().ok()) - .ok_or_else(|| { - ApiEngineError(EngineError::ValidationError { - message: "Missing x-thirdweb-service-key header when using IAW".to_string(), - }) - })?; - - ThirdwebAuth::ClientIdServiceKey(thirdweb_core::auth::ThirdwebClientIdAndServiceKey { + .ok_or_else(|| { + ApiEngineError(EngineError::ValidationError { + message: + "Missing x-thirdweb-client-id header when using x-wallet-access-token" + .to_string(), + }) + })?; + + let service_key = parts + .headers + .get("x-thirdweb-service-key") + .and_then(|v| v.to_str().ok()) + .ok_or_else(|| { + ApiEngineError(EngineError::ValidationError { + message: + "Missing x-thirdweb-service-key header when using x-wallet-access-token" + .to_string(), + }) + })?; + + let thirdweb_auth = ThirdwebAuth::ClientIdServiceKey( + thirdweb_core::auth::ThirdwebClientIdAndServiceKey { client_id: client_id.to_string(), service_key: service_key.to_string(), - }) - }; + }, + ); return Ok(SigningCredentialsExtractor(SigningCredential::Iaw { auth_token: wallet_token.to_string(), thirdweb_auth, })); - } + }; // Fall back to Vault credentials let vault_access_token = parts diff --git a/thirdweb-core/src/iaw/mod.rs b/thirdweb-core/src/iaw/mod.rs index bc02b3a..29d51ed 100644 --- a/thirdweb-core/src/iaw/mod.rs +++ b/thirdweb-core/src/iaw/mod.rs @@ -30,8 +30,8 @@ pub type AuthToken = String; )] #[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")] pub enum IAWError { - #[error("API error: {0}")] - ApiError(String), + #[error("API error: {message}")] + ApiError { message: String }, #[error("Serialization error: {message}")] SerializationError { message: String }, #[error("Network error: {error}")] @@ -197,14 +197,16 @@ impl IAWClient { .await?; if !response.status().is_success() { - return Err(IAWError::ApiError(format!( - "Failed to sign message - {} {}", - response.status(), - response - .status() - .canonical_reason() - .unwrap_or("Unknown error") - ))); + return Err(IAWError::ApiError { + message: format!( + "Failed to sign message - {} {}", + response.status(), + response + .status() + .canonical_reason() + .unwrap_or("Unknown error") + ), + }); } // Parse the response @@ -214,7 +216,9 @@ impl IAWClient { let signature = signed_response .get("signature") .and_then(|s| s.as_str()) - .ok_or_else(|| IAWError::ApiError("No signature in response".to_string()))?; + .ok_or_else(|| IAWError::ApiError { + message: "No signature in response".to_string(), + })?; Ok(SignMessageData { signature: signature.to_string(), @@ -262,14 +266,16 @@ impl IAWClient { .await?; if !response.status().is_success() { - return Err(IAWError::ApiError(format!( - "Failed to sign typed data - {} {}", - response.status(), - response - .status() - .canonical_reason() - .unwrap_or("Unknown error") - ))); + return Err(IAWError::ApiError { + message: format!( + "Failed to sign typed data - {} {}", + response.status(), + response + .status() + .canonical_reason() + .unwrap_or("Unknown error") + ), + }); } // Parse the response @@ -279,7 +285,9 @@ impl IAWClient { let signature = signed_response .get("signature") .and_then(|s| s.as_str()) - .ok_or_else(|| IAWError::ApiError("No signature in response".to_string()))?; + .ok_or_else(|| IAWError::ApiError { + message: "No signature in response".to_string(), + })?; Ok(SignTypedDataData { signature: signature.to_string(), @@ -328,14 +336,16 @@ impl IAWClient { .await?; if !response.status().is_success() { - return Err(IAWError::ApiError(format!( - "Failed to sign transaction - {} {}", - response.status(), - response - .status() - .canonical_reason() - .unwrap_or("Unknown error") - ))); + return Err(IAWError::ApiError { + message: format!( + "Failed to sign transaction - {} {}", + response.status(), + response + .status() + .canonical_reason() + .unwrap_or("Unknown error") + ), + }); } // Parse the response @@ -345,7 +355,9 @@ impl IAWClient { let signature = signed_response .get("signature") .and_then(|s| s.as_str()) - .ok_or_else(|| IAWError::ApiError("No signature in response".to_string()))?; + .ok_or_else(|| IAWError::ApiError { + message: "No signature in response".to_string(), + })?; Ok(SignTransactionData { signature: signature.to_string(), @@ -397,14 +409,16 @@ impl IAWClient { .await?; if !response.status().is_success() { - return Err(IAWError::ApiError(format!( - "Failed to sign authorization - {} {}", - response.status(), - response - .status() - .canonical_reason() - .unwrap_or("Unknown error") - ))); + return Err(IAWError::ApiError { + message: format!( + "Failed to sign authorization - {} {}", + response.status(), + response + .status() + .canonical_reason() + .unwrap_or("Unknown error") + ), + }); } // Parse the response @@ -414,8 +428,8 @@ impl IAWClient { let signed_authorization: SignedAuthorization = serde_json::from_value( signed_response .get("signedAuthorization") - .ok_or_else(|| { - IAWError::ApiError("No signedAuthorization in response".to_string()) + .ok_or_else(|| IAWError::ApiError { + message: "No signedAuthorization in response".to_string(), })? .clone(), )?; @@ -483,14 +497,16 @@ impl IAWClient { .await?; if !response.status().is_success() { - return Err(IAWError::ApiError(format!( - "Failed to sign userop - {} {}", - response.status(), - response - .status() - .canonical_reason() - .unwrap_or("Unknown error") - ))); + return Err(IAWError::ApiError { + message: format!( + "Failed to sign userop - {} {}", + response.status(), + response + .status() + .canonical_reason() + .unwrap_or("Unknown error") + ), + }); } // Parse the response @@ -500,7 +516,9 @@ impl IAWClient { let signature = signed_response .get("signature") .and_then(|s| s.as_str()) - .ok_or_else(|| IAWError::ApiError("No signature in response".to_string()))?; + .ok_or_else(|| IAWError::ApiError { + message: "No signature in response".to_string(), + })?; Ok(SignUserOpData { signature: signature.to_string(),