diff --git a/Cargo.lock b/Cargo.lock index a953b4f74..e3342ff2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7060,11 +7060,13 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ + "base64 0.21.7", "bitflags 2.6.0", "bytes", "http 1.1.0", "http-body 1.0.1", "http-body-util", + "mime", "pin-project-lite", "tower-layer", "tower-service", diff --git a/crates/service/Cargo.toml b/crates/service/Cargo.toml index 7c5162ea3..65a1c0a57 100644 --- a/crates/service/Cargo.toml +++ b/crates/service/Cargo.toml @@ -39,6 +39,7 @@ uuid.workspace = true alloy.workspace = true tower_governor = "0.4.0" tower-http = { version = "0.5.2", features = [ + "auth", "cors", "normalize-path", "trace", diff --git a/crates/service/src/routes/static_subgraph.rs b/crates/service/src/routes/static_subgraph.rs index 61551cb31..b2447b0ac 100644 --- a/crates/service/src/routes/static_subgraph.rs +++ b/crates/service/src/routes/static_subgraph.rs @@ -1,7 +1,7 @@ // Copyright 2023-, Edge & Node, GraphOps, and Semiotic Labs. // SPDX-License-Identifier: Apache-2.0 -use axum::{body::Bytes, http::HeaderMap, response::IntoResponse, Extension, Json}; +use axum::{body::Bytes, extract::State, response::IntoResponse, Json}; use reqwest::StatusCode; use serde_json::json; use tracing::warn; @@ -10,25 +10,9 @@ use indexer_common::SubgraphClient; #[autometrics::autometrics] pub async fn static_subgraph_request_handler( - Extension(subgraph_client): Extension<&'static SubgraphClient>, - Extension(required_auth_token): Extension>, - headers: HeaderMap, + State(subgraph_client): State<&'static SubgraphClient>, body: Bytes, ) -> Result { - if let Some(required_auth_token) = required_auth_token { - let authorization = headers - .get("authorization") - .map(|value| value.to_str()) - .transpose() - .map_err(|_| StaticSubgraphError::Unauthorized)? - .ok_or_else(|| StaticSubgraphError::Unauthorized)? - .trim_start_matches("Bearer "); - - if authorization != required_auth_token { - return Err(StaticSubgraphError::Unauthorized); - } - } - let response = subgraph_client.query_raw(body).await?; Ok(( @@ -42,9 +26,6 @@ pub async fn static_subgraph_request_handler( #[derive(Debug, thiserror::Error)] pub enum StaticSubgraphError { - #[error("No valid receipt or free query auth token provided")] - Unauthorized, - #[error("Failed to query subgraph: {0}")] FailedToQuery(#[from] anyhow::Error), @@ -54,16 +35,9 @@ pub enum StaticSubgraphError { impl IntoResponse for StaticSubgraphError { fn into_response(self) -> axum::response::Response { - let status = match self { - StaticSubgraphError::Unauthorized => StatusCode::UNAUTHORIZED, - StaticSubgraphError::FailedToQuery(_) | StaticSubgraphError::FailedToParse(_) => { - StatusCode::INTERNAL_SERVER_ERROR - } - }; - tracing::error!(%self, "StaticSubgraphError occoured."); ( - status, + StatusCode::INTERNAL_SERVER_ERROR, Json(json! {{ "message": self.to_string(), }}), diff --git a/crates/service/src/service/indexer_service.rs b/crates/service/src/service/indexer_service.rs index d94eca750..a36bd2dff 100644 --- a/crates/service/src/service/indexer_service.rs +++ b/crates/service/src/service/indexer_service.rs @@ -10,7 +10,7 @@ use axum::{ async_trait, response::{IntoResponse, Response}, routing::{get, post}, - Extension, Json, Router, + Json, Router, }; use axum::{serve, ServiceExt}; use build_info::BuildInfo; @@ -36,7 +36,9 @@ use tokio::net::TcpListener; use tokio::signal; use tokio::sync::watch::Receiver; use tower_governor::{governor::GovernorConfigBuilder, GovernorLayer}; +use tower_http::validate_request::ValidateRequestHeaderLayer; use tower_http::{cors, cors::CorsLayer, normalize_path::NormalizePath, trace::TraceLayer}; +use tracing::warn; use tracing::{error, info, info_span}; use crate::routes::health; @@ -403,25 +405,39 @@ impl IndexerService { .layer(misc_rate_limiter); if options.config.service.serve_network_subgraph { - info!("Serving network subgraph at /network"); - - misc_routes = misc_routes.route( - "/network", - post(static_subgraph_request_handler) - .route_layer(Extension(network_subgraph)) - .route_layer(Extension(options.config.service.serve_auth_token.clone())) - .route_layer(static_subgraph_rate_limiter.clone()), - ); + if let Some(free_auth_token) = &options.config.service.serve_auth_token { + info!("Serving network subgraph at /network"); + + let auth_layer = ValidateRequestHeaderLayer::bearer(free_auth_token); + + misc_routes = misc_routes.route( + "/network", + post(static_subgraph_request_handler) + .route_layer(auth_layer) + .with_state(network_subgraph) + .route_layer(static_subgraph_rate_limiter.clone()), + ); + } else { + warn!("`serve_network_subgraph` is enabled but no `serve_auth_token` provided. Disabling it."); + } } if options.config.service.serve_escrow_subgraph { - info!("Serving escrow subgraph at /escrow"); + if let Some(free_auth_token) = &options.config.service.serve_auth_token { + info!("Serving escrow subgraph at /escrow"); + + let auth_layer = ValidateRequestHeaderLayer::bearer(free_auth_token); - misc_routes = misc_routes - .route("/escrow", post(static_subgraph_request_handler)) - .route_layer(Extension(escrow_subgraph)) - .route_layer(Extension(options.config.service.serve_auth_token.clone())) - .route_layer(static_subgraph_rate_limiter); + misc_routes = misc_routes.route( + "/escrow", + post(static_subgraph_request_handler) + .route_layer(auth_layer) + .with_state(escrow_subgraph) + .route_layer(static_subgraph_rate_limiter), + ) + } else { + warn!("`serve_escrow_subgraph` is enabled but no `serve_auth_token` provided. Disabling it."); + } } misc_routes = misc_routes.with_state(state.clone());