feat: expose node's chain address on self-described API (#6815)
* feat: expose nym-nodes' on-chain address on v2 auxiliary endpoint * moved swagger page outside the v1 route * fixed swagger endpoint for nym-api * post rebasing fixes * remove redundant impl OfflineSigner for Arc<DirectSecp256k1HdWallet>
This commit is contained in:
committed by
GitHub
parent
8a93bce32f
commit
931ec03b28
@@ -11,6 +11,8 @@ use cosmrs::tx;
|
||||
use cosmrs::tx::SignDoc;
|
||||
use nym_config::defaults;
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
|
||||
|
||||
|
||||
@@ -395,8 +395,8 @@ impl From<nym_node_requests::api::v1::node::models::AnnouncePorts> for AnnounceP
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nym_node_requests::api::v1::node::models::AuxiliaryDetails> for AuxiliaryDetailsV1 {
|
||||
fn from(value: nym_node_requests::api::v1::node::models::AuxiliaryDetails) -> Self {
|
||||
impl From<nym_node_requests::api::v1::node::models::AuxiliaryDetailsV1> for AuxiliaryDetailsV1 {
|
||||
fn from(value: nym_node_requests::api::v1::node::models::AuxiliaryDetailsV1) -> Self {
|
||||
AuxiliaryDetailsV1 {
|
||||
location: value.location,
|
||||
announce_ports: value.announce_ports.into(),
|
||||
|
||||
@@ -41,7 +41,7 @@ use utoipauto::utoipauto;
|
||||
nym_config::defaults::NymContracts,
|
||||
ContractVersionSchemaResponse,
|
||||
nym_bin_common::build_information::BinaryBuildInformationOwned,
|
||||
nym_node_requests::api::v1::node::models::AuxiliaryDetails,
|
||||
nym_node_requests::api::v1::node::models::AuxiliaryDetailsV1,
|
||||
nym_contracts_common::ContractBuildInformation
|
||||
))
|
||||
)]
|
||||
|
||||
@@ -16,7 +16,7 @@ use nym_lp::peer::{DHPublicKey, LpRemotePeer};
|
||||
use nym_lp_data::packet::version;
|
||||
use nym_network_defaults::DEFAULT_NYM_NODE_HTTP_PORT;
|
||||
use nym_node_requests::api::client::NymNodeApiClientExt;
|
||||
use nym_node_requests::api::v1::node::models::AuxiliaryDetails as NodeAuxiliaryDetails;
|
||||
use nym_node_requests::api::v1::node::models::AuxiliaryDetailsV1 as NodeAuxiliaryDetails;
|
||||
use nym_sdk::mixnet::NodeIdentity;
|
||||
use nym_sdk::mixnet::Recipient;
|
||||
use nym_validator_client::client::NymApiClientExt;
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::api::v1::ip_packet_router::models::IpPacketRouter;
|
||||
use crate::api::v1::network_requester::exit_policy::models::UsedExitPolicy;
|
||||
use crate::api::v1::network_requester::models::NetworkRequester;
|
||||
use crate::api::v1::node::models::{
|
||||
AuxiliaryDetails, NodeDescription, NodeRoles, SignedHostInformation,
|
||||
AuxiliaryDetailsV1, NodeDescription, NodeRoles, SignedHostInformation,
|
||||
};
|
||||
use crate::api::v1::node_load::models::NodeLoad;
|
||||
use crate::routes;
|
||||
@@ -55,7 +55,7 @@ pub trait NymNodeApiClientExt: ApiClient {
|
||||
self.get_json_from(routes::api::v1::roles_absolute()).await
|
||||
}
|
||||
|
||||
async fn get_auxiliary_details(&self) -> Result<AuxiliaryDetails, NymNodeApiClientError> {
|
||||
async fn get_auxiliary_details(&self) -> Result<AuxiliaryDetailsV1, NymNodeApiClientError> {
|
||||
self.get_json_from(routes::api::v1::auxiliary_absolute())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ use std::ops::Deref;
|
||||
pub mod client;
|
||||
pub mod helpers;
|
||||
pub mod v1;
|
||||
pub mod v2;
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
pub use client::Client;
|
||||
|
||||
@@ -12,6 +12,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::net::IpAddr;
|
||||
|
||||
pub use crate::api::SignedHostInformation;
|
||||
use crate::api::v2::node::models::AuxiliaryDetailsV2;
|
||||
pub use nym_bin_common::build_information::BinaryBuildInformationOwned;
|
||||
|
||||
#[derive(Clone, Default, Debug, Copy, Serialize, Deserialize, JsonSchema)]
|
||||
@@ -366,7 +367,7 @@ pub struct NodeDescription {
|
||||
/// Auxiliary details of the associated Nym Node.
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
pub struct AuxiliaryDetails {
|
||||
pub struct AuxiliaryDetailsV1 {
|
||||
/// Optional ISO 3166 alpha-2 two-letter country code of the node's **physical** location
|
||||
#[cfg_attr(feature = "openapi", schema(example = "PL", value_type = Option<String>))]
|
||||
#[schemars(with = "Option<String>")]
|
||||
@@ -383,6 +384,16 @@ pub struct AuxiliaryDetails {
|
||||
pub accepted_operator_terms_and_conditions: bool,
|
||||
}
|
||||
|
||||
impl From<AuxiliaryDetailsV2> for AuxiliaryDetailsV1 {
|
||||
fn from(v2: AuxiliaryDetailsV2) -> Self {
|
||||
Self {
|
||||
location: v2.location,
|
||||
announce_ports: v2.announce_ports,
|
||||
accepted_operator_terms_and_conditions: v2.accepted_operator_terms_and_conditions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
pub mod node;
|
||||
@@ -0,0 +1,4 @@
|
||||
// Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
pub mod models;
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::api::v1::node::models::AnnouncePorts;
|
||||
use celes::Country;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Auxiliary details of the associated Nym Node.
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
pub struct AuxiliaryDetailsV2 {
|
||||
/// Optional ISO 3166 alpha-2 two-letter country code of the node's **physical** location
|
||||
#[cfg_attr(feature = "openapi", schema(example = "PL", value_type = Option<String>))]
|
||||
#[schemars(with = "Option<String>")]
|
||||
#[schemars(length(equal = 2))]
|
||||
pub location: Option<Country>,
|
||||
|
||||
/// On-chain address of this node
|
||||
pub address: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub announce_ports: AnnouncePorts,
|
||||
|
||||
/// Specifies whether this node operator has agreed to the terms and conditions
|
||||
/// as defined at <https://nymtech.net/terms-and-conditions/operators/v1.0.0>
|
||||
// make sure to include the default deserialisation as this field hasn't existed when the struct was first created
|
||||
#[serde(default)]
|
||||
pub accepted_operator_terms_and_conditions: bool,
|
||||
}
|
||||
@@ -23,8 +23,14 @@ pub mod routes {
|
||||
|
||||
pub mod api {
|
||||
pub const V1: &str = "/v1";
|
||||
pub const V2: &str = "/v2";
|
||||
|
||||
// canonical, version-neutral Swagger UI mount
|
||||
pub const SWAGGER: &str = "/swagger";
|
||||
|
||||
absolute_route!(v1_absolute, super::API, V1);
|
||||
absolute_route!(v2_absolute, super::API, V2);
|
||||
absolute_route!(swagger_absolute, super::API, SWAGGER);
|
||||
|
||||
pub mod v1 {
|
||||
use super::*;
|
||||
@@ -152,6 +158,14 @@ pub mod routes {
|
||||
// use super::*;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod v2 {
|
||||
use super::*;
|
||||
|
||||
pub const AUXILIARY: &str = "/auxiliary-details";
|
||||
|
||||
absolute_route!(auxiliary_absolute, v2_absolute(), AUXILIARY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,15 +5,20 @@ use crate::node::http::state::AppState;
|
||||
use axum::Router;
|
||||
use nym_node_requests::routes;
|
||||
|
||||
pub mod openapi;
|
||||
pub mod v1;
|
||||
pub mod v2;
|
||||
|
||||
pub use nym_node_requests::api as api_requests;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub v1_config: v1::Config,
|
||||
pub v2_config: v2::Config,
|
||||
}
|
||||
|
||||
pub(super) fn routes(config: Config) -> Router<AppState> {
|
||||
Router::new().nest(routes::api::V1, v1::routes(config.v1_config))
|
||||
Router::new()
|
||||
.nest(routes::api::V1, v1::routes(config.v1_config))
|
||||
.nest(routes::api::V2, v2::routes(config.v2_config))
|
||||
}
|
||||
|
||||
+14
-8
@@ -3,7 +3,7 @@
|
||||
|
||||
use axum::Router;
|
||||
use nym_node_requests::api as api_requests;
|
||||
use nym_node_requests::routes::api::{v1, v1_absolute};
|
||||
use nym_node_requests::routes;
|
||||
use utoipa::openapi::security::{Http, HttpAuthScheme};
|
||||
use utoipa::{Modify, OpenApi, openapi::security::SecurityScheme};
|
||||
use utoipa_swagger_ui::SwaggerUi;
|
||||
@@ -37,12 +37,14 @@ use utoipa_swagger_ui::SwaggerUi;
|
||||
crate::node::http::router::api::v1::gateway::client_interfaces::wireguard_details,
|
||||
crate::node::http::router::api::v1::gateway::root::root_gateway,
|
||||
crate::node::http::router::api::v1::lewes_protocol::root::root_lewes_protocol,
|
||||
|
||||
crate::node::http::router::api::v2::node::auxiliary::auxiliary,
|
||||
),
|
||||
components(
|
||||
schemas(
|
||||
nym_http_api_common::Output,
|
||||
nym_http_api_common::OutputParams,
|
||||
nym_http_api_common::OutputV2,
|
||||
nym_http_api_common::OutputParamsV2,
|
||||
api_requests::v1::health::models::NodeHealth,
|
||||
api_requests::v1::health::models::NodeStatus,
|
||||
api_requests::v1::node_load::models::NodeLoad,
|
||||
@@ -56,7 +58,7 @@ use utoipa_swagger_ui::SwaggerUi;
|
||||
api_requests::v1::node::models::Cpu,
|
||||
api_requests::v1::node::models::CryptoHardware,
|
||||
api_requests::v1::node::models::NodeDescription,
|
||||
api_requests::v1::node::models::AuxiliaryDetails,
|
||||
api_requests::v1::node::models::AuxiliaryDetailsV1,
|
||||
api_requests::v1::metrics::models::LegacyMixingStats,
|
||||
api_requests::v1::metrics::models::VerlocStats,
|
||||
api_requests::v1::metrics::models::VerlocResult,
|
||||
@@ -77,6 +79,7 @@ use utoipa_swagger_ui::SwaggerUi;
|
||||
api_requests::v1::network_requester::exit_policy::models::UsedExitPolicy,
|
||||
api_requests::v1::ip_packet_router::models::IpPacketRouter,
|
||||
api_requests::v1::lewes_protocol::models::LewesProtocol,
|
||||
api_requests::v2::node::models::AuxiliaryDetailsV2,
|
||||
),
|
||||
),
|
||||
modifiers(&SecurityAddon),
|
||||
@@ -97,11 +100,14 @@ impl Modify for SecurityAddon {
|
||||
}
|
||||
|
||||
pub(crate) fn route<S: Send + Sync + 'static + Clone>() -> Router<S> {
|
||||
// provide absolute path to the openapi.json
|
||||
let config =
|
||||
utoipa_swagger_ui::Config::from(format!("{}/api-docs/openapi.json", v1_absolute()));
|
||||
SwaggerUi::new(v1::SWAGGER)
|
||||
.url("/api-docs/openapi.json", ApiDoc::openapi())
|
||||
// SwaggerUi must be mounted with its absolute path: it emits internal redirects
|
||||
// (e.g. `/swagger` → `/swagger/`) whose `Location` header uses this string
|
||||
// literally and is not aware of any `.nest()` prefix above it. For the same
|
||||
// reason, this router must be merged at the outer router level — not nested.
|
||||
let openapi_json = format!("{}/api-docs/openapi.json", routes::API);
|
||||
let config = utoipa_swagger_ui::Config::from(openapi_json.clone());
|
||||
SwaggerUi::new(routes::api::swagger_absolute())
|
||||
.url(openapi_json, ApiDoc::openapi())
|
||||
.config(config)
|
||||
.into()
|
||||
}
|
||||
@@ -11,7 +11,7 @@ use nym_node_requests::api::v1::authenticator::models::Authenticator;
|
||||
get,
|
||||
path = "",
|
||||
context_path = "/api/v1/authenticator",
|
||||
tag = "Authenticator",
|
||||
tag = "v1 / Authenticator",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
|
||||
@@ -41,7 +41,7 @@ pub(crate) fn routes<S: Send + Sync + 'static + Clone>(
|
||||
get,
|
||||
path = "/client-interfaces",
|
||||
context_path = "/api/v1/gateway",
|
||||
tag = "Gateway",
|
||||
tag = "v1 / Gateway",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
@@ -67,7 +67,7 @@ pub type ClientInterfacesResponse = FormattedResponse<ClientInterfaces>;
|
||||
get,
|
||||
path = "/mixnet-websockets",
|
||||
context_path = "/api/v1/gateway/client-interfaces",
|
||||
tag = "Gateway",
|
||||
tag = "v1 / Gateway",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
@@ -93,7 +93,7 @@ pub type MixnetWebSocketsResponse = FormattedResponse<WebSockets>;
|
||||
get,
|
||||
path = "/wireguard",
|
||||
context_path = "/api/v1/gateway/client-interfaces",
|
||||
tag = "Gateway",
|
||||
tag = "v1 / Gateway",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
|
||||
@@ -11,7 +11,7 @@ use nym_node_requests::api::v1::gateway::models::Gateway;
|
||||
get,
|
||||
path = "",
|
||||
context_path = "/api/v1/gateway",
|
||||
tag = "Gateway",
|
||||
tag = "v1 / Gateway",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
|
||||
@@ -11,7 +11,7 @@ use nym_node_requests::api::v1::health::models::NodeHealth;
|
||||
get,
|
||||
path = "/health",
|
||||
context_path = "/api/v1",
|
||||
tag = "Health",
|
||||
tag = "v1 / Health",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(NodeHealth = "application/json"),
|
||||
|
||||
@@ -11,7 +11,7 @@ use nym_node_requests::api::v1::ip_packet_router::models::IpPacketRouter;
|
||||
get,
|
||||
path = "",
|
||||
context_path = "/api/v1/ip-packet-router",
|
||||
tag = "IP Packet Router",
|
||||
tag = "v1 / IP Packet Router",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
// Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::Router;
|
||||
use axum::routing::get;
|
||||
use nym_node_requests::api::SignedLewesProtocol;
|
||||
|
||||
pub mod root;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub details: SignedLewesProtocol,
|
||||
}
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Config {}
|
||||
|
||||
pub(crate) fn routes<S: Send + Sync + 'static + Clone>(config: Config) -> Router<S> {
|
||||
Router::new().route(
|
||||
"/",
|
||||
get({
|
||||
let lp_config = config.details;
|
||||
move |query| root::root_lewes_protocol(lp_config, query)
|
||||
}),
|
||||
)
|
||||
pub(crate) fn routes(_config: Config) -> Router<AppState> {
|
||||
Router::new().route("/", get(root::root_lewes_protocol))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use axum::extract::Query;
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::extract::{Query, State};
|
||||
use axum::http::StatusCode;
|
||||
use nym_http_api_common::{FormattedResponse, OutputParams};
|
||||
use nym_node_requests::api::{SignedLewesProtocol, SignedLewesProtocolInfo};
|
||||
@@ -11,7 +12,7 @@ use nym_node_requests::api::{SignedLewesProtocol, SignedLewesProtocolInfo};
|
||||
get,
|
||||
path = "/lewes-protocol",
|
||||
context_path = "/api/v1",
|
||||
tag = "Lewes Protocol",
|
||||
tag = "v1 / Lewes Protocol",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
@@ -23,10 +24,10 @@ use nym_node_requests::api::{SignedLewesProtocol, SignedLewesProtocolInfo};
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn root_lewes_protocol(
|
||||
config: SignedLewesProtocol,
|
||||
Query(output): Query<OutputParams>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<LewesProtocolResponse, StatusCode> {
|
||||
Ok(output.to_response(config))
|
||||
Ok(output.to_response(state.static_information.lewes_protocol.clone()))
|
||||
}
|
||||
|
||||
pub type LewesProtocolResponse = FormattedResponse<SignedLewesProtocol>;
|
||||
|
||||
@@ -11,7 +11,7 @@ use nym_node_requests::api::v1::node_load::models::NodeLoad;
|
||||
get,
|
||||
path = "/load",
|
||||
context_path = "/api/v1",
|
||||
tag = "Node",
|
||||
tag = "v1 / Node",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(NodeLoad = "application/json"),
|
||||
|
||||
@@ -13,7 +13,7 @@ use nym_node_requests::api::v1::metrics::models::LegacyMixingStats;
|
||||
get,
|
||||
path = "/mixing",
|
||||
context_path = "/api/v1/metrics",
|
||||
tag = "Metrics",
|
||||
tag = "v1 / Metrics",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(LegacyMixingStats = "application/json"),
|
||||
|
||||
@@ -15,7 +15,7 @@ use nym_node_requests::api::v1::metrics::models::packets::{
|
||||
get,
|
||||
path = "/packets-stats",
|
||||
context_path = "/api/v1/metrics",
|
||||
tag = "Metrics",
|
||||
tag = "v1 / Metrics",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(PacketsStats = "application/json"),
|
||||
|
||||
@@ -8,7 +8,7 @@ use nym_metrics::metrics;
|
||||
get,
|
||||
path = "/prometheus",
|
||||
context_path = "/api/v1/metrics",
|
||||
tag = "Metrics",
|
||||
tag = "v1 / Metrics",
|
||||
responses(
|
||||
(status = 200, body = String),
|
||||
(status = 400, description = "`Authorization` header was missing"),
|
||||
|
||||
@@ -14,7 +14,7 @@ use time::macros::time;
|
||||
get,
|
||||
path = "/sessions",
|
||||
context_path = "/api/v1/metrics",
|
||||
tag = "Metrics",
|
||||
tag = "v1 / Metrics",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(SessionStats = "application/json"),
|
||||
|
||||
@@ -15,7 +15,7 @@ use crate::node::http::state::metrics::MetricsAppState;
|
||||
get,
|
||||
path = "/verloc",
|
||||
context_path = "/api/v1/metrics",
|
||||
tag = "Metrics",
|
||||
tag = "v1 / Metrics",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(VerlocStats = "application/json"),
|
||||
|
||||
@@ -13,7 +13,7 @@ use nym_node_requests::api::v1::metrics::models::WireguardStats;
|
||||
get,
|
||||
path = "/wireguard-stats",
|
||||
context_path = "/api/v1/metrics",
|
||||
tag = "Metrics",
|
||||
tag = "v1 / Metrics",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(WireguardStats = "application/json"),
|
||||
|
||||
@@ -11,7 +11,7 @@ use nym_node_requests::api::v1::mixnode::models::Mixnode;
|
||||
get,
|
||||
path = "",
|
||||
context_path = "/api/v1/mixnode",
|
||||
tag = "Mixnode",
|
||||
tag = "v1 / Mixnode",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::Router;
|
||||
use axum::response::Redirect;
|
||||
use axum::routing::get;
|
||||
use nym_node_requests::routes;
|
||||
use nym_node_requests::routes::api::v1;
|
||||
|
||||
pub mod authenticator;
|
||||
@@ -18,7 +20,6 @@ pub mod mixnode;
|
||||
pub mod network;
|
||||
pub mod network_requester;
|
||||
pub mod node;
|
||||
pub mod openapi;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
@@ -34,7 +35,12 @@ pub struct Config {
|
||||
}
|
||||
|
||||
pub(super) fn routes(config: Config) -> Router<AppState> {
|
||||
// legacy redirects: the Swagger UI moved to a version-neutral /api/swagger
|
||||
let swagger_redirect = get(|| async { Redirect::temporary(&routes::api::swagger_absolute()) });
|
||||
|
||||
Router::new()
|
||||
.route(v1::SWAGGER, swagger_redirect.clone())
|
||||
.route(&format!("{}/", v1::SWAGGER), swagger_redirect)
|
||||
.route(v1::HEALTH, get(health::root_health))
|
||||
.route(v1::LOAD, get(load::root_load))
|
||||
.nest(v1::NETWORK, network::routes())
|
||||
@@ -59,5 +65,4 @@ pub(super) fn routes(config: Config) -> Router<AppState> {
|
||||
lewes_protocol::routes(config.lewes_protocol),
|
||||
)
|
||||
.merge(node::routes(config.node))
|
||||
.merge(openapi::route())
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use nym_node_requests::api::v1::network::models::UpgradeModeStatus;
|
||||
get,
|
||||
path = "/upgrade-mode-status",
|
||||
context_path = "/api/v1/network",
|
||||
tag = "Network",
|
||||
tag = "v1 / Network",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(UpgradeModeStatus = "application/json"),
|
||||
|
||||
@@ -10,7 +10,7 @@ use nym_node_requests::api::v1::network_requester::exit_policy::models::UsedExit
|
||||
get,
|
||||
path = "/exit-policy",
|
||||
context_path = "/api/v1/network-requester",
|
||||
tag = "Network Requester",
|
||||
tag = "v1 / Network Requester",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(UsedExitPolicy = "application/json"),
|
||||
|
||||
@@ -11,7 +11,7 @@ use nym_node_requests::api::v1::network_requester::models::NetworkRequester;
|
||||
get,
|
||||
path = "",
|
||||
context_path = "/api/v1/network-requester",
|
||||
tag = "Network Requester",
|
||||
tag = "v1 / Network Requester",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
|
||||
@@ -2,30 +2,31 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::http::router::types::RequestError;
|
||||
use axum::extract::Query;
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::extract::{Query, State};
|
||||
use nym_http_api_common::{FormattedResponse, OutputParams};
|
||||
use nym_node_requests::api::v1::node::models::AuxiliaryDetails;
|
||||
use nym_node_requests::api::v1::node::models::AuxiliaryDetailsV1;
|
||||
|
||||
/// Returns auxiliary details of this node.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/auxiliary-details",
|
||||
context_path = "/api/v1",
|
||||
tag = "Node",
|
||||
tag = "v1 / Node",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(AuxiliaryDetails = "application/json"),
|
||||
(AuxiliaryDetails = "application/yaml")
|
||||
(AuxiliaryDetailsV1 = "application/json"),
|
||||
(AuxiliaryDetailsV1 = "application/yaml")
|
||||
)),
|
||||
),
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn auxiliary(
|
||||
description: AuxiliaryDetails,
|
||||
Query(output): Query<OutputParams>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<AuxiliaryDetailsResponse, RequestError> {
|
||||
let output = output.output.unwrap_or_default();
|
||||
Ok(output.to_response(description))
|
||||
Ok(output.to_response(state.static_information.auxiliary_data.clone().into()))
|
||||
}
|
||||
|
||||
pub type AuxiliaryDetailsResponse = FormattedResponse<AuxiliaryDetails>;
|
||||
pub type AuxiliaryDetailsResponse = FormattedResponse<AuxiliaryDetailsV1>;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use axum::extract::Query;
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::extract::{Query, State};
|
||||
use nym_http_api_common::{FormattedResponse, OutputParams};
|
||||
use nym_node_requests::api::v1::node::models::BinaryBuildInformationOwned;
|
||||
|
||||
@@ -10,7 +11,7 @@ use nym_node_requests::api::v1::node::models::BinaryBuildInformationOwned;
|
||||
get,
|
||||
path = "/build-information",
|
||||
context_path = "/api/v1",
|
||||
tag = "Node",
|
||||
tag = "v1 / Node",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(BinaryBuildInformationOwned = "application/json"),
|
||||
@@ -20,11 +21,11 @@ use nym_node_requests::api::v1::node::models::BinaryBuildInformationOwned;
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn build_information(
|
||||
build_information: BinaryBuildInformationOwned,
|
||||
Query(output): Query<OutputParams>,
|
||||
State(state): State<AppState>,
|
||||
) -> BuildInformationResponse {
|
||||
let output = output.output.unwrap_or_default();
|
||||
output.to_response(build_information)
|
||||
output.to_response(state.static_information.build_information.clone())
|
||||
}
|
||||
|
||||
pub type BuildInformationResponse = FormattedResponse<BinaryBuildInformationOwned>;
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::http::router::types::RequestError;
|
||||
use axum::extract::Query;
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::extract::{Query, State};
|
||||
use nym_http_api_common::{FormattedResponse, OutputParams};
|
||||
use nym_node_requests::api::v1::node::models::NodeDescription;
|
||||
|
||||
@@ -11,7 +12,7 @@ use nym_node_requests::api::v1::node::models::NodeDescription;
|
||||
get,
|
||||
path = "/description",
|
||||
context_path = "/api/v1",
|
||||
tag = "Node",
|
||||
tag = "v1 / Node",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(NodeDescription = "application/json"),
|
||||
@@ -21,11 +22,11 @@ use nym_node_requests::api::v1::node::models::NodeDescription;
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn description(
|
||||
description: NodeDescription,
|
||||
Query(output): Query<OutputParams>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<NodeDescriptionResponse, RequestError> {
|
||||
let output = output.output.unwrap_or_default();
|
||||
Ok(output.to_response(description))
|
||||
Ok(output.to_response(state.static_information.description.clone()))
|
||||
}
|
||||
|
||||
pub type NodeDescriptionResponse = FormattedResponse<NodeDescription>;
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::http::router::types::RequestError;
|
||||
use axum::extract::Query;
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::extract::{Query, State};
|
||||
use axum::http::StatusCode;
|
||||
use nym_http_api_common::{FormattedResponse, OutputParams};
|
||||
use nym_node_requests::api::v1::node::models::HostSystem;
|
||||
@@ -12,7 +13,7 @@ use nym_node_requests::api::v1::node::models::HostSystem;
|
||||
get,
|
||||
path = "/system-info",
|
||||
context_path = "/api/v1",
|
||||
tag = "Node",
|
||||
tag = "v1 / Node",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(HostSystem = "application/json"),
|
||||
@@ -23,12 +24,12 @@ use nym_node_requests::api::v1::node::models::HostSystem;
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn host_system(
|
||||
system_info: Option<HostSystem>,
|
||||
Query(output): Query<OutputParams>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<HostSystemResponse, RequestError> {
|
||||
let output = output.output.unwrap_or_default();
|
||||
|
||||
let Some(system_info) = system_info else {
|
||||
let Some(system_info) = state.static_information.system_info.clone() else {
|
||||
return Err(RequestError::new(
|
||||
"this nym-node does not wish to expose the system information",
|
||||
StatusCode::FORBIDDEN,
|
||||
|
||||
@@ -12,7 +12,7 @@ use nym_node_requests::api::{SignedDataHostInfo, v1::node::models::SignedHostInf
|
||||
get,
|
||||
path = "/host-information",
|
||||
context_path = "/api/v1",
|
||||
tag = "Node",
|
||||
tag = "v1 / Node",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(SignedDataHostInfo = "application/json"),
|
||||
|
||||
@@ -10,7 +10,6 @@ use crate::node::http::api::v1::node::roles::roles;
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::Router;
|
||||
use axum::routing::get;
|
||||
use nym_node_requests::api::v1::node::models;
|
||||
use nym_node_requests::routes::api::v1;
|
||||
|
||||
pub mod auxiliary;
|
||||
@@ -20,51 +19,15 @@ pub mod hardware;
|
||||
pub mod host_information;
|
||||
pub mod roles;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub build_information: models::BinaryBuildInformationOwned,
|
||||
pub system_info: Option<models::HostSystem>,
|
||||
pub roles: models::NodeRoles,
|
||||
pub description: models::NodeDescription,
|
||||
pub auxiliary_details: models::AuxiliaryDetails,
|
||||
}
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Config {}
|
||||
|
||||
pub(super) fn routes(config: Config) -> Router<AppState> {
|
||||
pub(super) fn routes(_config: Config) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
v1::BUILD_INFO,
|
||||
get({
|
||||
let build_info = config.build_information;
|
||||
move |query| build_information(build_info, query)
|
||||
}),
|
||||
)
|
||||
.route(
|
||||
v1::ROLES,
|
||||
get({
|
||||
let node_roles = config.roles;
|
||||
move |query| roles(node_roles, query)
|
||||
}),
|
||||
)
|
||||
.route(v1::BUILD_INFO, get(build_information))
|
||||
.route(v1::ROLES, get(roles))
|
||||
.route(v1::HOST_INFO, get(host_information))
|
||||
.route(
|
||||
v1::SYSTEM_INFO,
|
||||
get({
|
||||
let system_info = config.system_info;
|
||||
move |query| host_system(system_info, query)
|
||||
}),
|
||||
)
|
||||
.route(
|
||||
v1::NODE_DESCRIPTION,
|
||||
get({
|
||||
let node_description = config.description;
|
||||
move |query| description(node_description, query)
|
||||
}),
|
||||
)
|
||||
.route(
|
||||
v1::AUXILIARY,
|
||||
get({
|
||||
let auxiliary_details = config.auxiliary_details;
|
||||
move |query| auxiliary(auxiliary_details, query)
|
||||
}),
|
||||
)
|
||||
.route(v1::SYSTEM_INFO, get(host_system))
|
||||
.route(v1::NODE_DESCRIPTION, get(description))
|
||||
.route(v1::AUXILIARY, get(auxiliary))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use axum::extract::Query;
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::extract::{Query, State};
|
||||
use nym_http_api_common::{FormattedResponse, OutputParams};
|
||||
use nym_node_requests::api::v1::node::models::NodeRoles;
|
||||
|
||||
@@ -10,7 +11,7 @@ use nym_node_requests::api::v1::node::models::NodeRoles;
|
||||
get,
|
||||
path = "/roles",
|
||||
context_path = "/api/v1",
|
||||
tag = "Node",
|
||||
tag = "v1 / Node",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(NodeRoles = "application/json"),
|
||||
@@ -20,11 +21,11 @@ use nym_node_requests::api::v1::node::models::NodeRoles;
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn roles(
|
||||
node_roles: NodeRoles,
|
||||
Query(output): Query<OutputParams>,
|
||||
State(state): State<AppState>,
|
||||
) -> RolesResponse {
|
||||
let output = output.output.unwrap_or_default();
|
||||
output.to_response(node_roles)
|
||||
output.to_response(state.static_information.roles)
|
||||
}
|
||||
|
||||
pub type RolesResponse = FormattedResponse<NodeRoles>;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::Router;
|
||||
|
||||
pub mod node;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub node: node::Config,
|
||||
}
|
||||
|
||||
pub(super) fn routes(config: Config) -> Router<AppState> {
|
||||
Router::new().merge(node::routes(config.node))
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::http::router::types::RequestError;
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::extract::{Query, State};
|
||||
use nym_http_api_common::{FormattedResponse, OutputParamsV2};
|
||||
use nym_node_requests::api::v2::node::models::AuxiliaryDetailsV2;
|
||||
|
||||
/// Returns auxiliary details of this node.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/auxiliary-details",
|
||||
context_path = "/api/v2",
|
||||
tag = "v2 / Node",
|
||||
// distinct from v1's `auxiliary`: OpenAPI requires operationId to be unique
|
||||
// across the whole document, and Swagger UI routes "Try it out" by operationId
|
||||
operation_id = "v2_auxiliary",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(AuxiliaryDetailsV2 = "application/json"),
|
||||
(AuxiliaryDetailsV2 = "application/yaml")
|
||||
)),
|
||||
),
|
||||
params(OutputParamsV2)
|
||||
)]
|
||||
pub(crate) async fn auxiliary(
|
||||
Query(output): Query<OutputParamsV2>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<AuxiliaryDetailsResponse, RequestError> {
|
||||
let output = output.output.unwrap_or_default();
|
||||
Ok(output.to_response(state.static_information.auxiliary_data.clone()))
|
||||
}
|
||||
|
||||
pub type AuxiliaryDetailsResponse = FormattedResponse<AuxiliaryDetailsV2>;
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::http::api::v2::node::auxiliary::auxiliary;
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::Router;
|
||||
use axum::routing::get;
|
||||
use nym_node_requests::routes::api::v2;
|
||||
|
||||
pub mod auxiliary;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Config {}
|
||||
|
||||
pub(super) fn routes(_config: Config) -> Router<AppState> {
|
||||
Router::new().route(v2::AUXILIARY, get(auxiliary))
|
||||
}
|
||||
@@ -27,7 +27,7 @@ pub(super) async fn default() -> Html<&'static str> {
|
||||
<div>
|
||||
<p> default page of the nym node - you can customize it by setting the 'assets' path under '[http]' section of your config. </p>
|
||||
|
||||
You can explore the REST API at <a href = "/api/v1/swagger/">/api/v1/swagger/</a>
|
||||
You can explore the REST API at <a href = "/api/swagger/">/api/swagger/</a>
|
||||
</div>
|
||||
"#,
|
||||
)
|
||||
|
||||
@@ -2,22 +2,18 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::http::NymNodeHttpServer;
|
||||
use crate::node::http::api::v1::lewes_protocol;
|
||||
use crate::node::http::error::NymNodeHttpError;
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::Router;
|
||||
use axum::response::Redirect;
|
||||
use axum::routing::get;
|
||||
use nym_bin_common::bin_info_owned;
|
||||
use nym_http_api_common::middleware::logging;
|
||||
use nym_node_requests::api::SignedLewesProtocol;
|
||||
use nym_node_requests::api::v1::authenticator::models::Authenticator;
|
||||
use nym_node_requests::api::v1::gateway::models::{Bridges, 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;
|
||||
@@ -36,18 +32,12 @@ pub struct HttpServerConfig {
|
||||
}
|
||||
|
||||
impl HttpServerConfig {
|
||||
pub fn new(signed_lewes_protocol: SignedLewesProtocol) -> Self {
|
||||
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(),
|
||||
},
|
||||
node: api::v1::node::Config {},
|
||||
metrics: Default::default(),
|
||||
gateway: Default::default(),
|
||||
mixnode: Default::default(),
|
||||
@@ -55,9 +45,10 @@ impl HttpServerConfig {
|
||||
network_requester: Default::default(),
|
||||
ip_packet_router: Default::default(),
|
||||
authenticator: Default::default(),
|
||||
lewes_protocol: lewes_protocol::Config {
|
||||
details: signed_lewes_protocol,
|
||||
},
|
||||
lewes_protocol: Default::default(),
|
||||
},
|
||||
v2_config: api::v2::Config {
|
||||
node: api::v2::node::Config {},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -69,24 +60,6 @@ impl HttpServerConfig {
|
||||
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);
|
||||
@@ -179,6 +152,10 @@ impl NymNodeRouter {
|
||||
)
|
||||
.merge(landing_page::routes(config.landing))
|
||||
.nest(routes::API, api::routes(config.api))
|
||||
// openapi must be merged at the outer router level (not nested) —
|
||||
// SwaggerUi emits internal redirects that use absolute paths
|
||||
// unaware of any `.nest()` prefix
|
||||
.merge(api::openapi::route())
|
||||
.layer(axum::middleware::from_fn(logging::log_request_info))
|
||||
.with_state(state),
|
||||
}
|
||||
@@ -208,20 +185,10 @@ impl NymNodeRouter {
|
||||
#[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 config = HttpServerConfig::new();
|
||||
let _ = NymNodeRouter::new(config, AppState::dummy());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
use crate::node::http::state::load::CachedNodeLoad;
|
||||
use crate::node::http::state::metrics::MetricsAppState;
|
||||
use crate::node::key_rotation::active_keys::ActiveSphinxKeys;
|
||||
use nym_bin_common::build_information::BinaryBuildInformationOwned;
|
||||
use nym_credential_verification::UpgradeModeState;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_node_metrics::NymNodeMetrics;
|
||||
use nym_node_requests::api::SignedLewesProtocol;
|
||||
use nym_node_requests::api::v1::node::models::{HostSystem, NodeDescription, NodeRoles};
|
||||
use nym_node_requests::api::v2::node::models::AuxiliaryDetailsV2;
|
||||
use nym_noise_keys::VersionedNoiseKeyV1;
|
||||
use nym_verloc::measurements::SharedVerlocStats;
|
||||
use std::net::IpAddr;
|
||||
@@ -23,6 +27,14 @@ pub(crate) struct StaticNodeInformation {
|
||||
pub(crate) x25519_versioned_noise_key: Option<VersionedNoiseKeyV1>,
|
||||
pub(crate) ip_addresses: Vec<IpAddr>,
|
||||
pub(crate) hostname: Option<String>,
|
||||
|
||||
// TODO: move other fields here too
|
||||
pub(crate) build_information: BinaryBuildInformationOwned,
|
||||
pub(crate) system_info: Option<HostSystem>,
|
||||
pub(crate) roles: NodeRoles,
|
||||
pub(crate) description: NodeDescription,
|
||||
pub(crate) auxiliary_data: AuxiliaryDetailsV2,
|
||||
pub(crate) lewes_protocol: SignedLewesProtocol,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -77,15 +89,34 @@ impl AppState {
|
||||
#[cfg(test)]
|
||||
pub(crate) fn dummy() -> Self {
|
||||
use crate::node::key_rotation::key::SphinxPrivateKey;
|
||||
use nym_crypto::asymmetric::x25519;
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
let ed25519_keys = ed25519::KeyPair::new(&mut OsRng);
|
||||
let mut rng = nym_test_utils::helpers::deterministic_rng();
|
||||
let ed25519_keys = ed25519::KeyPair::new(&mut rng);
|
||||
let x25519_pub: x25519::DHPublicKey = x25519::PrivateKey::new(&mut rng).public_key().into();
|
||||
let lp = nym_node_requests::api::v1::lewes_protocol::models::LewesProtocol::new(
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
x25519_pub,
|
||||
std::collections::BTreeMap::new(),
|
||||
);
|
||||
let signed =
|
||||
nym_node_requests::api::SignedData::new(lp, ed25519_keys.private_key()).unwrap();
|
||||
|
||||
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,
|
||||
build_information: nym_bin_common::bin_info_owned!(),
|
||||
system_info: None,
|
||||
roles: Default::default(),
|
||||
description: Default::default(),
|
||||
auxiliary_data: Default::default(),
|
||||
lewes_protocol: signed,
|
||||
};
|
||||
let active_sphinx = ActiveSphinxKeys::new_fresh(SphinxPrivateKey::new(&mut OsRng, 0));
|
||||
|
||||
|
||||
+42
-24
@@ -45,12 +45,10 @@ use crate::node::routing_filter::{OpenFilter, RoutingFilter};
|
||||
use crate::node::shared_network::CachedNetwork;
|
||||
use crate::node::shared_network::refresher::{NetworkRefresher, NetworkRefresherConfig};
|
||||
use crate::node::shared_network::topology_provider::{CachedTopologyProvider, LocalGatewayNode};
|
||||
use nym_bin_common::bin_info;
|
||||
use nym_bin_common::{bin_info, bin_info_owned};
|
||||
use nym_config::defaults::NymNetworkDetails;
|
||||
use nym_credential_verification::UpgradeModeState;
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
pub use nym_gateway::node::ActiveClientsStore;
|
||||
pub use nym_gateway::node::GatewayStorage;
|
||||
use nym_gateway::node::wireguard::PeerRegistrator;
|
||||
use nym_gateway::node::{GatewayTasksBuilder, UpgradeModeCheckRequestSender};
|
||||
use nym_kkt::key_utils::{
|
||||
@@ -69,15 +67,18 @@ use nym_node_metrics::NymNodeMetrics;
|
||||
use nym_node_metrics::events::MetricEventsSender;
|
||||
use nym_node_requests::api::SignedData;
|
||||
use nym_node_requests::api::v1::lewes_protocol::models::{LPHashFunction, LPKEM, LewesProtocol};
|
||||
use nym_node_requests::api::v1::node::models::{AnnouncePorts, NodeDescription};
|
||||
use nym_node_requests::api::v1::node::models::{AnnouncePorts, NodeDescription, NodeRoles};
|
||||
use nym_noise::config::{NetworkMonitorAgentNode, NoiseConfig, NoiseNetworkView};
|
||||
use nym_noise_keys::VersionedNoiseKeyV1;
|
||||
use nym_sphinx_acknowledgements::AckKey;
|
||||
use nym_sphinx_addressing::Recipient;
|
||||
use nym_task::{ShutdownManager, ShutdownToken, ShutdownTracker};
|
||||
use nym_validator_client::nyxd::AccountId;
|
||||
use nym_validator_client::nyxd::contract_traits::PagedNetworkMonitorsQueryClient;
|
||||
use nym_validator_client::nyxd::error::NyxdError;
|
||||
use nym_validator_client::nyxd::nym_network_monitors_contract_common::AuthorisedNetworkMonitor;
|
||||
use nym_validator_client::{QueryHttpRpcNyxdClient, UserAgent};
|
||||
use nym_validator_client::signing::signer::OfflineSigner;
|
||||
use nym_validator_client::{DirectSecp256k1HdWallet, QueryHttpRpcNyxdClient, UserAgent};
|
||||
use nym_verloc::measurements::SharedVerlocStats;
|
||||
use nym_verloc::{self, measurements::VerlocMeasurer};
|
||||
use nym_wireguard::{WireguardGatewayData, peer_controller::PeerControlRequest};
|
||||
@@ -95,6 +96,9 @@ use tokio_util::sync::WaitForCancellationFutureOwned;
|
||||
use tracing::{debug, error, info, trace};
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
pub use nym_gateway::node::ActiveClientsStore;
|
||||
pub use nym_gateway::node::GatewayStorage;
|
||||
|
||||
pub mod bonding_information;
|
||||
pub mod description;
|
||||
pub mod helpers;
|
||||
@@ -892,12 +896,27 @@ impl NymNode {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn node_chain_address(&self) -> Result<AccountId, NymNodeError> {
|
||||
let network_details = NymNetworkDetails::new_from_env();
|
||||
|
||||
// derive the address (annoyingly, this will derive our private keys that we will rederive
|
||||
// when starting the gateway, but changing this behaviour requires too much refactoring)
|
||||
let wallet = DirectSecp256k1HdWallet::checked_from_mnemonic(
|
||||
&network_details.chain_details.bech32_account_prefix,
|
||||
(**self.entry_gateway.mnemonic).clone(),
|
||||
)
|
||||
.map_err(NyxdError::from)?;
|
||||
|
||||
Ok(wallet.get_accounts()[0].address.clone())
|
||||
}
|
||||
|
||||
pub(crate) async fn build_http_server(
|
||||
&self,
|
||||
shutdown: WaitForCancellationFutureOwned,
|
||||
) -> Result<NymNodeHttpServer, NymNodeError> {
|
||||
let auxiliary_details = api_requests::v1::node::models::AuxiliaryDetails {
|
||||
let auxiliary_data = api_requests::v2::node::models::AuxiliaryDetailsV2 {
|
||||
location: self.config.host.location,
|
||||
address: self.node_chain_address()?.to_string(),
|
||||
announce_ports: AnnouncePorts {
|
||||
verloc_port: self.config.verloc.announce_port,
|
||||
mix_port: self.config.mixnet.announce_port,
|
||||
@@ -982,7 +1001,7 @@ impl NymNode {
|
||||
let signed_lewes_protocol =
|
||||
SignedData::new(lewes_protocol, self.ed25519_identity_keys.private_key()).unwrap();
|
||||
|
||||
let mut config = HttpServerConfig::new(signed_lewes_protocol)
|
||||
let mut config = HttpServerConfig::new()
|
||||
.with_landing_page_assets(self.config.http.landing_page_assets_path.as_ref())
|
||||
.with_mixnode_details(mixnode_details)
|
||||
.with_gateway_details(gateway_details)
|
||||
@@ -990,28 +1009,16 @@ impl NymNode {
|
||||
.with_ip_packet_router_details(ipr_details)
|
||||
.with_authenticator_details(auth_details)
|
||||
.with_used_exit_policy(exit_policy_details)
|
||||
.with_description(self.description.clone())
|
||||
.with_auxiliary_details(auxiliary_details)
|
||||
.with_prometheus_bearer_token(self.config.http.access_token.clone());
|
||||
|
||||
if self.config.http.expose_system_info {
|
||||
config = config.with_system_info(get_system_info(
|
||||
let system_info = if self.config.http.expose_system_info {
|
||||
Some(get_system_info(
|
||||
self.config.http.expose_system_hardware,
|
||||
self.config.http.expose_crypto_hardware,
|
||||
))
|
||||
}
|
||||
if self.config.modes.mixnode {
|
||||
config.api.v1_config.node.roles.mixnode_enabled = true;
|
||||
}
|
||||
|
||||
if self.config.modes.entry {
|
||||
config.api.v1_config.node.roles.gateway_enabled = true
|
||||
}
|
||||
|
||||
if self.config.modes.exit {
|
||||
config.api.v1_config.node.roles.network_requester_enabled = true;
|
||||
config.api.v1_config.node.roles.ip_packet_router_enabled = true;
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(path) = &self.config.gateway_tasks.storage_paths.bridge_client_params {
|
||||
config = config.with_bridge_client_params_file(path);
|
||||
@@ -1032,6 +1039,17 @@ impl NymNode {
|
||||
x25519_versioned_noise_key,
|
||||
ip_addresses: self.config.host.public_ips.clone(),
|
||||
hostname: self.config.host.hostname.clone(),
|
||||
build_information: bin_info_owned!(),
|
||||
system_info,
|
||||
roles: NodeRoles {
|
||||
mixnode_enabled: self.config.modes.mixnode,
|
||||
gateway_enabled: self.config.modes.entry,
|
||||
network_requester_enabled: self.config.modes.exit,
|
||||
ip_packet_router_enabled: self.config.modes.exit,
|
||||
},
|
||||
description: self.description.clone(),
|
||||
auxiliary_data,
|
||||
lewes_protocol: signed_lewes_protocol,
|
||||
},
|
||||
self.active_sphinx_keys()?.clone(),
|
||||
self.metrics.clone(),
|
||||
|
||||
Reference in New Issue
Block a user