upgrade axum to 0.8.9 (and side deps) (#6808)
* upgrade axum to 0.8.9 (and side deps) Bumps axum 0.7.5 → 0.8.9, axum-extra 0.9.4 → 0.12.6, axum-client-ip 0.6.1 → 1.3.1, axum-test 16.2.0 → 20.0.0, utoipa-swagger-ui 8.1 → 9.0.2. * warn upon using fallback ip Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * chore: replace use of deprecated try_next() * update console-subscriber to ensure single version of axum in the lock file * removed unused axum-test dev-dep --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
6b0a904d10
commit
28b22f6b22
Generated
+363
-469
File diff suppressed because it is too large
Load Diff
+6
-6
@@ -222,10 +222,10 @@ anyhow = "1.0.98"
|
||||
arc-swap = "1.7.1"
|
||||
argon2 = "0.5.0"
|
||||
async-trait = "0.1.88"
|
||||
axum = "0.7.5"
|
||||
axum-client-ip = "0.6.1"
|
||||
axum-extra = "0.9.4"
|
||||
axum-test = "16.2.0"
|
||||
axum = "0.8.9"
|
||||
axum-client-ip = "1.3.1"
|
||||
axum-extra = "0.12.6"
|
||||
axum-test = "20.0.0"
|
||||
base64 = "0.22.1"
|
||||
base85rs = "0.1.3"
|
||||
bincode = "1.3.3"
|
||||
@@ -250,7 +250,7 @@ clap_complete_fig = "4.5"
|
||||
colored = "2.2"
|
||||
comfy-table = "7.1.4"
|
||||
console = "0.16.0"
|
||||
console-subscriber = "0.4.1"
|
||||
console-subscriber = "0.5.0"
|
||||
console_error_panic_hook = "0.1"
|
||||
const-str = "0.5.6"
|
||||
const_format = "0.2.34"
|
||||
@@ -392,7 +392,7 @@ uniffi = "0.29.2"
|
||||
uniffi_build = "0.29.0"
|
||||
url = "2.5"
|
||||
utoipa = "5.2"
|
||||
utoipa-swagger-ui = "8.1"
|
||||
utoipa-swagger-ui = "9.0.2"
|
||||
utoipauto = "0.2"
|
||||
uuid = "1.19.0"
|
||||
vergen = { version = "=8.3.1", default-features = false }
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use axum::extract::{ConnectInfo, FromRequestParts};
|
||||
use axum::http::request::Parts;
|
||||
use axum_client_ip::RightmostXForwardedFor;
|
||||
use std::convert::Infallible;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use tracing::warn;
|
||||
|
||||
/// Best-effort client IP extractor.
|
||||
///
|
||||
/// Prefers the rightmost entry of `X-Forwarded-For` (set by a trusted reverse
|
||||
/// proxy); falls back to the TCP peer address when the header is absent, and to
|
||||
/// the unspecified address when neither is available (tests).
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ClientIpAddr(pub IpAddr);
|
||||
|
||||
impl<S> FromRequestParts<S> for ClientIpAddr
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
|
||||
if let Ok(RightmostXForwardedFor(ip)) =
|
||||
RightmostXForwardedFor::from_request_parts(parts, state).await
|
||||
{
|
||||
return Ok(ClientIpAddr(ip));
|
||||
}
|
||||
if let Ok(ConnectInfo(addr)) =
|
||||
ConnectInfo::<SocketAddr>::from_request_parts(parts, state).await
|
||||
{
|
||||
return Ok(ClientIpAddr(addr.ip()));
|
||||
}
|
||||
warn!("ClientIpAddr: no X-Forwarded-For or ConnectInfo found; using 0.0.0.0 fallback");
|
||||
Ok(ClientIpAddr(IpAddr::V4(Ipv4Addr::UNSPECIFIED)))
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::middleware::client_ip::ClientIpAddr;
|
||||
use axum::extract::Request;
|
||||
use axum::http::HeaderValue;
|
||||
use axum::http::header::{HOST, USER_AGENT};
|
||||
use axum::middleware::Next;
|
||||
use axum::response::IntoResponse;
|
||||
use axum_client_ip::InsecureClientIp;
|
||||
use colored::Colorize;
|
||||
use std::time::Instant;
|
||||
use tracing::{debug, info};
|
||||
@@ -17,24 +17,24 @@ enum LogLevel {
|
||||
}
|
||||
|
||||
pub async fn log_request_info(
|
||||
insecure_client_ip: InsecureClientIp,
|
||||
client_ip: ClientIpAddr,
|
||||
request: Request,
|
||||
next: Next,
|
||||
) -> impl IntoResponse {
|
||||
log_request(insecure_client_ip, request, next, LogLevel::Info).await
|
||||
log_request(client_ip, request, next, LogLevel::Info).await
|
||||
}
|
||||
|
||||
pub async fn log_request_debug(
|
||||
insecure_client_ip: InsecureClientIp,
|
||||
client_ip: ClientIpAddr,
|
||||
request: Request,
|
||||
next: Next,
|
||||
) -> impl IntoResponse {
|
||||
log_request(insecure_client_ip, request, next, LogLevel::Debug).await
|
||||
log_request(client_ip, request, next, LogLevel::Debug).await
|
||||
}
|
||||
|
||||
/// Simple logger for requests
|
||||
async fn log_request(
|
||||
InsecureClientIp(addr): InsecureClientIp,
|
||||
ClientIpAddr(addr): ClientIpAddr,
|
||||
request: Request,
|
||||
next: Next,
|
||||
level: LogLevel,
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod bearer_auth;
|
||||
pub mod client_ip;
|
||||
pub mod logging;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use async_trait::async_trait;
|
||||
use axum::extract::FromRequestParts;
|
||||
use axum::http::Request;
|
||||
use axum::http::request::Parts;
|
||||
@@ -56,7 +55,6 @@ impl DummyConnectInfo {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for DummyConnectInfo
|
||||
where
|
||||
S: Send + Sync,
|
||||
|
||||
@@ -57,7 +57,7 @@ pub(crate) mod test {
|
||||
|
||||
async fn handle_check_request(&mut self, polled_request: CheckRequest) {
|
||||
let mut requests = vec![polled_request];
|
||||
while let Ok(Some(queued_up)) = self.check_request_receiver.try_next() {
|
||||
while let Ok(queued_up) = self.check_request_receiver.try_recv() {
|
||||
requests.push(queued_up);
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ impl UpgradeModeWatcher {
|
||||
|
||||
async fn handle_check_request(&mut self, polled_request: CheckRequest) {
|
||||
let mut requests = vec![polled_request];
|
||||
while let Ok(Some(queued_up)) = self.check_request_receiver.try_next() {
|
||||
while let Ok(queued_up) = self.check_request_receiver.try_recv() {
|
||||
requests.push(queued_up);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,15 +32,15 @@ pub(crate) fn issued_routes() -> Router<AppState> {
|
||||
axum::routing::get(issued_ticketbooks_count),
|
||||
)
|
||||
.route(
|
||||
"/issued-ticketbooks-for-count/:expiration_date",
|
||||
"/issued-ticketbooks-for-count/{expiration_date}",
|
||||
axum::routing::get(issued_ticketbooks_for_count),
|
||||
)
|
||||
.route(
|
||||
"/issued-ticketbooks-on-count/:issuance_date",
|
||||
"/issued-ticketbooks-on-count/{issuance_date}",
|
||||
axum::routing::get(issued_ticketbooks_on_count),
|
||||
)
|
||||
.route(
|
||||
"/issued-ticketbooks-for/:expiration_date",
|
||||
"/issued-ticketbooks-for/{expiration_date}",
|
||||
axum::routing::get(issued_ticketbooks_for),
|
||||
)
|
||||
.route(
|
||||
|
||||
@@ -1369,8 +1369,7 @@ impl TestFixture {
|
||||
Router::new()
|
||||
.nest("/v1/ecash", ecash_routes())
|
||||
.with_state(app_state),
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
storage,
|
||||
chain_state: bundle.chain_state,
|
||||
epoch: bundle.epoch,
|
||||
|
||||
@@ -23,8 +23,8 @@ const MAX_FAMILIES_PAGE_SIZE: u32 = 200;
|
||||
pub(crate) fn routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route("/", get(get_families))
|
||||
.route("/:family_id", get(get_family_by_id))
|
||||
.route("/by-node/:node_id", get(get_family_for_node))
|
||||
.route("/{family_id}", get(get_family_by_id))
|
||||
.route("/by-node/{node_id}", get(get_family_for_node))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
||||
@@ -52,8 +52,7 @@ impl NodeFamiliesTestFixture {
|
||||
Router::new()
|
||||
.nest("/v1/node-families", handlers::routes())
|
||||
.with_state(app_state),
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
|
||||
NodeFamiliesTestFixture {
|
||||
axum: server,
|
||||
|
||||
@@ -25,7 +25,7 @@ use utoipa::IntoParams;
|
||||
pub(super) fn network_monitor_routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.nest(
|
||||
"/gateway/:identity",
|
||||
"/gateway/{identity}",
|
||||
Router::new()
|
||||
.route("/history", axum::routing::get(gateway_uptime_history))
|
||||
.route(
|
||||
@@ -34,7 +34,7 @@ pub(super) fn network_monitor_routes() -> Router<AppState> {
|
||||
),
|
||||
)
|
||||
.nest(
|
||||
"/mixnode/:mix_id",
|
||||
"/mixnode/{mix_id}",
|
||||
Router::new()
|
||||
.route("/history", axum::routing::get(mixnode_uptime_history))
|
||||
.route(
|
||||
@@ -45,14 +45,14 @@ pub(super) fn network_monitor_routes() -> Router<AppState> {
|
||||
.nest(
|
||||
"/mixnodes",
|
||||
Router::new().route(
|
||||
"/unstable/:mix_id/test-results",
|
||||
"/unstable/{mix_id}/test-results",
|
||||
axum::routing::get(unstable::mixnode_test_results),
|
||||
),
|
||||
)
|
||||
.nest(
|
||||
"/gateways",
|
||||
Router::new().route(
|
||||
"/unstable/:gateway_identity/test-results",
|
||||
"/unstable/{gateway_identity}/test-results",
|
||||
axum::routing::get(unstable::gateway_test_results),
|
||||
),
|
||||
)
|
||||
@@ -60,7 +60,7 @@ pub(super) fn network_monitor_routes() -> Router<AppState> {
|
||||
"/network-monitor/unstable",
|
||||
Router::new()
|
||||
.route(
|
||||
"/run/:monitor_run_id/details",
|
||||
"/run/{monitor_run_id}/details",
|
||||
axum::routing::get(monitor_run_report),
|
||||
)
|
||||
.route(
|
||||
|
||||
@@ -30,19 +30,22 @@ pub(crate) fn routes() -> Router<AppState> {
|
||||
.route("/noise", get(nodes_noise))
|
||||
.route("/bonded", get(get_bonded_nodes))
|
||||
.route("/described", get(get_described_nodes))
|
||||
.route("/annotation/:node_id", get(get_node_annotation))
|
||||
.route("/performance/:node_id", get(get_current_node_performance))
|
||||
.route("/stake-saturation/:node_id", get(get_node_stake_saturation))
|
||||
.route("/annotation/{node_id}", get(get_node_annotation))
|
||||
.route("/performance/{node_id}", get(get_current_node_performance))
|
||||
.route(
|
||||
"/historical-performance/:node_id",
|
||||
"/stake-saturation/{node_id}",
|
||||
get(get_node_stake_saturation),
|
||||
)
|
||||
.route(
|
||||
"/historical-performance/{node_id}",
|
||||
get(get_historical_performance),
|
||||
)
|
||||
.route(
|
||||
"/performance-history/:node_id",
|
||||
"/performance-history/{node_id}",
|
||||
get(get_node_performance_history),
|
||||
)
|
||||
// to make it compatible with all the explorers that were used to using 0-100 values
|
||||
.route("/uptime-history/:node_id", get(get_node_uptime_history))
|
||||
.route("/uptime-history/{node_id}", get(get_node_uptime_history))
|
||||
.route("/rewarded-set", get(rewarded_set))
|
||||
.layer(CompressionLayer::new())
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ pub(crate) mod data_collector;
|
||||
pub(crate) mod models;
|
||||
|
||||
pub(crate) fn routes() -> Router<AppState> {
|
||||
Router::new().route("/:address", get(address))
|
||||
Router::new().route("/{address}", get(address))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, utoipa::IntoParams)]
|
||||
|
||||
@@ -62,9 +62,9 @@ pub mod routes {
|
||||
pub mod shares {
|
||||
use super::*;
|
||||
|
||||
pub const SHARE_BY_ID: &str = "/:share_id";
|
||||
pub const SHARE_BY_ID: &str = "/{share_id}";
|
||||
pub const SHARE_BY_DEVICE_AND_CREDENTIAL_ID: &str =
|
||||
"/device/:device_id/credential/:credential_id";
|
||||
"/device/{device_id}/credential/{credential_id}";
|
||||
|
||||
absolute_route!(share_by_id_absolute, shares_absolute(), SHARE_BY_ID);
|
||||
absolute_route!(
|
||||
|
||||
@@ -77,3 +77,13 @@ fn setup_cors() -> CorsLayer {
|
||||
.allow_headers(tower_http::cors::Any)
|
||||
.allow_credentials(false)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn router_constructs_without_panic() {
|
||||
let _ = RouterBuilder::with_default_routes().finalize_routes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,21 @@ impl AppState {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_router(state: AppState) -> Router {
|
||||
Router::new()
|
||||
.route("/v1/send", post(send_handler).with_state(state))
|
||||
.merge(SwaggerUi::new("/v1/ui").url("/v1/docs/openapi.json", ApiDoc::openapi()))
|
||||
.route("/v1/accounting", get(accounting_handler))
|
||||
.route("/v1/sent", get(sent_handler))
|
||||
.route("/v1/dot/{mix_id}", get(mix_dot_handler))
|
||||
.route("/v1/dot", get(graph_handler))
|
||||
.route("/v1/mermaid", get(mermaid_handler))
|
||||
.route("/v1/stats", get(stats_handler))
|
||||
.route("/v1/node_stats/{mix_id}", get(node_stats_handler))
|
||||
.route("/v1/node_stats", get(all_nodes_stats_handler))
|
||||
.route("/v1/received", get(recv_handler))
|
||||
}
|
||||
|
||||
impl HttpServer {
|
||||
pub fn new(listener: SocketAddr, cancel: CancellationToken) -> Self {
|
||||
HttpServer { listener, cancel }
|
||||
@@ -66,18 +81,7 @@ impl HttpServer {
|
||||
pub async fn run(self, clients: ClientsWrapper) -> anyhow::Result<()> {
|
||||
let n_clients = clients.read().await.len();
|
||||
let state = AppState { clients };
|
||||
let app = Router::new()
|
||||
.route("/v1/send", post(send_handler).with_state(state))
|
||||
.merge(SwaggerUi::new("/v1/ui").url("/v1/docs/openapi.json", ApiDoc::openapi()))
|
||||
.route("/v1/accounting", get(accounting_handler))
|
||||
.route("/v1/sent", get(sent_handler))
|
||||
.route("/v1/dot/:mix_id", get(mix_dot_handler))
|
||||
.route("/v1/dot", get(graph_handler))
|
||||
.route("/v1/mermaid", get(mermaid_handler))
|
||||
.route("/v1/stats", get(stats_handler))
|
||||
.route("/v1/node_stats/:mix_id", get(node_stats_handler))
|
||||
.route("/v1/node_stats", get(all_nodes_stats_handler))
|
||||
.route("/v1/received", get(recv_handler));
|
||||
let app = build_router(state);
|
||||
let listener = tokio::net::TcpListener::bind(self.listener).await?;
|
||||
|
||||
let server_future =
|
||||
@@ -98,3 +102,17 @@ impl HttpServer {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[test]
|
||||
fn router_constructs_without_panic() {
|
||||
let clients: ClientsWrapper = Arc::new(RwLock::new(VecDeque::new()));
|
||||
let _ = build_router(AppState { clients });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,5 @@ sqlx = { workspace = true, features = [
|
||||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
axum-test = { workspace = true }
|
||||
time = { workspace = true, features = ["macros"] }
|
||||
nym-gateway-probe = { workspace = true, features = ["test-utils"] }
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::http::{error::HttpResult, state::AppState};
|
||||
pub(crate) fn routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/country/:two_letter_country_code",
|
||||
"/country/{two_letter_country_code}",
|
||||
axum::routing::get(get_gateways_by_country),
|
||||
)
|
||||
.route("/countries", axum::routing::get(get_gateway_countries))
|
||||
|
||||
@@ -18,7 +18,7 @@ pub(crate) fn routes() -> Router<AppState> {
|
||||
axum::routing::get(get_entry_gateway_countries),
|
||||
)
|
||||
.route(
|
||||
"/entry/country/:two_letter_country_code",
|
||||
"/entry/country/{two_letter_country_code}",
|
||||
axum::routing::get(get_entry_gateways_by_country),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ pub(crate) fn routes() -> Router<AppState> {
|
||||
axum::routing::get(get_entry_gateway_countries),
|
||||
)
|
||||
.route(
|
||||
"/exit/country/:two_letter_country_code",
|
||||
"/exit/country/{two_letter_country_code}",
|
||||
axum::routing::get(get_exit_gateways_by_country),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ pub(crate) fn routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route("/", axum::routing::get(gateways))
|
||||
.route("/skinny", axum::routing::get(gateways_skinny))
|
||||
.route("/:identity_key", axum::routing::get(get_gateway))
|
||||
.route("/{identity_key}", axum::routing::get(get_gateway))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
||||
@@ -14,8 +14,8 @@ use crate::http::{
|
||||
|
||||
pub(crate) fn routes() -> Router<AppState> {
|
||||
Router::new().route("/", axum::routing::get(get_all_sessions))
|
||||
// .route("/:node_id", axum::routing::get(get_node_sessions))
|
||||
// .route("/:day", axum::routing::get(get_daily_sessions))
|
||||
// .route("/{node_id}", axum::routing::get(get_node_sessions))
|
||||
// .route("/{day}", axum::routing::get(get_daily_sessions))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, utoipa::IntoParams)]
|
||||
|
||||
@@ -18,7 +18,7 @@ pub(crate) fn routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route("/", axum::routing::get(nym_nodes))
|
||||
.route(
|
||||
"/:node_id/delegations",
|
||||
"/{node_id}/delegations",
|
||||
axum::routing::get(node_delegations),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ use tracing::error;
|
||||
pub(crate) fn routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route("/", axum::routing::get(request_testrun))
|
||||
.route("/:testrun_id", axum::routing::post(submit_testrun))
|
||||
.route("/:testrun_id/v2", axum::routing::post(submit_testrun_v2))
|
||||
.route("/{testrun_id}", axum::routing::post(submit_testrun))
|
||||
.route("/{testrun_id}/v2", axum::routing::post(submit_testrun_v2))
|
||||
.layer(DefaultBodyLimit::max(1024 * 1024 * 5))
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,10 @@ use axum::Router;
|
||||
use axum::extract::ConnectInfo;
|
||||
use axum::extract::connect_info::IntoMakeServiceWithConnectInfo;
|
||||
use axum::middleware::AddExtension;
|
||||
use axum::serve::Serve;
|
||||
use axum::serve::WithGracefulShutdown;
|
||||
use std::net::SocketAddr;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio_util::sync::WaitForCancellationFutureOwned;
|
||||
|
||||
pub use router::{HttpServerConfig, NymNodeRouter, api};
|
||||
|
||||
@@ -15,6 +17,7 @@ pub mod helpers;
|
||||
pub mod router;
|
||||
pub mod state;
|
||||
|
||||
type InnerService = IntoMakeServiceWithConnectInfo<Router, SocketAddr>;
|
||||
type ConnectInfoExt = AddExtension<Router, ConnectInfo<SocketAddr>>;
|
||||
pub type NymNodeHttpServer = Serve<InnerService, ConnectInfoExt>;
|
||||
type MakeService = IntoMakeServiceWithConnectInfo<Router, SocketAddr>;
|
||||
type InnerService = AddExtension<Router, ConnectInfo<SocketAddr>>;
|
||||
pub type NymNodeHttpServer =
|
||||
WithGracefulShutdown<TcpListener, MakeService, InnerService, WaitForCancellationFutureOwned>;
|
||||
|
||||
@@ -14,7 +14,7 @@ pub struct Config {
|
||||
|
||||
pub(super) fn routes<S: Send + Sync + 'static + Clone>(config: Config) -> Router<S> {
|
||||
if let Some(assets) = config.assets_path {
|
||||
Router::new().nest_service("/", ServeDir::new(assets))
|
||||
Router::new().fallback_service(ServeDir::new(assets))
|
||||
} else {
|
||||
Router::new().route("/", get(default))
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ use nym_node_requests::routes;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use tokio_util::sync::WaitForCancellationFutureOwned;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
pub mod api;
|
||||
@@ -176,7 +177,7 @@ impl NymNodeRouter {
|
||||
Redirect::to(&routes::api::v1::metrics::prometheus_absolute())
|
||||
}),
|
||||
)
|
||||
.nest(routes::LANDING_PAGE, landing_page::routes(config.landing))
|
||||
.merge(landing_page::routes(config.landing))
|
||||
.nest(routes::API, api::routes(config.api))
|
||||
.layer(axum::middleware::from_fn(logging::log_request_info))
|
||||
.with_state(state),
|
||||
@@ -186,6 +187,7 @@ impl NymNodeRouter {
|
||||
pub async fn build_server(
|
||||
self,
|
||||
bind_address: &SocketAddr,
|
||||
shutdown: WaitForCancellationFutureOwned,
|
||||
) -> Result<NymNodeHttpServer, NymNodeHttpError> {
|
||||
let listener = tokio::net::TcpListener::bind(bind_address)
|
||||
.await
|
||||
@@ -198,6 +200,28 @@ impl NymNodeRouter {
|
||||
listener,
|
||||
self.inner
|
||||
.into_make_service_with_connect_info::<SocketAddr>(),
|
||||
))
|
||||
)
|
||||
.with_graceful_shutdown(shutdown))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
use nym_node_requests::api::SignedData;
|
||||
use nym_node_requests::api::v1::lewes_protocol::models::LewesProtocol;
|
||||
use nym_test_utils::helpers::deterministic_rng;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[test]
|
||||
fn router_constructs_without_panic() {
|
||||
let mut rng = deterministic_rng();
|
||||
let signing = ed25519::KeyPair::new(&mut rng);
|
||||
let x25519_pub: x25519::DHPublicKey = x25519::PrivateKey::new(&mut rng).public_key().into();
|
||||
let lp = LewesProtocol::new(false, 0, 0, x25519_pub, BTreeMap::new());
|
||||
let signed = SignedData::new(lp, signing.private_key()).unwrap();
|
||||
let config = HttpServerConfig::new(signed);
|
||||
let _ = NymNodeRouter::new(config, AppState::dummy());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,4 +73,30 @@ impl AppState {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn dummy() -> Self {
|
||||
use crate::node::key_rotation::key::SphinxPrivateKey;
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
let ed25519_keys = ed25519::KeyPair::new(&mut OsRng);
|
||||
let attester_pk = *ed25519_keys.public_key();
|
||||
let static_information = StaticNodeInformation {
|
||||
ed25519_identity_keys: Arc::new(ed25519_keys),
|
||||
x25519_versioned_noise_key: None,
|
||||
ip_addresses: vec![],
|
||||
hostname: None,
|
||||
};
|
||||
let active_sphinx = ActiveSphinxKeys::new_fresh(SphinxPrivateKey::new(&mut OsRng, 0));
|
||||
|
||||
AppState::new(
|
||||
static_information,
|
||||
active_sphinx,
|
||||
NymNodeMetrics::new(),
|
||||
SharedVerlocStats::default(),
|
||||
Url::parse("https://attestation.test").unwrap(),
|
||||
UpgradeModeState::new(attester_pk),
|
||||
Duration::from_secs(60),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ use std::ops::Deref;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio_util::sync::WaitForCancellationFutureOwned;
|
||||
use tracing::{debug, info, trace};
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
@@ -872,7 +873,10 @@ impl NymNode {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) async fn build_http_server(&self) -> Result<NymNodeHttpServer, NymNodeError> {
|
||||
pub(crate) async fn build_http_server(
|
||||
&self,
|
||||
shutdown: WaitForCancellationFutureOwned,
|
||||
) -> Result<NymNodeHttpServer, NymNodeError> {
|
||||
let auxiliary_details = api_requests::v1::node::models::AuxiliaryDetails {
|
||||
location: self.config.host.location,
|
||||
announce_ports: AnnouncePorts {
|
||||
@@ -1023,7 +1027,7 @@ impl NymNode {
|
||||
);
|
||||
|
||||
Ok(NymNodeRouter::new(config, app_state)
|
||||
.build_server(&self.config.http.bind_address)
|
||||
.build_server(&self.config.http.bind_address, shutdown)
|
||||
.await?)
|
||||
}
|
||||
|
||||
@@ -1342,16 +1346,17 @@ impl NymNode {
|
||||
);
|
||||
debug!("config: {:#?}", self.config);
|
||||
|
||||
let http_server = self.build_http_server().await?;
|
||||
let bind_address = self.config.http.bind_address;
|
||||
let server_shutdown = self.shutdown_manager.clone_shutdown_token();
|
||||
let shutdown = self
|
||||
.shutdown_manager
|
||||
.clone_shutdown_token()
|
||||
.cancelled_owned();
|
||||
let http_server = self.build_http_server(shutdown).await?;
|
||||
|
||||
self.shutdown_manager.try_spawn_named(
|
||||
async move {
|
||||
info!("starting NymNodeHTTPServer on {bind_address}");
|
||||
http_server
|
||||
.with_graceful_shutdown(async move { server_shutdown.cancelled().await })
|
||||
.await
|
||||
http_server.await
|
||||
},
|
||||
"HttpApi",
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use axum::{Json, Router, extract::State};
|
||||
use axum_client_ip::InsecureClientIp;
|
||||
use axum_extra::{TypedHeader, headers::UserAgent};
|
||||
use nym_http_api_common::middleware::client_ip::ClientIpAddr;
|
||||
use nym_statistics_common::report::vpn_client::{
|
||||
ActiveDeviceReport, StaticInformationReport, VpnClientStatsReport, VpnClientStatsReportV2,
|
||||
};
|
||||
@@ -35,15 +35,12 @@ pub(crate) fn routes() -> Router<AppState> {
|
||||
async fn submit_stats_report(
|
||||
State(mut state): State<AppState>,
|
||||
TypedHeader(user_agent): TypedHeader<UserAgent>,
|
||||
insecure_ip_addr: InsecureClientIp,
|
||||
ClientIpAddr(client_ip): ClientIpAddr,
|
||||
Json(report): Json<VpnClientStatsReport>,
|
||||
) -> HttpResult<Json<()>> {
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
|
||||
let gateway_record = state
|
||||
.network_view()
|
||||
.get_country_by_ip(&insecure_ip_addr.0)
|
||||
.await;
|
||||
let gateway_record = state.network_view().get_country_by_ip(&client_ip).await;
|
||||
|
||||
let from_mixnet = gateway_record.is_some();
|
||||
let maybe_location = gateway_record.unwrap_or_default();
|
||||
@@ -60,7 +57,7 @@ async fn submit_stats_report(
|
||||
&report,
|
||||
user_agent,
|
||||
from_mixnet,
|
||||
insecure_ip_addr.0,
|
||||
client_ip,
|
||||
maybe_location,
|
||||
);
|
||||
|
||||
@@ -93,15 +90,12 @@ async fn submit_stats_report(
|
||||
async fn submit_active_device(
|
||||
State(mut state): State<AppState>,
|
||||
TypedHeader(user_agent): TypedHeader<UserAgent>,
|
||||
insecure_ip_addr: InsecureClientIp,
|
||||
ClientIpAddr(client_ip): ClientIpAddr,
|
||||
Json(report): Json<ActiveDeviceReport>,
|
||||
) -> HttpResult<Json<()>> {
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
|
||||
let gateway_record = state
|
||||
.network_view()
|
||||
.get_country_by_ip(&insecure_ip_addr.0)
|
||||
.await;
|
||||
let gateway_record = state.network_view().get_country_by_ip(&client_ip).await;
|
||||
|
||||
let from_mixnet = gateway_record.is_some();
|
||||
|
||||
@@ -140,7 +134,7 @@ async fn submit_active_device(
|
||||
async fn submit_session_report(
|
||||
State(mut state): State<AppState>,
|
||||
TypedHeader(user_agent): TypedHeader<UserAgent>,
|
||||
insecure_ip_addr: InsecureClientIp, // This is the reverse proxy IP for now, but maybe in the future?
|
||||
ClientIpAddr(client_ip): ClientIpAddr,
|
||||
Json(report): Json<VpnClientStatsReportV2>,
|
||||
) -> HttpResult<Json<()>> {
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
@@ -164,7 +158,7 @@ async fn submit_session_report(
|
||||
&report,
|
||||
user_agent,
|
||||
from_mixnet,
|
||||
insecure_ip_addr.0,
|
||||
client_ip,
|
||||
maybe_location,
|
||||
);
|
||||
|
||||
|
||||
@@ -79,3 +79,13 @@ fn setup_cors() -> CorsLayer {
|
||||
.allow_headers(tower_http::cors::Any)
|
||||
.allow_credentials(false)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn router_constructs_without_panic() {
|
||||
let _ = RouterBuilder::with_default_routes().finalize_routes();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user