Files
nym/nym-node/src/node/http/router/mod.rs
T
Jędrzej Stuczyński d8c84cc4d6 feat: key rotation (#5777)
* wip

* wip: wrap node's sphinx key with a manager

* wip: choosing correct key for packet processing

* further propagation of key rotation information

* attaching key rotation information to reply surbs

* added basic key rotation information to mixnet contract

* wip: introducing cached queries for key rotation info from nym api

* unified nym-api contract cache refreshing

* finish packet decoding

* multi api client + retrieving rotation id

* rotating sphinx key files

* logic for migrating config file

* wip: putting new sphinx keys to self described endpoints

* processing loop of KeyRotationController

* fixed sphinx key loading

* rotating bloomfilters

* wired up KeyRotationController

* flushing bloomfilters to disk and loading

* most of nym-node changes

* post rebase fixes

* fixes due to backwards compatible hostkeys

* split http state.rs file

* dont use deprecated fields

* fixed backwards compatible deserialisation of host information

* split up node describe cache

* added a dedicated CacheRefresher listener to perform full refresh outside the set interval

* controlling announced sphinx keys within nym-api

* retrieving rotation id when pulling topology

* split nym-nodes http handlers

* v2 nym-api endpoints to retrieve nodes with additional metadata information

* bug fixes...

* additional bugfixes and guards against stuck epoch

* testnet manager: set first nym-api as the rewarder

* fixed host information deserialisation

* fixed panic during first key rotation

* post rebase fixes

* clippy

* more guards against stuck epochs

* added helper method to reset node's sphinx key

* instantiate mixnet contract with custom key rotation validity

* additional bugfixes and debugging nym-api deadlock

* passing shutdown to nym apis client

* remove dead test

* post rebasing fixes

* missing MixnetQueryClient variants

* remove usage of deprecated methods in sdk example

* fix: incorrect method signature

* post rebasing fixes

* attempt to retrieve key rotation id before doing any config migration work

* ignore tests relying on networking behaviour

* allow networking failures in certain tests
2025-06-03 11:22:51 +01:00

184 lines
6.1 KiB
Rust

// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::node::http::error::NymNodeHttpError;
use crate::node::http::state::AppState;
use crate::node::http::NymNodeHttpServer;
use axum::response::Redirect;
use axum::routing::get;
use axum::Router;
use nym_bin_common::bin_info_owned;
use nym_http_api_common::middleware::logging;
use nym_node_requests::api::v1::authenticator::models::Authenticator;
use nym_node_requests::api::v1::gateway::models::Gateway;
use nym_node_requests::api::v1::ip_packet_router::models::IpPacketRouter;
use nym_node_requests::api::v1::mixnode::models::Mixnode;
use nym_node_requests::api::v1::network_requester::exit_policy::models::UsedExitPolicy;
use nym_node_requests::api::v1::network_requester::models::NetworkRequester;
use nym_node_requests::api::v1::node::models::{AuxiliaryDetails, HostSystem, NodeDescription};
use nym_node_requests::routes;
use std::net::SocketAddr;
use std::path::Path;
use std::sync::Arc;
use zeroize::Zeroizing;
pub mod api;
pub mod landing_page;
pub mod types;
#[derive(Debug, Clone)]
pub struct HttpServerConfig {
pub landing: landing_page::Config,
pub api: api::Config,
}
impl HttpServerConfig {
pub fn new() -> Self {
HttpServerConfig {
landing: Default::default(),
api: api::Config {
v1_config: api::v1::Config {
node: api::v1::node::Config {
build_information: bin_info_owned!(),
system_info: None,
roles: Default::default(),
description: Default::default(),
auxiliary_details: Default::default(),
},
metrics: Default::default(),
gateway: Default::default(),
mixnode: Default::default(),
network_requester: Default::default(),
ip_packet_router: Default::default(),
authenticator: Default::default(),
},
},
}
}
#[must_use]
pub fn with_landing_page_assets<P: AsRef<Path>>(mut self, assets_path: Option<P>) -> Self {
self.landing.assets_path = assets_path.map(|p| p.as_ref().to_path_buf());
self
}
#[must_use]
pub fn with_system_info(mut self, info: HostSystem) -> Self {
self.api.v1_config.node.system_info = Some(info);
self
}
#[must_use]
pub fn with_description(mut self, description: NodeDescription) -> Self {
self.api.v1_config.node.description = description;
self
}
#[must_use]
pub fn with_auxiliary_details(mut self, auxiliary_details: AuxiliaryDetails) -> Self {
self.api.v1_config.node.auxiliary_details = auxiliary_details;
self
}
#[must_use]
pub fn with_gateway_details(mut self, gateway: Gateway) -> Self {
self.api.v1_config.gateway.details = Some(gateway);
self
}
#[must_use]
pub fn with_mixnode_details(mut self, mixnode: Mixnode) -> Self {
self.api.v1_config.mixnode.details = Some(mixnode);
self
}
#[must_use]
pub fn with_network_requester_details(mut self, network_requester: NetworkRequester) -> Self {
self.api.v1_config.network_requester.details = Some(network_requester);
self
}
#[must_use]
pub fn with_used_exit_policy(mut self, exit_policy: UsedExitPolicy) -> Self {
self.api.v1_config.network_requester.exit_policy = Some(exit_policy);
self
}
#[must_use]
pub fn with_ip_packet_router_details(mut self, ip_packet_router: IpPacketRouter) -> Self {
self.api.v1_config.ip_packet_router.details = Some(ip_packet_router);
self
}
#[must_use]
pub fn with_authenticator_details(mut self, authenticator: Authenticator) -> Self {
self.api.v1_config.authenticator.details = Some(authenticator);
self
}
#[must_use]
pub fn with_prometheus_bearer_token(mut self, bearer_token: Option<String>) -> Self {
self.api.v1_config.metrics.bearer_token = bearer_token.map(|b| Arc::new(Zeroizing::new(b)));
self
}
}
pub struct NymNodeRouter {
inner: Router,
}
impl NymNodeRouter {
pub fn new(config: HttpServerConfig, state: AppState) -> NymNodeRouter {
NymNodeRouter {
inner: Router::new()
// redirection for old legacy mixnode routes
.route(
"/hardware",
get(|| async { Redirect::to(&routes::api::v1::system_info_absolute()) }),
)
.route(
"/description",
get(|| async { Redirect::to(&routes::api::v1::description_absolute()) }),
)
.route(
"/stats",
get(|| async {
Redirect::to(&routes::api::v1::metrics::legacy_mixing_absolute())
}),
)
.route(
"/verloc",
get(|| async { Redirect::to(&routes::api::v1::metrics::verloc_absolute()) }),
)
.route(
"/metrics",
get(|| async {
Redirect::to(&routes::api::v1::metrics::prometheus_absolute())
}),
)
.nest(routes::LANDING_PAGE, landing_page::routes(config.landing))
.nest(routes::API, api::routes(config.api))
.layer(axum::middleware::from_fn(logging::log_request_info))
.with_state(state),
}
}
pub async fn build_server(
self,
bind_address: &SocketAddr,
) -> Result<NymNodeHttpServer, NymNodeHttpError> {
let listener = tokio::net::TcpListener::bind(bind_address)
.await
.map_err(|source| NymNodeHttpError::HttpBindFailure {
bind_address: *bind_address,
source,
})?;
Ok(axum::serve(
listener,
self.inner
.into_make_service_with_connect_info::<SocketAddr>(),
))
}
}