diff --git a/gateway/src/error.rs b/gateway/src/error.rs index 5f2f9d4299..edf34b3a95 100644 --- a/gateway/src/error.rs +++ b/gateway/src/error.rs @@ -148,6 +148,9 @@ pub enum GatewayError { #[error("failed to startup local ip packet router")] IpPacketRouterStartupFailure, + #[error("failed to startup local authenticator")] + AuthenticatorStartupFailure, + #[error("there are no nym API endpoints available")] NoNymApisAvailable, diff --git a/gateway/src/node/mod.rs b/gateway/src/node/mod.rs index ada40c10a7..3f8690dd79 100644 --- a/gateway/src/node/mod.rs +++ b/gateway/src/node/mod.rs @@ -47,6 +47,16 @@ struct StartedNetworkRequester { handle: LocalEmbeddedClientHandle, } +// TODO: should this struct live here? +#[allow(unused)] +struct StartedAuthenticator { + #[cfg(feature = "wireguard")] + wg_api: Arc, + + /// Handle to interact with the local authenticator + handle: LocalEmbeddedClientHandle, +} + /// Wire up and create Gateway instance pub async fn create_gateway( config: Config, @@ -238,17 +248,63 @@ impl Gateway { #[cfg(all(feature = "wireguard", target_os = "linux"))] async fn start_authenticator( &mut self, - opts: &LocalAuthenticatorOpts, + forwarding_channel: MixForwardingSender, shutdown: TaskClient, - ) -> Result, Box> { + ) -> Result> { + let opts = self + .authenticator_opts + .as_ref() + .ok_or(GatewayError::UnspecifiedAuthenticatorConfig)?; + let (router_tx, mut router_rx) = oneshot::channel(); + let (auth_mix_sender, auth_mix_receiver) = mpsc::unbounded(); + let router_shutdown = shutdown.fork("message_router"); + let transceiver = LocalGateway::new( + *self.identity_keypair.public_key(), + forwarding_channel, + router_tx, + ); + if let Some(wireguard_data) = self.wireguard_data.take() { - let authenticator_server = nym_authenticator::Authenticator::new( + let (on_start_tx, on_start_rx) = oneshot::channel(); + let mut authenticator_server = nym_authenticator::Authenticator::new( opts.config.clone(), wireguard_data.inner.clone(), ) - .with_shutdown(shutdown.fork("authenticator")); - tokio::spawn(async move { authenticator_server.run_service_provider().await }); - nym_wireguard::start_wireguard(shutdown, wireguard_data).await + .with_custom_gateway_transceiver(Box::new(transceiver)) + .with_shutdown(shutdown.fork("authenticator")) + .with_wait_for_gateway(true) + .with_minimum_gateway_performance(0) + .with_on_start(on_start_tx); + + if let Some(custom_mixnet) = &opts.custom_mixnet_path { + authenticator_server = authenticator_server.with_stored_topology(custom_mixnet)? + } + + tokio::spawn(async move { + if let Err(e) = authenticator_server.run_service_provider().await { + log::error!("Run authenticator server - {e}"); + } + }); + + let start_data = on_start_rx + .await + .map_err(|_| GatewayError::AuthenticatorStartupFailure)?; + + // this should be instantaneous since the data is sent on this channel before the on start is called; + // the failure should be impossible + let Ok(Some(packet_router)) = router_rx.try_recv() else { + return Err(Box::new(GatewayError::AuthenticatorStartupFailure)); + }; + + MessageRouter::new(auth_mix_receiver, packet_router) + .start_with_shutdown(router_shutdown); + + let wg_api = nym_wireguard::start_wireguard(shutdown, wireguard_data).await?; + + Ok(StartedAuthenticator { + wg_api, + handle: LocalEmbeddedClientHandle::new(start_data.address, auth_mix_sender), + }) } else { Err(Box::new(GatewayError::WireguardNotSet)) } @@ -257,9 +313,9 @@ impl Gateway { #[cfg(all(feature = "wireguard", not(target_os = "linux")))] async fn start_authenticator( &self, - _opts: &LocalAuthenticatorOpts, + _forwarding_channel: MixForwardingSender, _shutdown: TaskClient, - ) -> Result, Box> { + ) -> Result> { todo!("Authenticator is currently only supported on Linux"); } @@ -554,7 +610,7 @@ impl Gateway { if self.config.ip_packet_router.enabled { let embedded_ip_sp = self .start_ip_packet_router( - mix_forwarding_channel, + mix_forwarding_channel.clone(), shutdown.fork("ip_service_provider"), ) .await?; @@ -564,14 +620,13 @@ impl Gateway { }; #[cfg(feature = "wireguard")] - let _wg_api = if let Some(opts) = self.authenticator_opts.clone() { - Some( - self.start_authenticator(&opts, shutdown.fork("wireguard")) - .await - .map_err(|source| GatewayError::AuthenticatorStartError { source })?, - ) - } else { - None + let _wg_api = { + let embedded_auth = self + .start_authenticator(mix_forwarding_channel, shutdown.fork("authenticator")) + .await + .map_err(|source| GatewayError::AuthenticatorStartError { source })?; + active_clients_store.insert_embedded(embedded_auth.handle); + Some(embedded_auth.wg_api) }; if self.run_http_server { diff --git a/nym-node/src/cli/commands/migrate.rs b/nym-node/src/cli/commands/migrate.rs index 1b97a769f9..f44bdc399b 100644 --- a/nym-node/src/cli/commands/migrate.rs +++ b/nym-node/src/cli/commands/migrate.rs @@ -409,9 +409,6 @@ async fn migrate_gateway(mut args: Args) -> Result<(), NymNodeError> { bind_address: SocketAddr::new(ip, cfg.gateway.clients_port), announce_ws_port: None, announce_wss_port: cfg.gateway.clients_wss_port, - authenticator: config::authenticator::Authenticator { - debug: Default::default(), - }, debug: config::entry_gateway::Debug { message_retrieval_limit: cfg.debug.message_retrieval_limit, }, @@ -457,9 +454,6 @@ async fn migrate_gateway(mut args: Args) -> Result<(), NymNodeError> { .unwrap_or_default(), }, }, - authenticator: config::authenticator::Authenticator { - debug: Default::default(), - }, }), ) .build(); diff --git a/nym-node/src/config/entry_gateway.rs b/nym-node/src/config/entry_gateway.rs index e93c1825e1..d4ef188da9 100644 --- a/nym-node/src/config/entry_gateway.rs +++ b/nym-node/src/config/entry_gateway.rs @@ -8,11 +8,13 @@ use crate::error::EntryGatewayError; use nym_config::defaults::DEFAULT_CLIENT_LISTENING_PORT; use nym_config::helpers::inaddr_any; use nym_config::serde_helpers::de_maybe_port; +use nym_gateway::node::LocalAuthenticatorOpts; use serde::{Deserialize, Serialize}; use std::net::SocketAddr; use std::path::Path; -use super::authenticator::Authenticator; +use super::helpers::{base_client_config, EphemeralConfig}; +use super::LocalWireguardOpts; pub const DEFAULT_WS_PORT: u16 = DEFAULT_CLIENT_LISTENING_PORT; @@ -40,8 +42,6 @@ pub struct EntryGatewayConfig { #[serde(deserialize_with = "de_maybe_port")] pub announce_wss_port: Option, - pub authenticator: Authenticator, - #[serde(default)] pub debug: Debug, } @@ -73,7 +73,6 @@ impl EntryGatewayConfig { bind_address: SocketAddr::new(inaddr_any(), DEFAULT_WS_PORT), announce_ws_port: None, announce_wss_port: None, - authenticator: Default::default(), debug: Default::default(), } } @@ -83,6 +82,44 @@ impl EntryGatewayConfig { pub fn ephemeral_entry_gateway_config( config: Config, mnemonic: &bip39::Mnemonic, -) -> Result { - Ok(ephemeral_gateway_config(config, mnemonic)?) +) -> Result { + let auth_opts = LocalAuthenticatorOpts { + config: nym_authenticator::Config { + base: nym_client_core_config_types::Config { + client: base_client_config(&config), + debug: config.authenticator.debug.client_debug, + }, + authenticator: config.wireguard.clone().into(), + storage_paths: nym_authenticator::config::AuthenticatorPaths { + common_paths: config + .exit_gateway + .storage_paths + .authenticator + .to_common_client_paths(), + }, + logging: config.logging, + }, + custom_mixnet_path: None, + }; + + let wg_opts = LocalWireguardOpts { + config: super::Wireguard { + enabled: config.wireguard.enabled, + bind_address: config.wireguard.bind_address, + private_ip: config.wireguard.private_ip, + announced_port: config.wireguard.announced_port, + private_network_prefix: config.wireguard.private_network_prefix, + storage_paths: config.wireguard.storage_paths.clone(), + }, + custom_mixnet_path: None, + }; + + let gateway = ephemeral_gateway_config(config, mnemonic)?; + Ok(EphemeralConfig { + nr_opts: None, + ipr_opts: None, + auth_opts, + wg_opts, + gateway, + }) } diff --git a/nym-node/src/config/exit_gateway.rs b/nym-node/src/config/exit_gateway.rs index e86b63907d..1ad3e42f02 100644 --- a/nym-node/src/config/exit_gateway.rs +++ b/nym-node/src/config/exit_gateway.rs @@ -5,7 +5,6 @@ use crate::config::helpers::ephemeral_gateway_config; use crate::config::persistence::ExitGatewayPaths; use crate::config::Config; use crate::error::ExitGatewayError; -use clap::crate_version; use nym_client_core_config_types::DebugConfig as ClientDebugConfig; use nym_config::defaults::mainnet; use nym_gateway::node::{ @@ -15,7 +14,10 @@ use serde::{Deserialize, Serialize}; use std::path::Path; use url::Url; -use super::{authenticator::Authenticator, LocalWireguardOpts}; +use super::{ + helpers::{base_client_config, EphemeralConfig}, + LocalWireguardOpts, +}; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] @@ -32,8 +34,6 @@ pub struct ExitGatewayConfig { pub network_requester: NetworkRequester, pub ip_packet_router: IpPacketRouter, - - pub authenticator: Authenticator, } impl ExitGatewayConfig { @@ -49,7 +49,6 @@ impl ExitGatewayConfig { .expect("invalid default exit policy URL"), network_requester: Default::default(), ip_packet_router: Default::default(), - authenticator: Default::default(), } } } @@ -139,25 +138,6 @@ impl Default for IpPacketRouterDebug { } } -pub struct EphemeralConfig { - pub gateway: nym_gateway::config::Config, - pub nr_opts: LocalNetworkRequesterOpts, - pub ipr_opts: LocalIpPacketRouterOpts, - pub auth_opts: LocalAuthenticatorOpts, - pub wg_opts: LocalWireguardOpts, -} - -fn base_client_config(config: &Config) -> nym_client_core_config_types::Client { - nym_client_core_config_types::Client { - version: format!("{}-nym-node", crate_version!()), - id: config.id.clone(), - // irrelevant field - no need for credentials in embedded mode - disabled_credentials_mode: true, - nyxd_urls: config.mixnet.nyxd_urls.clone(), - nym_api_urls: config.mixnet.nym_api_urls.clone(), - } -} - // that function is rather disgusting, but I hope it's not going to live for too long pub fn ephemeral_exit_gateway_config( config: Config, @@ -244,7 +224,7 @@ pub fn ephemeral_exit_gateway_config( config: nym_authenticator::Config { base: nym_client_core_config_types::Config { client: base_client_config(&config), - debug: config.exit_gateway.authenticator.debug.client_debug, + debug: config.authenticator.debug.client_debug, }, authenticator: config.wireguard.clone().into(), storage_paths: nym_authenticator::config::AuthenticatorPaths { @@ -253,7 +233,6 @@ pub fn ephemeral_exit_gateway_config( .storage_paths .authenticator .to_common_client_paths(), - authenticator_description: Default::default(), }, logging: config.logging, }, @@ -290,8 +269,8 @@ pub fn ephemeral_exit_gateway_config( gateway.storage_paths.keys.public_identity_key_file = pub_id_path; Ok(EphemeralConfig { - nr_opts, - ipr_opts, + nr_opts: Some(nr_opts), + ipr_opts: Some(ipr_opts), auth_opts, wg_opts, gateway, diff --git a/nym-node/src/config/helpers.rs b/nym-node/src/config/helpers.rs index ce9c45751f..5f3c5b7453 100644 --- a/nym-node/src/config/helpers.rs +++ b/nym-node/src/config/helpers.rs @@ -3,9 +3,14 @@ use crate::config::Config; use clap::crate_version; +use nym_gateway::node::{ + LocalAuthenticatorOpts, LocalIpPacketRouterOpts, LocalNetworkRequesterOpts, +}; use std::net::IpAddr; use thiserror::Error; +use super::LocalWireguardOpts; + #[derive(Debug, Error)] #[error("currently it's not supported to have different ip addresses for clients and mixnet ({clients_bind_ip} and {mix_bind_ip} were used)")] pub struct UnsupportedGatewayAddresses { @@ -80,3 +85,22 @@ pub fn ephemeral_gateway_config( }, )) } + +pub fn base_client_config(config: &Config) -> nym_client_core_config_types::Client { + nym_client_core_config_types::Client { + version: format!("{}-nym-node", crate_version!()), + id: config.id.clone(), + // irrelevant field - no need for credentials in embedded mode + disabled_credentials_mode: true, + nyxd_urls: config.mixnet.nyxd_urls.clone(), + nym_api_urls: config.mixnet.nym_api_urls.clone(), + } +} + +pub struct EphemeralConfig { + pub gateway: nym_gateway::config::Config, + pub nr_opts: Option, + pub ipr_opts: Option, + pub auth_opts: LocalAuthenticatorOpts, + pub wg_opts: LocalWireguardOpts, +} diff --git a/nym-node/src/config/mod.rs b/nym-node/src/config/mod.rs index bfe6831590..5da49419cf 100644 --- a/nym-node/src/config/mod.rs +++ b/nym-node/src/config/mod.rs @@ -4,6 +4,7 @@ use crate::config::persistence::NymNodePaths; use crate::config::template::CONFIG_TEMPLATE; use crate::error::NymNodeError; +use authenticator::Authenticator; use celes::Country; use clap::ValueEnum; use nym_bin_common::logging::LoggingSettings; @@ -113,6 +114,8 @@ pub struct ConfigBuilder { pub exit_gateway: Option, + pub authenticator: Option, + pub logging: Option, } @@ -131,6 +134,7 @@ impl ConfigBuilder { mixnode: None, entry_gateway: None, exit_gateway: None, + authenticator: None, logging: None, } } @@ -207,6 +211,7 @@ impl ConfigBuilder { .unwrap_or_else(|| ExitGatewayConfig::new_default(&self.data_dir)), logging: self.logging.unwrap_or_default(), save_path: Some(self.config_path), + authenticator: self.authenticator.unwrap_or_default(), } } } @@ -243,6 +248,8 @@ pub struct Config { pub exit_gateway: ExitGatewayConfig, + pub authenticator: Authenticator, + #[serde(default)] pub logging: LoggingSettings, } diff --git a/nym-node/src/config/old_configs/mod.rs b/nym-node/src/config/old_configs/mod.rs index 3a3fc9ce9d..d85e583953 100644 --- a/nym-node/src/config/old_configs/mod.rs +++ b/nym-node/src/config/old_configs/mod.rs @@ -1,8 +1,8 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -mod old_config_1_1_2; -mod old_config_1_1_3; +mod old_config_v1; +mod old_config_v2; -pub use old_config_1_1_2::try_upgrade_config_1_1_2; -pub use old_config_1_1_3::try_upgrade_config_1_1_3; +pub use old_config_v1::try_upgrade_config_v1; +pub use old_config_v2::try_upgrade_config_v2; diff --git a/nym-node/src/config/old_configs/old_config_1_1_2.rs b/nym-node/src/config/old_configs/old_config_v1.rs similarity index 87% rename from nym-node/src/config/old_configs/old_config_1_1_2.rs rename to nym-node/src/config/old_configs/old_config_v1.rs index 419de25b2c..e3a76cdc56 100644 --- a/nym-node/src/config/old_configs/old_config_1_1_2.rs +++ b/nym-node/src/config/old_configs/old_config_v1.rs @@ -8,21 +8,21 @@ use nym_client_core_config_types::DebugConfig as ClientDebugConfig; use nym_config::serde_helpers::de_maybe_port; use nym_crypto::asymmetric::encryption::KeyPair; use nym_pemstore::store_keypair; -use old_configs::old_config_1_1_3::*; +use old_configs::old_config_v2::*; use rand::rngs::OsRng; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct WireguardPaths1_1_2 { +pub struct WireguardPathsV1 { pub private_diffie_hellman_key_file: PathBuf, pub public_diffie_hellman_key_file: PathBuf, } -impl WireguardPaths1_1_2 { +impl WireguardPathsV1 { pub fn new>(data_dir: P) -> Self { let data_dir = data_dir.as_ref(); - WireguardPaths1_1_2 { + WireguardPathsV1 { private_diffie_hellman_key_file: data_dir .join(persistence::DEFAULT_X25519_WG_DH_KEY_FILENAME), public_diffie_hellman_key_file: data_dir @@ -40,7 +40,7 @@ impl WireguardPaths1_1_2 { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] -pub struct Wireguard1_1_2 { +pub struct WireguardV1 { /// Specifies whether the wireguard service is enabled on this node. pub enabled: bool, @@ -61,13 +61,13 @@ pub struct Wireguard1_1_2 { pub private_network_prefix: u8, /// Paths for wireguard keys, client registries, etc. - pub storage_paths: WireguardPaths1_1_2, + pub storage_paths: WireguardPathsV1, } // a temporary solution until all "types" are run at the same time #[derive(Debug, Default, Serialize, Deserialize, ValueEnum, Clone, Copy)] #[serde(rename_all = "snake_case")] -pub enum NodeMode1_1_2 { +pub enum NodeModeV1 { #[default] #[clap(alias = "mix")] Mixnode, @@ -79,12 +79,12 @@ pub enum NodeMode1_1_2 { ExitGateway, } -impl From for NodeMode1_1_3 { - fn from(config: NodeMode1_1_2) -> Self { +impl From for NodeModeV2 { + fn from(config: NodeModeV1) -> Self { match config { - NodeMode1_1_2::Mixnode => NodeMode1_1_3::Mixnode, - NodeMode1_1_2::EntryGateway => NodeMode1_1_3::EntryGateway, - NodeMode1_1_2::ExitGateway => NodeMode1_1_3::ExitGateway, + NodeModeV1::Mixnode => NodeModeV2::Mixnode, + NodeModeV1::EntryGateway => NodeModeV2::EntryGateway, + NodeModeV1::ExitGateway => NodeModeV2::ExitGateway, } } } @@ -93,7 +93,7 @@ impl From for NodeMode1_1_3 { #[derive(Debug, Clone, Default, Deserialize, PartialEq, Serialize)] #[serde(default)] #[serde(deny_unknown_fields)] -pub struct Host1_1_2 { +pub struct HostV1 { /// Ip address(es) of this host, such as 1.1.1.1 that external clients will use for connections. /// If no values are provided, when this node gets included in the network, /// its ip addresses will be populated by whatever value is resolved by associated nym-api. @@ -112,7 +112,7 @@ pub struct Host1_1_2 { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(default)] #[serde(deny_unknown_fields)] -pub struct MixnetDebug1_1_2 { +pub struct MixnetDebugV1 { /// Initial value of an exponential backoff to reconnect to dropped TCP connection when /// forwarding sphinx packets. #[serde(with = "humantime_serde")] @@ -134,16 +134,16 @@ pub struct MixnetDebug1_1_2 { pub unsafe_disable_noise: bool, } -impl MixnetDebug1_1_2 { +impl MixnetDebugV1 { const DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF: Duration = Duration::from_millis(10_000); const DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF: Duration = Duration::from_millis(300_000); const DEFAULT_INITIAL_CONNECTION_TIMEOUT: Duration = Duration::from_millis(1_500); const DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE: usize = 2000; } -impl Default for MixnetDebug1_1_2 { +impl Default for MixnetDebugV1 { fn default() -> Self { - MixnetDebug1_1_2 { + MixnetDebugV1 { packet_forwarding_initial_backoff: Self::DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF, packet_forwarding_maximum_backoff: Self::DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF, initial_connection_timeout: Self::DEFAULT_INITIAL_CONNECTION_TIMEOUT, @@ -154,7 +154,7 @@ impl Default for MixnetDebug1_1_2 { } } -impl Default for Mixnet1_1_2 { +impl Default for MixnetV1 { fn default() -> Self { // SAFETY: // our hardcoded values should always be valid @@ -173,7 +173,7 @@ impl Default for Mixnet1_1_2 { vec![mainnet::NYXD_URL.parse().expect("Invalid default nyxd URL")] }; - Mixnet1_1_2 { + MixnetV1 { bind_address: SocketAddr::new(inaddr_any(), DEFAULT_MIXNET_PORT), nym_api_urls, nyxd_urls, @@ -185,7 +185,7 @@ impl Default for Mixnet1_1_2 { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(default)] #[serde(deny_unknown_fields)] -pub struct Mixnet1_1_2 { +pub struct MixnetV1 { /// Address this node will bind to for listening for mixnet packets /// default: `0.0.0.0:1789` pub bind_address: SocketAddr, @@ -197,12 +197,12 @@ pub struct Mixnet1_1_2 { pub nyxd_urls: Vec, #[serde(default)] - pub debug: MixnetDebug1_1_2, + pub debug: MixnetDebugV1, } #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct KeysPaths1_1_2 { +pub struct KeysPathsV1 { /// Path to file containing ed25519 identity private key. pub private_ed25519_identity_key_file: PathBuf, @@ -224,8 +224,8 @@ pub struct KeysPaths1_1_2 { #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct NymNodePaths1_1_2 { - pub keys: KeysPaths1_1_2, +pub struct NymNodePathsV1 { + pub keys: KeysPathsV1, /// Path to a file containing basic node description: human-readable name, website, details, etc. pub description: PathBuf, @@ -234,7 +234,7 @@ pub struct NymNodePaths1_1_2 { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(default)] #[serde(deny_unknown_fields)] -pub struct Http1_1_2 { +pub struct HttpV1 { /// Socket address this node will use for binding its http API. /// default: `0.0.0.0:8080` pub bind_address: SocketAddr, @@ -263,9 +263,9 @@ pub struct Http1_1_2 { pub expose_crypto_hardware: bool, } -impl Default for Http1_1_2 { +impl Default for HttpV1 { fn default() -> Self { - Http1_1_2 { + HttpV1 { bind_address: SocketAddr::new(inaddr_any(), DEFAULT_HTTP_PORT), landing_page_assets_path: None, access_token: None, @@ -278,11 +278,11 @@ impl Default for Http1_1_2 { #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct MixnodePaths1_1_2 {} +pub struct MixnodePathsV1 {} #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct Debug1_1_2 { +pub struct DebugV1 { /// Delay between each subsequent node statistics being logged to the console #[serde(with = "humantime_serde")] pub node_stats_logging_delay: Duration, @@ -294,7 +294,7 @@ pub struct Debug1_1_2 { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] -pub struct VerlocDebug1_1_2 { +pub struct VerlocDebugV1 { /// Specifies number of echo packets sent to each node during a measurement run. pub packets_per_node: usize, @@ -325,16 +325,16 @@ pub struct VerlocDebug1_1_2 { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] -pub struct Verloc1_1_2 { +pub struct VerlocV1 { /// Socket address this node will use for binding its verloc API. /// default: `0.0.0.0:1790` pub bind_address: SocketAddr, #[serde(default)] - pub debug: VerlocDebug1_1_2, + pub debug: VerlocDebugV1, } -impl VerlocDebug1_1_2 { +impl VerlocDebugV1 { const DEFAULT_PACKETS_PER_NODE: usize = 100; const DEFAULT_CONNECTION_TIMEOUT: Duration = Duration::from_millis(5000); const DEFAULT_PACKET_TIMEOUT: Duration = Duration::from_millis(1500); @@ -344,9 +344,9 @@ impl VerlocDebug1_1_2 { const DEFAULT_RETRY_TIMEOUT: Duration = Duration::from_secs(60 * 30); } -impl Default for VerlocDebug1_1_2 { +impl Default for VerlocDebugV1 { fn default() -> Self { - VerlocDebug1_1_2 { + VerlocDebugV1 { packets_per_node: Self::DEFAULT_PACKETS_PER_NODE, connection_timeout: Self::DEFAULT_CONNECTION_TIMEOUT, packet_timeout: Self::DEFAULT_PACKET_TIMEOUT, @@ -360,23 +360,23 @@ impl Default for VerlocDebug1_1_2 { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct MixnodeConfig1_1_2 { - pub storage_paths: MixnodePaths1_1_2, +pub struct MixnodeConfigV1 { + pub storage_paths: MixnodePathsV1, - pub verloc: Verloc1_1_2, + pub verloc: VerlocV1, #[serde(default)] - pub debug: Debug1_1_2, + pub debug: DebugV1, } -impl Debug1_1_2 { +impl DebugV1 { const DEFAULT_NODE_STATS_LOGGING_DELAY: Duration = Duration::from_millis(60_000); const DEFAULT_NODE_STATS_UPDATING_DELAY: Duration = Duration::from_millis(30_000); } -impl Default for Debug1_1_2 { +impl Default for DebugV1 { fn default() -> Self { - Debug1_1_2 { + DebugV1 { node_stats_logging_delay: Self::DEFAULT_NODE_STATS_LOGGING_DELAY, node_stats_updating_delay: Self::DEFAULT_NODE_STATS_UPDATING_DELAY, } @@ -385,7 +385,7 @@ impl Default for Debug1_1_2 { #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct EntryGatewayPaths1_1_2 { +pub struct EntryGatewayPathsV1 { /// Path to sqlite database containing all persistent data: messages for offline clients, /// derived shared keys and available client bandwidths. pub clients_storage: PathBuf, @@ -396,18 +396,18 @@ pub struct EntryGatewayPaths1_1_2 { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct EntryGatewayConfigDebug1_1_2 { +pub struct EntryGatewayConfigDebugV1 { /// Number of messages from offline client that can be pulled at once (i.e. with a single SQL query) from the storage. pub message_retrieval_limit: i64, } -impl EntryGatewayConfigDebug1_1_2 { +impl EntryGatewayConfigDebugV1 { const DEFAULT_MESSAGE_RETRIEVAL_LIMIT: i64 = 100; } -impl Default for EntryGatewayConfigDebug1_1_2 { +impl Default for EntryGatewayConfigDebugV1 { fn default() -> Self { - EntryGatewayConfigDebug1_1_2 { + EntryGatewayConfigDebugV1 { message_retrieval_limit: Self::DEFAULT_MESSAGE_RETRIEVAL_LIMIT, } } @@ -415,8 +415,8 @@ impl Default for EntryGatewayConfigDebug1_1_2 { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct EntryGatewayConfig1_1_2 { - pub storage_paths: EntryGatewayPaths1_1_2, +pub struct EntryGatewayConfigV1 { + pub storage_paths: EntryGatewayPathsV1, /// Indicates whether this gateway is accepting only coconut credentials for accessing the mixnet /// or if it also accepts non-paying clients @@ -438,12 +438,12 @@ pub struct EntryGatewayConfig1_1_2 { pub announce_wss_port: Option, #[serde(default)] - pub debug: EntryGatewayConfigDebug1_1_2, + pub debug: EntryGatewayConfigDebugV1, } #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct NetworkRequesterPaths1_1_2 { +pub struct NetworkRequesterPathsV1 { /// Path to file containing network requester ed25519 identity private key. pub private_ed25519_identity_key_file: PathBuf, @@ -473,7 +473,7 @@ pub struct NetworkRequesterPaths1_1_2 { #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct IpPacketRouterPaths1_1_2 { +pub struct IpPacketRouterPathsV1 { /// Path to file containing ip packet router ed25519 identity private key. pub private_ed25519_identity_key_file: PathBuf, @@ -503,15 +503,15 @@ pub struct IpPacketRouterPaths1_1_2 { #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct ExitGatewayPaths1_1_2 { - pub network_requester: NetworkRequesterPaths1_1_2, +pub struct ExitGatewayPathsV1 { + pub network_requester: NetworkRequesterPathsV1, - pub ip_packet_router: IpPacketRouterPaths1_1_2, + pub ip_packet_router: IpPacketRouterPathsV1, } #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] #[serde(default)] -pub struct IpPacketRouterDebug1_1_2 { +pub struct IpPacketRouterDebugV1 { /// Specifies whether ip packet routing service is enabled in this process. /// This is only here for debugging purposes as exit gateway should always run **both** /// network requester and an ip packet router. @@ -527,9 +527,9 @@ pub struct IpPacketRouterDebug1_1_2 { pub client_debug: ClientDebugConfig, } -impl Default for IpPacketRouterDebug1_1_2 { +impl Default for IpPacketRouterDebugV1 { fn default() -> Self { - IpPacketRouterDebug1_1_2 { + IpPacketRouterDebugV1 { enabled: true, disable_poisson_rate: true, client_debug: Default::default(), @@ -538,22 +538,22 @@ impl Default for IpPacketRouterDebug1_1_2 { } #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] -pub struct IpPacketRouter1_1_2 { +pub struct IpPacketRouterV1 { #[serde(default)] - pub debug: IpPacketRouterDebug1_1_2, + pub debug: IpPacketRouterDebugV1, } #[allow(clippy::derivable_impls)] -impl Default for IpPacketRouter1_1_2 { +impl Default for IpPacketRouterV1 { fn default() -> Self { - IpPacketRouter1_1_2 { + IpPacketRouterV1 { debug: Default::default(), } } } #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] -pub struct NetworkRequesterDebug1_1_2 { +pub struct NetworkRequesterDebugV1 { /// Specifies whether network requester service is enabled in this process. /// This is only here for debugging purposes as exit gateway should always run **both** /// network requester and an ip packet router. @@ -569,9 +569,9 @@ pub struct NetworkRequesterDebug1_1_2 { pub client_debug: ClientDebugConfig, } -impl Default for NetworkRequesterDebug1_1_2 { +impl Default for NetworkRequesterDebugV1 { fn default() -> Self { - NetworkRequesterDebug1_1_2 { + NetworkRequesterDebugV1 { enabled: true, disable_poisson_rate: true, client_debug: Default::default(), @@ -580,15 +580,15 @@ impl Default for NetworkRequesterDebug1_1_2 { } #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] -pub struct NetworkRequester1_1_2 { +pub struct NetworkRequesterV1 { #[serde(default)] - pub debug: NetworkRequesterDebug1_1_2, + pub debug: NetworkRequesterDebugV1, } #[allow(clippy::derivable_impls)] -impl Default for NetworkRequester1_1_2 { +impl Default for NetworkRequesterV1 { fn default() -> Self { - NetworkRequester1_1_2 { + NetworkRequesterV1 { debug: Default::default(), } } @@ -596,8 +596,8 @@ impl Default for NetworkRequester1_1_2 { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct ExitGatewayConfig1_1_2 { - pub storage_paths: ExitGatewayPaths1_1_2, +pub struct ExitGatewayConfigV1 { + pub storage_paths: ExitGatewayPathsV1, /// specifies whether this exit node should run in 'open-proxy' mode /// and thus would attempt to resolve **ANY** request it receives. @@ -606,20 +606,20 @@ pub struct ExitGatewayConfig1_1_2 { /// Specifies the url for an upstream source of the exit policy used by this node. pub upstream_exit_policy_url: Url, - pub network_requester: NetworkRequester1_1_2, + pub network_requester: NetworkRequesterV1, - pub ip_packet_router: IpPacketRouter1_1_2, + pub ip_packet_router: IpPacketRouterV1, } #[derive(Debug, Default, Copy, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct LoggingSettings1_1_2 { +pub struct LoggingSettingsV1 { // well, we need to implement something here at some point... } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct Config1_1_2 { +pub struct ConfigV1 { // additional metadata holding on-disk location of this config file #[serde(skip)] pub(crate) save_path: Option, @@ -629,37 +629,37 @@ pub struct Config1_1_2 { /// Current mode of this nym-node. /// Expect this field to be changed in the future to allow running the node in multiple modes (i.e. mixnode + gateway) - pub mode: NodeMode1_1_2, + pub mode: NodeModeV1, - pub host: Host1_1_2, + pub host: HostV1, - pub mixnet: Mixnet1_1_2, + pub mixnet: MixnetV1, /// Storage paths to persistent nym-node data, such as its long term keys. - pub storage_paths: NymNodePaths1_1_2, + pub storage_paths: NymNodePathsV1, #[serde(default)] - pub http: Http1_1_2, + pub http: HttpV1, - pub wireguard: Wireguard1_1_2, + pub wireguard: WireguardV1, - pub mixnode: MixnodeConfig1_1_2, + pub mixnode: MixnodeConfigV1, - pub entry_gateway: EntryGatewayConfig1_1_2, + pub entry_gateway: EntryGatewayConfigV1, - pub exit_gateway: ExitGatewayConfig1_1_2, + pub exit_gateway: ExitGatewayConfigV1, #[serde(default)] - pub logging: LoggingSettings1_1_2, + pub logging: LoggingSettingsV1, } -impl NymConfigTemplate for Config1_1_2 { +impl NymConfigTemplate for ConfigV1 { fn template(&self) -> &'static str { CONFIG_TEMPLATE } } -impl Config1_1_2 { +impl ConfigV1 { pub fn save(&self) -> Result<(), NymNodeError> { let save_location = self.save_location(); debug!( @@ -727,7 +727,7 @@ impl Config1_1_2 { // simple wrapper that reads config file and assigns path location fn read_from_path>(path: P) -> Result { let path = path.as_ref(); - let mut loaded: Config1_1_2 = + let mut loaded: ConfigV1 = read_config_from_toml_file(path).map_err(|source| NymNodeError::ConfigLoadFailure { path: path.to_path_buf(), source, @@ -742,7 +742,7 @@ impl Config1_1_2 { } } -fn initialise(config: &Wireguard1_1_3) -> std::io::Result<()> { +fn initialise(config: &WireguardV2) -> std::io::Result<()> { let mut rng = OsRng; let x25519_keys = KeyPair::new(&mut rng); @@ -754,36 +754,43 @@ fn initialise(config: &Wireguard1_1_3) -> std::io::Result<()> { Ok(()) } -// currently there are no upgrades -pub async fn try_upgrade_config_1_1_2>(path: P) -> Result<(), NymNodeError> { - let old_cfg = Config1_1_2::read_from_path(&path)?; - let wireguard = Wireguard1_1_3 { +pub async fn try_upgrade_config_v1>( + path: P, + prev_config: Option, +) -> Result { + tracing::debug!("Updating from 1.1.2"); + let old_cfg = if let Some(prev_config) = prev_config { + prev_config + } else { + ConfigV1::read_from_path(&path)? + }; + let wireguard = WireguardV2 { enabled: old_cfg.wireguard.enabled, bind_address: old_cfg.wireguard.bind_address, private_ip: old_cfg.wireguard.private_network_ip, announced_port: old_cfg.wireguard.announced_port, private_network_prefix: old_cfg.wireguard.private_network_prefix, - storage_paths: WireguardPaths1_1_3::new(Config1_1_3::default_data_directory(path)?), + storage_paths: WireguardPathsV2::new(ConfigV2::default_data_directory(path)?), }; initialise(&wireguard).map_err(|err| KeyIOFailure::KeyPairStoreFailure { keys: "wg-x25519-dh".to_string(), paths: wireguard.storage_paths.x25519_wireguard_storage_paths(), err, })?; - let cfg = Config1_1_3 { + let cfg = ConfigV2 { save_path: old_cfg.save_path, id: old_cfg.id, mode: old_cfg.mode.into(), - host: Host1_1_3 { + host: HostV2 { public_ips: old_cfg.host.public_ips, hostname: old_cfg.host.hostname, location: old_cfg.host.location, }, - mixnet: Mixnet1_1_3 { + mixnet: MixnetV2 { bind_address: old_cfg.mixnet.bind_address, nym_api_urls: old_cfg.mixnet.nym_api_urls, nyxd_urls: old_cfg.mixnet.nyxd_urls, - debug: MixnetDebug1_1_3 { + debug: MixnetDebugV2 { packet_forwarding_initial_backoff: old_cfg .mixnet .debug @@ -797,8 +804,8 @@ pub async fn try_upgrade_config_1_1_2>(path: P) -> Result<(), Nym unsafe_disable_noise: old_cfg.mixnet.debug.unsafe_disable_noise, }, }, - storage_paths: NymNodePaths1_1_3 { - keys: KeysPaths1_1_3 { + storage_paths: NymNodePathsV2 { + keys: KeysPathsV2 { private_ed25519_identity_key_file: old_cfg .storage_paths .keys @@ -826,7 +833,7 @@ pub async fn try_upgrade_config_1_1_2>(path: P) -> Result<(), Nym }, description: old_cfg.storage_paths.description, }, - http: Http1_1_3 { + http: HttpV2 { bind_address: old_cfg.http.bind_address, landing_page_assets_path: old_cfg.http.landing_page_assets_path, access_token: old_cfg.http.access_token, @@ -835,11 +842,11 @@ pub async fn try_upgrade_config_1_1_2>(path: P) -> Result<(), Nym expose_crypto_hardware: old_cfg.http.expose_crypto_hardware, }, wireguard, - mixnode: MixnodeConfig1_1_3 { - storage_paths: MixnodePaths1_1_3 {}, - verloc: Verloc1_1_3 { + mixnode: MixnodeConfigV2 { + storage_paths: MixnodePathsV2 {}, + verloc: VerlocV2 { bind_address: old_cfg.mixnode.verloc.bind_address, - debug: VerlocDebug1_1_3 { + debug: VerlocDebugV2 { packets_per_node: old_cfg.mixnode.verloc.debug.packets_per_node, connection_timeout: old_cfg.mixnode.verloc.debug.connection_timeout, packet_timeout: old_cfg.mixnode.verloc.debug.packet_timeout, @@ -849,13 +856,13 @@ pub async fn try_upgrade_config_1_1_2>(path: P) -> Result<(), Nym retry_timeout: old_cfg.mixnode.verloc.debug.retry_timeout, }, }, - debug: Debug1_1_3 { + debug: DebugV2 { node_stats_logging_delay: old_cfg.mixnode.debug.node_stats_logging_delay, node_stats_updating_delay: old_cfg.mixnode.debug.node_stats_updating_delay, }, }, - entry_gateway: EntryGatewayConfig1_1_3 { - storage_paths: EntryGatewayPaths1_1_3 { + entry_gateway: EntryGatewayConfigV2 { + storage_paths: EntryGatewayPathsV2 { clients_storage: old_cfg.entry_gateway.storage_paths.clients_storage, cosmos_mnemonic: old_cfg.entry_gateway.storage_paths.cosmos_mnemonic, }, @@ -863,13 +870,13 @@ pub async fn try_upgrade_config_1_1_2>(path: P) -> Result<(), Nym bind_address: old_cfg.entry_gateway.bind_address, announce_ws_port: old_cfg.entry_gateway.announce_ws_port, announce_wss_port: old_cfg.entry_gateway.announce_wss_port, - debug: EntryGatewayConfigDebug1_1_3 { + debug: EntryGatewayConfigDebugV2 { message_retrieval_limit: old_cfg.entry_gateway.debug.message_retrieval_limit, }, }, - exit_gateway: ExitGatewayConfig1_1_3 { - storage_paths: ExitGatewayPaths1_1_3 { - network_requester: NetworkRequesterPaths1_1_3 { + exit_gateway: ExitGatewayConfigV2 { + storage_paths: ExitGatewayPathsV2 { + network_requester: NetworkRequesterPathsV2 { private_ed25519_identity_key_file: old_cfg .exit_gateway .storage_paths @@ -906,7 +913,7 @@ pub async fn try_upgrade_config_1_1_2>(path: P) -> Result<(), Nym .network_requester .gateway_registrations, }, - ip_packet_router: IpPacketRouterPaths1_1_3 { + ip_packet_router: IpPacketRouterPathsV2 { private_ed25519_identity_key_file: old_cfg .exit_gateway .storage_paths @@ -946,8 +953,8 @@ pub async fn try_upgrade_config_1_1_2>(path: P) -> Result<(), Nym }, open_proxy: old_cfg.exit_gateway.open_proxy, upstream_exit_policy_url: old_cfg.exit_gateway.upstream_exit_policy_url, - network_requester: NetworkRequester1_1_3 { - debug: NetworkRequesterDebug1_1_3 { + network_requester: NetworkRequesterV2 { + debug: NetworkRequesterDebugV2 { enabled: old_cfg.exit_gateway.network_requester.debug.enabled, disable_poisson_rate: old_cfg .exit_gateway @@ -957,8 +964,8 @@ pub async fn try_upgrade_config_1_1_2>(path: P) -> Result<(), Nym client_debug: old_cfg.exit_gateway.network_requester.debug.client_debug, }, }, - ip_packet_router: IpPacketRouter1_1_3 { - debug: IpPacketRouterDebug1_1_3 { + ip_packet_router: IpPacketRouterV2 { + debug: IpPacketRouterDebugV2 { enabled: old_cfg.exit_gateway.ip_packet_router.debug.enabled, disable_poisson_rate: old_cfg .exit_gateway @@ -969,10 +976,8 @@ pub async fn try_upgrade_config_1_1_2>(path: P) -> Result<(), Nym }, }, }, - logging: LoggingSettings1_1_3 {}, + logging: LoggingSettingsV2 {}, }; - cfg.save()?; - - Ok(()) + Ok(cfg) } diff --git a/nym-node/src/config/old_configs/old_config_1_1_3.rs b/nym-node/src/config/old_configs/old_config_v2.rs similarity index 59% rename from nym-node/src/config/old_configs/old_config_1_1_3.rs rename to nym-node/src/config/old_configs/old_config_v2.rs index e38113a004..5516a8d326 100644 --- a/nym-node/src/config/old_configs/old_config_1_1_3.rs +++ b/nym-node/src/config/old_configs/old_config_v2.rs @@ -2,25 +2,38 @@ // SPDX-License-Identifier: GPL-3.0-only #![allow(dead_code)] -use crate::config::*; + +use crate::{config::*, error::KeyIOFailure}; +use entry_gateway::Debug as EntryGatewayConfigDebug; +use exit_gateway::{IpPacketRouter, IpPacketRouterDebug, NetworkRequester, NetworkRequesterDebug}; +use mixnode::{Verloc, VerlocDebug}; use nym_client_core_config_types::DebugConfig as ClientDebugConfig; use nym_config::serde_helpers::de_maybe_port; -use nym_crypto::asymmetric::encryption::KeyPair; -use nym_pemstore::store_keypair; +use nym_crypto::asymmetric::{ed25519, x25519}; +use nym_network_requester::{ + set_active_gateway, setup_fs_gateways_storage, store_gateway_details, CustomGatewayDetails, + GatewayDetails, +}; +use nym_pemstore::{load_key, store_key, store_keypair}; +use nym_sphinx_acknowledgements::AckKey; +use persistence::{ + AuthenticatorPaths, EntryGatewayPaths, ExitGatewayPaths, IpPacketRouterPaths, KeysPaths, + MixnodePaths, NetworkRequesterPaths, WireguardPaths, +}; use rand::rngs::OsRng; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct WireguardPaths1_1_3 { +pub struct WireguardPathsV2 { pub private_diffie_hellman_key_file: PathBuf, pub public_diffie_hellman_key_file: PathBuf, } -impl WireguardPaths1_1_3 { +impl WireguardPathsV2 { pub fn new>(data_dir: P) -> Self { let data_dir = data_dir.as_ref(); - WireguardPaths1_1_3 { + WireguardPathsV2 { private_diffie_hellman_key_file: data_dir .join(persistence::DEFAULT_X25519_WG_DH_KEY_FILENAME), public_diffie_hellman_key_file: data_dir @@ -38,7 +51,7 @@ impl WireguardPaths1_1_3 { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] -pub struct Wireguard1_1_3 { +pub struct WireguardV2 { /// Specifies whether the wireguard service is enabled on this node. pub enabled: bool, @@ -59,13 +72,13 @@ pub struct Wireguard1_1_3 { pub private_network_prefix: u8, /// Paths for wireguard keys, client registries, etc. - pub storage_paths: WireguardPaths1_1_3, + pub storage_paths: WireguardPathsV2, } // a temporary solution until all "types" are run at the same time #[derive(Debug, Default, Serialize, Deserialize, ValueEnum, Clone, Copy)] #[serde(rename_all = "snake_case")] -pub enum NodeMode1_1_3 { +pub enum NodeModeV2 { #[default] #[clap(alias = "mix")] Mixnode, @@ -77,11 +90,21 @@ pub enum NodeMode1_1_3 { ExitGateway, } +impl From for NodeMode { + fn from(config: NodeModeV2) -> Self { + match config { + NodeModeV2::Mixnode => NodeMode::Mixnode, + NodeModeV2::EntryGateway => NodeMode::EntryGateway, + NodeModeV2::ExitGateway => NodeMode::ExitGateway, + } + } +} + // TODO: this is very much a WIP. we need proper ssl certificate support here #[derive(Debug, Clone, Default, Deserialize, PartialEq, Serialize)] #[serde(default)] #[serde(deny_unknown_fields)] -pub struct Host1_1_3 { +pub struct HostV2 { /// Ip address(es) of this host, such as 1.1.1.1 that external clients will use for connections. /// If no values are provided, when this node gets included in the network, /// its ip addresses will be populated by whatever value is resolved by associated nym-api. @@ -100,7 +123,7 @@ pub struct Host1_1_3 { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(default)] #[serde(deny_unknown_fields)] -pub struct MixnetDebug1_1_3 { +pub struct MixnetDebugV2 { /// Initial value of an exponential backoff to reconnect to dropped TCP connection when /// forwarding sphinx packets. #[serde(with = "humantime_serde")] @@ -122,16 +145,16 @@ pub struct MixnetDebug1_1_3 { pub unsafe_disable_noise: bool, } -impl MixnetDebug1_1_3 { +impl MixnetDebugV2 { const DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF: Duration = Duration::from_millis(10_000); const DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF: Duration = Duration::from_millis(300_000); const DEFAULT_INITIAL_CONNECTION_TIMEOUT: Duration = Duration::from_millis(1_500); const DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE: usize = 2000; } -impl Default for MixnetDebug1_1_3 { +impl Default for MixnetDebugV2 { fn default() -> Self { - MixnetDebug1_1_3 { + MixnetDebugV2 { packet_forwarding_initial_backoff: Self::DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF, packet_forwarding_maximum_backoff: Self::DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF, initial_connection_timeout: Self::DEFAULT_INITIAL_CONNECTION_TIMEOUT, @@ -142,7 +165,7 @@ impl Default for MixnetDebug1_1_3 { } } -impl Default for Mixnet1_1_3 { +impl Default for MixnetV2 { fn default() -> Self { // SAFETY: // our hardcoded values should always be valid @@ -161,7 +184,7 @@ impl Default for Mixnet1_1_3 { vec![mainnet::NYXD_URL.parse().expect("Invalid default nyxd URL")] }; - Mixnet1_1_3 { + MixnetV2 { bind_address: SocketAddr::new(inaddr_any(), DEFAULT_MIXNET_PORT), nym_api_urls, nyxd_urls, @@ -173,7 +196,7 @@ impl Default for Mixnet1_1_3 { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(default)] #[serde(deny_unknown_fields)] -pub struct Mixnet1_1_3 { +pub struct MixnetV2 { /// Address this node will bind to for listening for mixnet packets /// default: `0.0.0.0:1789` pub bind_address: SocketAddr, @@ -185,12 +208,12 @@ pub struct Mixnet1_1_3 { pub nyxd_urls: Vec, #[serde(default)] - pub debug: MixnetDebug1_1_3, + pub debug: MixnetDebugV2, } #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct KeysPaths1_1_3 { +pub struct KeysPathsV2 { /// Path to file containing ed25519 identity private key. pub private_ed25519_identity_key_file: PathBuf, @@ -212,8 +235,8 @@ pub struct KeysPaths1_1_3 { #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct NymNodePaths1_1_3 { - pub keys: KeysPaths1_1_3, +pub struct NymNodePathsV2 { + pub keys: KeysPathsV2, /// Path to a file containing basic node description: human-readable name, website, details, etc. pub description: PathBuf, @@ -222,7 +245,7 @@ pub struct NymNodePaths1_1_3 { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(default)] #[serde(deny_unknown_fields)] -pub struct Http1_1_3 { +pub struct HttpV2 { /// Socket address this node will use for binding its http API. /// default: `0.0.0.0:8080` pub bind_address: SocketAddr, @@ -251,9 +274,9 @@ pub struct Http1_1_3 { pub expose_crypto_hardware: bool, } -impl Default for Http1_1_3 { +impl Default for HttpV2 { fn default() -> Self { - Http1_1_3 { + HttpV2 { bind_address: SocketAddr::new(inaddr_any(), DEFAULT_HTTP_PORT), landing_page_assets_path: None, access_token: None, @@ -266,11 +289,11 @@ impl Default for Http1_1_3 { #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct MixnodePaths1_1_3 {} +pub struct MixnodePathsV2 {} #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct Debug1_1_3 { +pub struct DebugV2 { /// Delay between each subsequent node statistics being logged to the console #[serde(with = "humantime_serde")] pub node_stats_logging_delay: Duration, @@ -282,7 +305,7 @@ pub struct Debug1_1_3 { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] -pub struct VerlocDebug1_1_3 { +pub struct VerlocDebugV2 { /// Specifies number of echo packets sent to each node during a measurement run. pub packets_per_node: usize, @@ -313,16 +336,16 @@ pub struct VerlocDebug1_1_3 { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] -pub struct Verloc1_1_3 { +pub struct VerlocV2 { /// Socket address this node will use for binding its verloc API. /// default: `0.0.0.0:1790` pub bind_address: SocketAddr, #[serde(default)] - pub debug: VerlocDebug1_1_3, + pub debug: VerlocDebugV2, } -impl VerlocDebug1_1_3 { +impl VerlocDebugV2 { const DEFAULT_PACKETS_PER_NODE: usize = 100; const DEFAULT_CONNECTION_TIMEOUT: Duration = Duration::from_millis(5000); const DEFAULT_PACKET_TIMEOUT: Duration = Duration::from_millis(1500); @@ -332,9 +355,9 @@ impl VerlocDebug1_1_3 { const DEFAULT_RETRY_TIMEOUT: Duration = Duration::from_secs(60 * 30); } -impl Default for VerlocDebug1_1_3 { +impl Default for VerlocDebugV2 { fn default() -> Self { - VerlocDebug1_1_3 { + VerlocDebugV2 { packets_per_node: Self::DEFAULT_PACKETS_PER_NODE, connection_timeout: Self::DEFAULT_CONNECTION_TIMEOUT, packet_timeout: Self::DEFAULT_PACKET_TIMEOUT, @@ -348,23 +371,23 @@ impl Default for VerlocDebug1_1_3 { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct MixnodeConfig1_1_3 { - pub storage_paths: MixnodePaths1_1_3, +pub struct MixnodeConfigV2 { + pub storage_paths: MixnodePathsV2, - pub verloc: Verloc1_1_3, + pub verloc: VerlocV2, #[serde(default)] - pub debug: Debug1_1_3, + pub debug: DebugV2, } -impl Debug1_1_3 { +impl DebugV2 { const DEFAULT_NODE_STATS_LOGGING_DELAY: Duration = Duration::from_millis(60_000); const DEFAULT_NODE_STATS_UPDATING_DELAY: Duration = Duration::from_millis(30_000); } -impl Default for Debug1_1_3 { +impl Default for DebugV2 { fn default() -> Self { - Debug1_1_3 { + DebugV2 { node_stats_logging_delay: Self::DEFAULT_NODE_STATS_LOGGING_DELAY, node_stats_updating_delay: Self::DEFAULT_NODE_STATS_UPDATING_DELAY, } @@ -373,7 +396,7 @@ impl Default for Debug1_1_3 { #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct EntryGatewayPaths1_1_3 { +pub struct EntryGatewayPathsV2 { /// Path to sqlite database containing all persistent data: messages for offline clients, /// derived shared keys and available client bandwidths. pub clients_storage: PathBuf, @@ -384,18 +407,18 @@ pub struct EntryGatewayPaths1_1_3 { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct EntryGatewayConfigDebug1_1_3 { +pub struct EntryGatewayConfigDebugV2 { /// Number of messages from offline client that can be pulled at once (i.e. with a single SQL query) from the storage. pub message_retrieval_limit: i64, } -impl EntryGatewayConfigDebug1_1_3 { +impl EntryGatewayConfigDebugV2 { const DEFAULT_MESSAGE_RETRIEVAL_LIMIT: i64 = 100; } -impl Default for EntryGatewayConfigDebug1_1_3 { +impl Default for EntryGatewayConfigDebugV2 { fn default() -> Self { - EntryGatewayConfigDebug1_1_3 { + EntryGatewayConfigDebugV2 { message_retrieval_limit: Self::DEFAULT_MESSAGE_RETRIEVAL_LIMIT, } } @@ -403,8 +426,8 @@ impl Default for EntryGatewayConfigDebug1_1_3 { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct EntryGatewayConfig1_1_3 { - pub storage_paths: EntryGatewayPaths1_1_3, +pub struct EntryGatewayConfigV2 { + pub storage_paths: EntryGatewayPathsV2, /// Indicates whether this gateway is accepting only coconut credentials for accessing the mixnet /// or if it also accepts non-paying clients @@ -426,12 +449,12 @@ pub struct EntryGatewayConfig1_1_3 { pub announce_wss_port: Option, #[serde(default)] - pub debug: EntryGatewayConfigDebug1_1_3, + pub debug: EntryGatewayConfigDebugV2, } #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct NetworkRequesterPaths1_1_3 { +pub struct NetworkRequesterPathsV2 { /// Path to file containing network requester ed25519 identity private key. pub private_ed25519_identity_key_file: PathBuf, @@ -461,7 +484,7 @@ pub struct NetworkRequesterPaths1_1_3 { #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct IpPacketRouterPaths1_1_3 { +pub struct IpPacketRouterPathsV2 { /// Path to file containing ip packet router ed25519 identity private key. pub private_ed25519_identity_key_file: PathBuf, @@ -491,15 +514,15 @@ pub struct IpPacketRouterPaths1_1_3 { #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct ExitGatewayPaths1_1_3 { - pub network_requester: NetworkRequesterPaths1_1_3, +pub struct ExitGatewayPathsV2 { + pub network_requester: NetworkRequesterPathsV2, - pub ip_packet_router: IpPacketRouterPaths1_1_3, + pub ip_packet_router: IpPacketRouterPathsV2, } #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] #[serde(default)] -pub struct IpPacketRouterDebug1_1_3 { +pub struct IpPacketRouterDebugV2 { /// Specifies whether ip packet routing service is enabled in this process. /// This is only here for debugging purposes as exit gateway should always run **both** /// network requester and an ip packet router. @@ -515,9 +538,9 @@ pub struct IpPacketRouterDebug1_1_3 { pub client_debug: ClientDebugConfig, } -impl Default for IpPacketRouterDebug1_1_3 { +impl Default for IpPacketRouterDebugV2 { fn default() -> Self { - IpPacketRouterDebug1_1_3 { + IpPacketRouterDebugV2 { enabled: true, disable_poisson_rate: true, client_debug: Default::default(), @@ -526,22 +549,22 @@ impl Default for IpPacketRouterDebug1_1_3 { } #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] -pub struct IpPacketRouter1_1_3 { +pub struct IpPacketRouterV2 { #[serde(default)] - pub debug: IpPacketRouterDebug1_1_3, + pub debug: IpPacketRouterDebugV2, } #[allow(clippy::derivable_impls)] -impl Default for IpPacketRouter1_1_3 { +impl Default for IpPacketRouterV2 { fn default() -> Self { - IpPacketRouter1_1_3 { + IpPacketRouterV2 { debug: Default::default(), } } } #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] -pub struct NetworkRequesterDebug1_1_3 { +pub struct NetworkRequesterDebugV2 { /// Specifies whether network requester service is enabled in this process. /// This is only here for debugging purposes as exit gateway should always run **both** /// network requester and an ip packet router. @@ -557,9 +580,9 @@ pub struct NetworkRequesterDebug1_1_3 { pub client_debug: ClientDebugConfig, } -impl Default for NetworkRequesterDebug1_1_3 { +impl Default for NetworkRequesterDebugV2 { fn default() -> Self { - NetworkRequesterDebug1_1_3 { + NetworkRequesterDebugV2 { enabled: true, disable_poisson_rate: true, client_debug: Default::default(), @@ -568,15 +591,15 @@ impl Default for NetworkRequesterDebug1_1_3 { } #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] -pub struct NetworkRequester1_1_3 { +pub struct NetworkRequesterV2 { #[serde(default)] - pub debug: NetworkRequesterDebug1_1_3, + pub debug: NetworkRequesterDebugV2, } #[allow(clippy::derivable_impls)] -impl Default for NetworkRequester1_1_3 { +impl Default for NetworkRequesterV2 { fn default() -> Self { - NetworkRequester1_1_3 { + NetworkRequesterV2 { debug: Default::default(), } } @@ -584,8 +607,8 @@ impl Default for NetworkRequester1_1_3 { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct ExitGatewayConfig1_1_3 { - pub storage_paths: ExitGatewayPaths1_1_3, +pub struct ExitGatewayConfigV2 { + pub storage_paths: ExitGatewayPathsV2, /// specifies whether this exit node should run in 'open-proxy' mode /// and thus would attempt to resolve **ANY** request it receives. @@ -594,20 +617,20 @@ pub struct ExitGatewayConfig1_1_3 { /// Specifies the url for an upstream source of the exit policy used by this node. pub upstream_exit_policy_url: Url, - pub network_requester: NetworkRequester1_1_3, + pub network_requester: NetworkRequesterV2, - pub ip_packet_router: IpPacketRouter1_1_3, + pub ip_packet_router: IpPacketRouterV2, } #[derive(Debug, Default, Copy, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] -pub struct LoggingSettings1_1_3 { +pub struct LoggingSettingsV2 { // well, we need to implement something here at some point... } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct Config1_1_3 { +pub struct ConfigV2 { // additional metadata holding on-disk location of this config file #[serde(skip)] pub(crate) save_path: Option, @@ -617,37 +640,37 @@ pub struct Config1_1_3 { /// Current mode of this nym-node. /// Expect this field to be changed in the future to allow running the node in multiple modes (i.e. mixnode + gateway) - pub mode: NodeMode1_1_3, + pub mode: NodeModeV2, - pub host: Host1_1_3, + pub host: HostV2, - pub mixnet: Mixnet1_1_3, + pub mixnet: MixnetV2, /// Storage paths to persistent nym-node data, such as its long term keys. - pub storage_paths: NymNodePaths1_1_3, + pub storage_paths: NymNodePathsV2, #[serde(default)] - pub http: Http1_1_3, + pub http: HttpV2, - pub wireguard: Wireguard1_1_3, + pub wireguard: WireguardV2, - pub mixnode: MixnodeConfig1_1_3, + pub mixnode: MixnodeConfigV2, - pub entry_gateway: EntryGatewayConfig1_1_3, + pub entry_gateway: EntryGatewayConfigV2, - pub exit_gateway: ExitGatewayConfig1_1_3, + pub exit_gateway: ExitGatewayConfigV2, #[serde(default)] - pub logging: LoggingSettings1_1_3, + pub logging: LoggingSettingsV2, } -impl NymConfigTemplate for Config1_1_3 { +impl NymConfigTemplate for ConfigV2 { fn template(&self) -> &'static str { CONFIG_TEMPLATE } } -impl Config1_1_3 { +impl ConfigV2 { pub fn save(&self) -> Result<(), NymNodeError> { let save_location = self.save_location(); debug!( @@ -715,7 +738,7 @@ impl Config1_1_3 { // simple wrapper that reads config file and assigns path location fn read_from_path>(path: P) -> Result { let path = path.as_ref(); - let mut loaded: Config1_1_3 = + let mut loaded: ConfigV2 = read_config_from_toml_file(path).map_err(|source| NymNodeError::ConfigLoadFailure { path: path.to_path_buf(), source, @@ -730,37 +753,303 @@ impl Config1_1_3 { } } -fn initialise(config: &Wireguard1_1_3) -> std::io::Result<()> { +pub async fn initialise( + paths: &AuthenticatorPaths, + public_key: nym_crypto::asymmetric::identity::PublicKey, +) -> Result<(), NymNodeError> { let mut rng = OsRng; - let x25519_keys = KeyPair::new(&mut rng); - - store_keypair( - &x25519_keys, - &config.storage_paths.x25519_wireguard_storage_paths(), - )?; + let ed25519_keys = ed25519::KeyPair::new(&mut rng); + let x25519_keys = x25519::KeyPair::new(&mut rng); + let aes128ctr_key = AckKey::new(&mut rng); + let gateway_details = GatewayDetails::Custom(CustomGatewayDetails::new(public_key)).into(); + + store_keypair(&ed25519_keys, &paths.ed25519_identity_storage_paths()).map_err(|e| { + KeyIOFailure::KeyPairStoreFailure { + keys: "ed25519-identity".to_string(), + paths: paths.ed25519_identity_storage_paths(), + err: e, + } + })?; + store_keypair(&x25519_keys, &paths.x25519_diffie_hellman_storage_paths()).map_err(|e| { + KeyIOFailure::KeyPairStoreFailure { + keys: "x25519-dh".to_string(), + paths: paths.x25519_diffie_hellman_storage_paths(), + err: e, + } + })?; + store_key(&aes128ctr_key, &paths.ack_key_file).map_err(|e| KeyIOFailure::KeyStoreFailure { + key: "ack".to_string(), + path: paths.ack_key_file.clone(), + err: e, + })?; + + // insert all required information into the gateways store + // (I hate that we have to do it, but that's currently the simplest thing to do) + let storage = setup_fs_gateways_storage(&paths.gateway_registrations).await?; + store_gateway_details(&storage, &gateway_details).await?; + set_active_gateway(&storage, &gateway_details.gateway_id().to_base58_string()).await?; Ok(()) } -// currently there are no upgrades -pub async fn try_upgrade_config_1_1_3>(path: P) -> Result<(), NymNodeError> { - let old_cfg = Config::read_from_path(&path)?; +pub async fn try_upgrade_config_v2>( + path: P, + prev_config: Option, +) -> Result { + tracing::debug!("Updating from 1.1.3"); + let old_cfg = if let Some(prev_config) = prev_config { + prev_config + } else { + ConfigV2::read_from_path(&path)? + }; + + let authenticator_paths = AuthenticatorPaths::new( + old_cfg + .exit_gateway + .storage_paths + .ip_packet_router + .private_ed25519_identity_key_file + .parent() + .ok_or(NymNodeError::DataDirDerivationFailure)?, + ); + let cfg = Config { save_path: old_cfg.save_path, id: old_cfg.id, - mode: old_cfg.mode, - host: old_cfg.host, - mixnet: old_cfg.mixnet, - storage_paths: old_cfg.storage_paths, - http: old_cfg.http, - wireguard: old_cfg.wireguard, - mixnode: old_cfg.mixnode, - entry_gateway: old_cfg.entry_gateway, - exit_gateway: old_cfg.exit_gateway, - logging: old_cfg.logging, + mode: old_cfg.mode.into(), + host: Host { + public_ips: old_cfg.host.public_ips, + hostname: old_cfg.host.hostname, + location: old_cfg.host.location, + }, + mixnet: Mixnet { + bind_address: old_cfg.mixnet.bind_address, + nym_api_urls: old_cfg.mixnet.nym_api_urls, + nyxd_urls: old_cfg.mixnet.nyxd_urls, + debug: MixnetDebug { + packet_forwarding_initial_backoff: old_cfg + .mixnet + .debug + .packet_forwarding_initial_backoff, + packet_forwarding_maximum_backoff: old_cfg + .mixnet + .debug + .packet_forwarding_maximum_backoff, + initial_connection_timeout: old_cfg.mixnet.debug.initial_connection_timeout, + maximum_connection_buffer_size: old_cfg.mixnet.debug.maximum_connection_buffer_size, + unsafe_disable_noise: old_cfg.mixnet.debug.unsafe_disable_noise, + }, + }, + storage_paths: NymNodePaths { + keys: KeysPaths { + private_ed25519_identity_key_file: old_cfg + .storage_paths + .keys + .private_ed25519_identity_key_file, + public_ed25519_identity_key_file: old_cfg + .storage_paths + .keys + .public_ed25519_identity_key_file, + private_x25519_sphinx_key_file: old_cfg + .storage_paths + .keys + .private_x25519_sphinx_key_file, + public_x25519_sphinx_key_file: old_cfg + .storage_paths + .keys + .public_x25519_sphinx_key_file, + private_x25519_noise_key_file: old_cfg + .storage_paths + .keys + .private_x25519_noise_key_file, + public_x25519_noise_key_file: old_cfg + .storage_paths + .keys + .public_x25519_noise_key_file, + }, + description: old_cfg.storage_paths.description, + }, + http: Http { + bind_address: old_cfg.http.bind_address, + landing_page_assets_path: old_cfg.http.landing_page_assets_path, + access_token: old_cfg.http.access_token, + expose_system_info: old_cfg.http.expose_system_info, + expose_system_hardware: old_cfg.http.expose_system_hardware, + expose_crypto_hardware: old_cfg.http.expose_crypto_hardware, + }, + wireguard: Wireguard { + enabled: old_cfg.wireguard.enabled, + bind_address: old_cfg.wireguard.bind_address, + private_ip: old_cfg.wireguard.private_ip, + announced_port: old_cfg.wireguard.announced_port, + private_network_prefix: old_cfg.wireguard.private_network_prefix, + storage_paths: WireguardPaths { + private_diffie_hellman_key_file: old_cfg + .wireguard + .storage_paths + .private_diffie_hellman_key_file, + public_diffie_hellman_key_file: old_cfg + .wireguard + .storage_paths + .public_diffie_hellman_key_file, + }, + }, + mixnode: MixnodeConfig { + storage_paths: MixnodePaths {}, + verloc: Verloc { + bind_address: old_cfg.mixnode.verloc.bind_address, + debug: VerlocDebug { + packets_per_node: old_cfg.mixnode.verloc.debug.packets_per_node, + connection_timeout: old_cfg.mixnode.verloc.debug.connection_timeout, + packet_timeout: old_cfg.mixnode.verloc.debug.packet_timeout, + delay_between_packets: old_cfg.mixnode.verloc.debug.delay_between_packets, + tested_nodes_batch_size: old_cfg.mixnode.verloc.debug.tested_nodes_batch_size, + testing_interval: old_cfg.mixnode.verloc.debug.testing_interval, + retry_timeout: old_cfg.mixnode.verloc.debug.retry_timeout, + }, + }, + debug: mixnode::Debug { + node_stats_logging_delay: old_cfg.mixnode.debug.node_stats_logging_delay, + node_stats_updating_delay: old_cfg.mixnode.debug.node_stats_updating_delay, + }, + }, + entry_gateway: EntryGatewayConfig { + storage_paths: EntryGatewayPaths { + clients_storage: old_cfg.entry_gateway.storage_paths.clients_storage, + cosmos_mnemonic: old_cfg.entry_gateway.storage_paths.cosmos_mnemonic, + authenticator: authenticator_paths.clone(), + }, + enforce_zk_nyms: old_cfg.entry_gateway.enforce_zk_nyms, + bind_address: old_cfg.entry_gateway.bind_address, + announce_ws_port: old_cfg.entry_gateway.announce_ws_port, + announce_wss_port: old_cfg.entry_gateway.announce_wss_port, + debug: EntryGatewayConfigDebug { + message_retrieval_limit: old_cfg.entry_gateway.debug.message_retrieval_limit, + }, + }, + exit_gateway: ExitGatewayConfig { + storage_paths: ExitGatewayPaths { + network_requester: NetworkRequesterPaths { + private_ed25519_identity_key_file: old_cfg + .exit_gateway + .storage_paths + .network_requester + .private_ed25519_identity_key_file, + public_ed25519_identity_key_file: old_cfg + .exit_gateway + .storage_paths + .network_requester + .public_ed25519_identity_key_file, + private_x25519_diffie_hellman_key_file: old_cfg + .exit_gateway + .storage_paths + .network_requester + .private_x25519_diffie_hellman_key_file, + public_x25519_diffie_hellman_key_file: old_cfg + .exit_gateway + .storage_paths + .network_requester + .public_x25519_diffie_hellman_key_file, + ack_key_file: old_cfg + .exit_gateway + .storage_paths + .network_requester + .ack_key_file, + reply_surb_database: old_cfg + .exit_gateway + .storage_paths + .network_requester + .reply_surb_database, + gateway_registrations: old_cfg + .exit_gateway + .storage_paths + .network_requester + .gateway_registrations, + }, + ip_packet_router: IpPacketRouterPaths { + private_ed25519_identity_key_file: old_cfg + .exit_gateway + .storage_paths + .ip_packet_router + .private_ed25519_identity_key_file, + public_ed25519_identity_key_file: old_cfg + .exit_gateway + .storage_paths + .ip_packet_router + .public_ed25519_identity_key_file, + private_x25519_diffie_hellman_key_file: old_cfg + .exit_gateway + .storage_paths + .ip_packet_router + .private_x25519_diffie_hellman_key_file, + public_x25519_diffie_hellman_key_file: old_cfg + .exit_gateway + .storage_paths + .ip_packet_router + .public_x25519_diffie_hellman_key_file, + ack_key_file: old_cfg + .exit_gateway + .storage_paths + .ip_packet_router + .ack_key_file, + reply_surb_database: old_cfg + .exit_gateway + .storage_paths + .ip_packet_router + .reply_surb_database, + gateway_registrations: old_cfg + .exit_gateway + .storage_paths + .ip_packet_router + .gateway_registrations, + }, + authenticator: authenticator_paths.clone(), + }, + open_proxy: old_cfg.exit_gateway.open_proxy, + upstream_exit_policy_url: old_cfg.exit_gateway.upstream_exit_policy_url, + network_requester: NetworkRequester { + debug: NetworkRequesterDebug { + enabled: old_cfg.exit_gateway.network_requester.debug.enabled, + disable_poisson_rate: old_cfg + .exit_gateway + .network_requester + .debug + .disable_poisson_rate, + client_debug: old_cfg.exit_gateway.network_requester.debug.client_debug, + }, + }, + ip_packet_router: IpPacketRouter { + debug: IpPacketRouterDebug { + enabled: old_cfg.exit_gateway.ip_packet_router.debug.enabled, + disable_poisson_rate: old_cfg + .exit_gateway + .ip_packet_router + .debug + .disable_poisson_rate, + client_debug: old_cfg.exit_gateway.ip_packet_router.debug.client_debug, + }, + }, + }, + authenticator: Default::default(), + logging: LoggingSettings {}, }; - cfg.save()?; - - Ok(()) + let public_key = load_key( + cfg.storage_paths + .keys + .ed25519_identity_storage_paths() + .public_key_path, + ) + .map_err(|source| NymNodeError::DescriptionLoadFailure { + path: cfg + .storage_paths + .keys + .ed25519_identity_storage_paths() + .public_key_path, + source, + })?; + + initialise(&authenticator_paths, public_key).await?; + + Ok(cfg) } diff --git a/nym-node/src/config/persistence.rs b/nym-node/src/config/persistence.rs index 2c6dcfe8fa..3861f0e7ac 100644 --- a/nym-node/src/config/persistence.rs +++ b/nym-node/src/config/persistence.rs @@ -149,6 +149,8 @@ pub struct EntryGatewayPaths { /// Path to file containing cosmos account mnemonic used for zk-nym redemption. pub cosmos_mnemonic: PathBuf, + + pub authenticator: AuthenticatorPaths, } impl EntryGatewayPaths { @@ -156,6 +158,7 @@ impl EntryGatewayPaths { EntryGatewayPaths { clients_storage: data_dir.as_ref().join(DEFAULT_CLIENTS_STORAGE_FILENAME), cosmos_mnemonic: data_dir.as_ref().join(DEFAULT_MNEMONIC_FILENAME), + authenticator: AuthenticatorPaths::new(data_dir), } } diff --git a/nym-node/src/config/template.rs b/nym-node/src/config/template.rs index ea6003d5e3..0c2cf47f51 100644 --- a/nym-node/src/config/template.rs +++ b/nym-node/src/config/template.rs @@ -167,6 +167,7 @@ announce_ws_port = {{#if entry_gateway.announce_ws_port }} {{ entry_gateway.anno # (default: 0 - disabled) announce_wss_port = {{#if entry_gateway.announce_wss_port }} {{ entry_gateway.announce_wss_port }} {{else}} 0 {{/if}} + [entry_gateway.storage_paths] # Path to sqlite database containing all persistent data: messages for offline clients, # derived shared keys and available client bandwidths. @@ -175,6 +176,32 @@ clients_storage = '{{ entry_gateway.storage_paths.clients_storage }}' # Path to file containing cosmos account mnemonic used for zk-nym redemption. cosmos_mnemonic = '{{ entry_gateway.storage_paths.cosmos_mnemonic }}' +[entry_gateway.storage_paths.authenticator] +# Path to file containing authenticator ed25519 identity private key. +private_ed25519_identity_key_file = '{{ entry_gateway.storage_paths.authenticator.private_ed25519_identity_key_file }}' + +# Path to file containing authenticator ed25519 identity public key. +public_ed25519_identity_key_file = '{{ entry_gateway.storage_paths.authenticator.public_ed25519_identity_key_file }}' + +# Path to file containing authenticator x25519 diffie hellman private key. +private_x25519_diffie_hellman_key_file = '{{ entry_gateway.storage_paths.authenticator.private_x25519_diffie_hellman_key_file }}' + +# Path to file containing authenticator x25519 diffie hellman public key. +public_x25519_diffie_hellman_key_file = '{{ entry_gateway.storage_paths.authenticator.public_x25519_diffie_hellman_key_file }}' + +# Path to file containing key used for encrypting and decrypting the content of an +# acknowledgement so that nobody besides the client knows which packet it refers to. +ack_key_file = '{{ entry_gateway.storage_paths.authenticator.ack_key_file }}' + +# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags. +reply_surb_database = '{{ entry_gateway.storage_paths.authenticator.reply_surb_database }}' + +# Normally this is a path to the file containing information about gateways used by this client, +# i.e. details such as their public keys, owner addresses or the network information. +# but in this case it just has the basic information of "we're using custom gateway". +# Due to how clients are started up, this file has to exist. +gateway_registrations = '{{ entry_gateway.storage_paths.authenticator.gateway_registrations }}' + ##### exit-gateway mode nym-node config options ##### [exit_gateway] @@ -246,6 +273,36 @@ reply_surb_database = '{{ exit_gateway.storage_paths.ip_packet_router.reply_surb # Due to how clients are started up, this file has to exist. gateway_registrations = '{{ exit_gateway.storage_paths.ip_packet_router.gateway_registrations }}' +[exit_gateway.storage_paths.authenticator] +# Path to file containing authenticator ed25519 identity private key. +private_ed25519_identity_key_file = '{{ exit_gateway.storage_paths.authenticator.private_ed25519_identity_key_file }}' + +# Path to file containing authenticator ed25519 identity public key. +public_ed25519_identity_key_file = '{{ exit_gateway.storage_paths.authenticator.public_ed25519_identity_key_file }}' + +# Path to file containing authenticator x25519 diffie hellman private key. +private_x25519_diffie_hellman_key_file = '{{ exit_gateway.storage_paths.authenticator.private_x25519_diffie_hellman_key_file }}' + +# Path to file containing authenticator x25519 diffie hellman public key. +public_x25519_diffie_hellman_key_file = '{{ exit_gateway.storage_paths.authenticator.public_x25519_diffie_hellman_key_file }}' + +# Path to file containing key used for encrypting and decrypting the content of an +# acknowledgement so that nobody besides the client knows which packet it refers to. +ack_key_file = '{{ exit_gateway.storage_paths.authenticator.ack_key_file }}' + +# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags. +reply_surb_database = '{{ exit_gateway.storage_paths.authenticator.reply_surb_database }}' + +# Normally this is a path to the file containing information about gateways used by this client, +# i.e. details such as their public keys, owner addresses or the network information. +# but in this case it just has the basic information of "we're using custom gateway". +# Due to how clients are started up, this file has to exist. +gateway_registrations = '{{ exit_gateway.storage_paths.authenticator.gateway_registrations }}' + + +[authenticator] +# currently empty (there are some debug options one might want to configure) + ##### logging configuration options ##### [logging] diff --git a/nym-node/src/config/upgrade_helpers.rs b/nym-node/src/config/upgrade_helpers.rs index c49340542e..1eb5115414 100644 --- a/nym-node/src/config/upgrade_helpers.rs +++ b/nym-node/src/config/upgrade_helpers.rs @@ -1,8 +1,6 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use tracing::debug; - use crate::config::old_configs::*; use crate::config::Config; use crate::error::NymNodeError; @@ -10,14 +8,14 @@ use std::path::Path; // currently there are no upgrades async fn try_upgrade_config(path: &Path) -> Result<(), NymNodeError> { - if try_upgrade_config_1_1_2(path).await.is_ok() { - debug!("Updated from 1.1.2 or previous"); - } - if try_upgrade_config_1_1_3(path).await.is_ok() { - debug!("Updated from 1.1.3"); + let cfg = try_upgrade_config_v1(path, None).await.ok(); + match try_upgrade_config_v2(path, cfg).await { + Ok(cfg) => cfg.save(), + Err(e) => { + tracing::error!("Failed to finish upgrade - {e}"); + Err(NymNodeError::FailedUpgrade) + } } - - Ok(()) } pub async fn try_load_current_config>( diff --git a/nym-node/src/error.rs b/nym-node/src/error.rs index c7b42294c1..06f1b6c3fa 100644 --- a/nym-node/src/error.rs +++ b/nym-node/src/error.rs @@ -143,6 +143,13 @@ pub enum NymNodeError { #[error(transparent)] ExitGatewayFailure(#[from] ExitGatewayError), + + // TODO: more granular errors + #[error(transparent)] + ExternalClientCore(#[from] ClientCoreError), + + #[error("failed upgrade")] + FailedUpgrade, } impl From for NymNodeError { @@ -172,6 +179,13 @@ pub enum MixnodeError { #[derive(Debug, Error)] pub enum EntryGatewayError { + #[error(transparent)] + KeyFailure(#[from] KeyIOFailure), + + // TODO: more granular errors + #[error(transparent)] + ExternalClientCore(#[from] ClientCoreError), + #[error("failed to load entry gateway account mnemonic from {}: {source}", path.display())] MnemonicLoadFailure { path: PathBuf, diff --git a/nym-node/src/node/mod.rs b/nym-node/src/node/mod.rs index d026a7bd1b..4bfbbe2feb 100644 --- a/nym-node/src/node/mod.rs +++ b/nym-node/src/node/mod.rs @@ -19,6 +19,7 @@ use nym_network_requester::{ use nym_node::config::entry_gateway::ephemeral_entry_gateway_config; use nym_node::config::exit_gateway::ephemeral_exit_gateway_config; use nym_node::config::mixnode::ephemeral_mixnode_config; +use nym_node::config::persistence::AuthenticatorPaths; use nym_node::config::{ Config, EntryGatewayConfig, ExitGatewayConfig, MixnodeConfig, NodeMode, Wireguard, }; @@ -202,7 +203,7 @@ impl ExitGatewayData { config: &ExitGatewayConfig, public_key: ed25519::PublicKey, ) -> Result<(), ExitGatewayError> { - // generate all the keys for NR and IPR + // generate all the keys for NR, IPR and AUTH let mut rng = OsRng; let gateway_details = GatewayDetails::Custom(CustomGatewayDetails::new(public_key)).into(); @@ -328,6 +329,57 @@ pub(crate) struct NymNode { } impl NymNode { + fn initialise_client_keys( + rng: &mut R, + typ: &str, + ed25519_paths: nym_pemstore::KeyPairPath, + x25519_paths: nym_pemstore::KeyPairPath, + ack_key_path: &Path, + ) -> Result<(), EntryGatewayError> { + let ed25519_keys = ed25519::KeyPair::new(rng); + let x25519_keys = x25519::KeyPair::new(rng); + let aes128ctr_key = AckKey::new(rng); + + store_keypair( + &ed25519_keys, + ed25519_paths, + format!("{typ}-ed25519-identity"), + )?; + store_keypair(&x25519_keys, x25519_paths, format!("{typ}-x25519-dh"))?; + store_key(&aes128ctr_key, ack_key_path, format!("{typ}-ack-key"))?; + + Ok(()) + } + + async fn initialise_client_gateway_storage( + storage_path: &Path, + registration: &GatewayRegistration, + ) -> Result<(), EntryGatewayError> { + // insert all required information into the gateways store + // (I hate that we have to do it, but that's currently the simplest thing to do) + let storage = setup_fs_gateways_storage(storage_path).await?; + store_gateway_details(&storage, registration).await?; + set_active_gateway(&storage, ®istration.gateway_id().to_base58_string()).await?; + Ok(()) + } + + pub async fn initialise_authenticator( + rng: &mut R, + paths: &AuthenticatorPaths, + registration: &GatewayRegistration, + ) -> Result<(), NymNodeError> { + trace!("initialising authenticator keys"); + Self::initialise_client_keys( + rng, + "authenticator", + paths.ed25519_identity_storage_paths(), + paths.x25519_diffie_hellman_storage_paths(), + &paths.ack_key_file, + )?; + Self::initialise_client_gateway_storage(&paths.gateway_registrations, registration).await?; + Ok(()) + } + pub(crate) async fn initialise( config: &Config, custom_mnemonic: Option>, @@ -374,6 +426,17 @@ impl NymNode { ExitGatewayData::initialise(&config.exit_gateway, *ed25519_identity_keys.public_key()) .await?; + // authenticator initialization: + Self::initialise_authenticator( + &mut rng, + &config.entry_gateway.storage_paths.authenticator, + &GatewayDetails::Custom(CustomGatewayDetails::new( + *ed25519_identity_keys.public_key(), + )) + .into(), + ) + .await?; + // wireguard initialisation WireguardData::initialise(&config.wireguard)?; @@ -497,10 +560,10 @@ impl NymNode { let config = ephemeral_entry_gateway_config(self.config.clone(), &self.entry_gateway.mnemonic)?; let mut entry_gateway = Gateway::new_loaded( - config, - None, - None, - None, + config.gateway, + config.nr_opts, + config.ipr_opts, + Some(config.auth_opts), self.ed25519_identity_keys.clone(), self.x25519_sphinx_keys.clone(), self.entry_gateway.client_storage.clone(), @@ -526,8 +589,8 @@ impl NymNode { let mut exit_gateway = Gateway::new_loaded( config.gateway, - Some(config.nr_opts), - Some(config.ipr_opts), + config.nr_opts, + config.ipr_opts, Some(config.auth_opts), self.ed25519_identity_keys.clone(), self.x25519_sphinx_keys.clone(), diff --git a/service-providers/authenticator/src/authenticator.rs b/service-providers/authenticator/src/authenticator.rs index 473cae92f3..e8faf1b371 100644 --- a/service-providers/authenticator/src/authenticator.rs +++ b/service-providers/authenticator/src/authenticator.rs @@ -6,7 +6,7 @@ use std::path::Path; use futures::channel::oneshot; use ipnetwork::IpNetwork; use nym_client_core::{HardcodedTopologyProvider, TopologyProvider}; -use nym_sdk::mixnet::Recipient; +use nym_sdk::{mixnet::Recipient, GatewayTransceiver}; use nym_task::{TaskClient, TaskHandle}; use nym_wireguard::WireguardGatewayData; @@ -28,6 +28,7 @@ pub struct Authenticator { config: Config, wait_for_gateway: bool, custom_topology_provider: Option>, + custom_gateway_transceiver: Option>, wireguard_gateway_data: WireguardGatewayData, shutdown: Option, on_start: Option>, @@ -39,6 +40,7 @@ impl Authenticator { config, wait_for_gateway: false, custom_topology_provider: None, + custom_gateway_transceiver: None, wireguard_gateway_data, shutdown: None, on_start: None, @@ -59,6 +61,12 @@ impl Authenticator { self } + #[must_use] + pub fn with_minimum_gateway_performance(mut self, minimum_gateway_performance: u8) -> Self { + self.config.base.debug.topology.minimum_gateway_performance = minimum_gateway_performance; + self + } + #[must_use] #[allow(unused)] pub fn with_on_start(mut self, on_start: oneshot::Sender) -> Self { @@ -66,6 +74,16 @@ impl Authenticator { self } + #[must_use] + #[allow(unused)] + pub fn with_custom_gateway_transceiver( + mut self, + gateway_transceiver: Box, + ) -> Self { + self.custom_gateway_transceiver = Some(gateway_transceiver); + self + } + #[must_use] #[allow(unused)] pub fn with_custom_topology_provider( @@ -94,7 +112,7 @@ impl Authenticator { let mixnet_client = crate::mixnet_client::create_mixnet_client( &self.config.base, task_handle.get_handle().named("nym_sdk::MixnetClient"), - None, + self.custom_gateway_transceiver, self.custom_topology_provider, self.wait_for_gateway, &self.config.storage_paths.common_paths, diff --git a/service-providers/authenticator/src/config/persistence.rs b/service-providers/authenticator/src/config/persistence.rs index af11293a36..147919c825 100644 --- a/service-providers/authenticator/src/config/persistence.rs +++ b/service-providers/authenticator/src/config/persistence.rs @@ -3,17 +3,12 @@ use nym_client_core::config::disk_persistence::CommonClientPaths; use serde::{Deserialize, Serialize}; -use std::path::{Path, PathBuf}; - -pub const DEFAULT_DESCRIPTION_FILENAME: &str = "description.toml"; +use std::path::Path; #[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)] pub struct AuthenticatorPaths { #[serde(flatten)] pub common_paths: CommonClientPaths, - - /// Location of the file containing our description - pub authenticator_description: PathBuf, } impl AuthenticatorPaths { @@ -22,7 +17,6 @@ impl AuthenticatorPaths { Self { common_paths: CommonClientPaths::new_base(base_dir), - authenticator_description: base_dir.join(DEFAULT_DESCRIPTION_FILENAME), } } } diff --git a/service-providers/authenticator/src/config/template.rs b/service-providers/authenticator/src/config/template.rs index 2c4144b0f7..d4b7eb7aa6 100644 --- a/service-providers/authenticator/src/config/template.rs +++ b/service-providers/authenticator/src/config/template.rs @@ -71,9 +71,6 @@ allowed_list_location = '{{ storage_paths.allowed_list_location }}' # Location of the file containing our unknown.list unknown_list_location = '{{ storage_paths.unknown_list_location }}' -# Path to file containing description of this authenticator. -authenticator_description = '{{ storage_paths.authenticator_description }}' - ##### logging configuration options #####