From d5bc26d2e356d80a5dadea1345a5438710031ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 25 May 2023 11:55:58 +0100 Subject: [PATCH] native client config revamping --- clients/native/src/client/config/mod.rs | 140 +++++++++--------- .../src/client/config/old_config_v1_1_13.rs | 76 +++++----- .../src/client/config/old_config_v1_1_19.rs | 2 + clients/native/src/client/config/template.rs | 5 +- clients/native/src/client/mod.rs | 23 ++- clients/native/src/commands/init.rs | 53 ++++--- clients/native/src/commands/mod.rs | 25 ++-- clients/native/src/commands/run.rs | 9 +- clients/native/src/commands/upgrade.rs | 55 ++----- .../client-core/src/client/base_client/mod.rs | 6 +- .../client/base_client/non_wasm_helpers.rs | 4 +- .../config/disk_persistence/key_pathfinder.rs | 38 ++--- common/client-core/src/config/mod.rs | 12 +- .../src/config/old_config_v1_1_13.rs | 78 +++++----- common/client-core/src/init/mod.rs | 79 +++------- common/config/src/helpers.rs | 65 ++++++++ common/credential-storage/src/lib.rs | 3 +- .../src/persistent_storage.rs | 2 +- gateway/src/commands/sign.rs | 2 +- mixnode/src/commands/init.rs | 7 +- mixnode/src/config/mod.rs | 6 +- 21 files changed, 336 insertions(+), 354 deletions(-) create mode 100644 clients/native/src/client/config/old_config_v1_1_19.rs diff --git a/clients/native/src/client/config/mod.rs b/clients/native/src/client/config/mod.rs index f8a14efbb0..8f2d687e1c 100644 --- a/clients/native/src/client/config/mod.rs +++ b/clients/native/src/client/config/mod.rs @@ -1,25 +1,26 @@ // Copyright 2021-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::client::config::template::config_template; +use crate::client::config::template::CONFIG_TEMPLATE; use nym_client_core::config::disk_persistence::CommonClientPathfinder; -use nym_client_core::config::ClientCoreConfigTrait; use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT; use nym_config::{ - must_get_home, NymConfig, OptionalSet, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, - DEFAULT_DATA_DIR, NYM_DIR, + define_optional_set_inner, must_get_home, read_config_from_toml_file, + save_formatted_config_to_file, NymConfigTemplate, OptionalSet, DEFAULT_CONFIG_DIR, + DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR, }; use serde::{Deserialize, Serialize}; use std::fmt::Debug; +use std::io; use std::net::{IpAddr, Ipv4Addr}; use std::path::{Path, PathBuf}; use std::str::FromStr; pub use nym_client_core::config::Config as BaseConfig; -pub use nym_client_core::config::MISSING_VALUE; pub use nym_client_core::config::{DebugConfig, GatewayEndpointConfig}; pub mod old_config_v1_1_13; +pub mod old_config_v1_1_19; mod template; const DEFAULT_CLIENTS_DIR: &str = "clients"; @@ -58,8 +59,7 @@ impl SocketType { } } -#[derive(Debug, Default, Deserialize, PartialEq, Serialize)] -#[serde(deny_unknown_fields)] +#[derive(Debug, Deserialize, PartialEq, Serialize)] pub struct Config { #[serde(flatten)] pub base: BaseConfig, @@ -71,6 +71,12 @@ pub struct Config { pub logging: Logging, } +impl NymConfigTemplate for Config { + fn template() -> &'static str { + CONFIG_TEMPLATE + } +} + impl Config { pub fn new>(id: S) -> Self { Config { @@ -81,8 +87,21 @@ impl Config { } } - pub fn get_gateway_endpoint(&self) -> &GatewayEndpointConfig { - self.base.get_gateway_endpoint() + pub fn read_from_toml_file>(path: P) -> io::Result { + read_config_from_toml_file(path) + } + + pub fn read_from_default_path>(id: P) -> io::Result { + Self::read_from_toml_file(default_config_filepath(id)) + } + + pub fn default_location(&self) -> PathBuf { + default_config_filepath(&self.base.client.id) + } + + pub fn save_to_default_location(&self) -> io::Result<()> { + let config_save_location: PathBuf = self.default_location(); + save_formatted_config_to_file(self, config_save_location) } pub fn validate(&self) -> bool { @@ -114,80 +133,53 @@ impl Config { self } - // getters - pub fn get_config_file_save_location(&self) -> PathBuf { - self.config_directory().join(Self::config_file_name()) + // poor man's 'builder' method + pub fn with_base(mut self, f: F, val: T) -> Self + where + F: Fn(BaseConfig, T) -> BaseConfig, + { + self.base = f(self.base, val); + self } - // pub fn get_base(&self) -> &BaseConfig { - // &self.base - // } - // - // pub fn get_base_mut(&mut self) -> &mut BaseConfig { - // &mut self.base - // } - - pub fn get_debug_settings(&self) -> &DebugConfig { - self.get_base().get_debug_config() + // helper methods to use `OptionalSet` trait. Those are defined due to very... ehm. 'specific' structure of this config + // (plz, lets refactor it) + pub fn with_optional_ext(mut self, f: F, val: Option) -> Self + where + F: Fn(BaseConfig, T) -> BaseConfig, + { + self.base = self.base.with_optional(f, val); + self } - pub fn get_socket_type(&self) -> SocketType { - self.socket.socket_type + pub fn with_optional_env_ext(mut self, f: F, val: Option, env_var: &str) -> Self + where + F: Fn(BaseConfig, T) -> BaseConfig, + T: FromStr, + ::Err: Debug, + { + self.base = self.base.with_optional_env(f, val, env_var); + self } - pub fn get_listening_ip(&self) -> IpAddr { - self.socket.host + pub fn with_optional_custom_env_ext( + mut self, + f: F, + val: Option, + env_var: &str, + parser: G, + ) -> Self + where + F: Fn(BaseConfig, T) -> BaseConfig, + G: Fn(&str) -> T, + { + self.base = self.base.with_optional_custom_env(f, val, env_var, parser); + self } - - pub fn get_listening_port(&self) -> u16 { - self.socket.listening_port - } - - // // poor man's 'builder' method - // pub fn with_base(mut self, f: F, val: T) -> Self - // where - // F: Fn(BaseConfig, T) -> BaseConfig, - // { - // self.base = f(self.base, val); - // self - // } - // - // // helper methods to use `OptionalSet` trait. Those are defined due to very... ehm. 'specific' structure of this config - // // (plz, lets refactor it) - // pub fn with_optional_ext(mut self, f: F, val: Option) -> Self - // where - // F: Fn(BaseConfig, T) -> BaseConfig, - // { - // self.base = self.base.with_optional(f, val); - // self - // } - // - // pub fn with_optional_env_ext(mut self, f: F, val: Option, env_var: &str) -> Self - // where - // F: Fn(BaseConfig, T) -> BaseConfig, - // T: FromStr, - // ::Err: Debug, - // { - // self.base = self.base.with_optional_env(f, val, env_var); - // self - // } - // - // pub fn with_optional_custom_env_ext( - // mut self, - // f: F, - // val: Option, - // env_var: &str, - // parser: G, - // ) -> Self - // where - // F: Fn(BaseConfig, T) -> BaseConfig, - // G: Fn(&str) -> T, - // { - // self.base = self.base.with_optional_custom_env(f, val, env_var, parser); - // self - // } } +// define_optional_set_inner!(Config, base, BaseConfig); + #[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] pub struct Logging {} diff --git a/clients/native/src/client/config/old_config_v1_1_13.rs b/clients/native/src/client/config/old_config_v1_1_13.rs index 9e1b5bff81..d0f3da819b 100644 --- a/clients/native/src/client/config/old_config_v1_1_13.rs +++ b/clients/native/src/client/config/old_config_v1_1_13.rs @@ -3,7 +3,6 @@ use crate::client::config::{Config, Socket}; use nym_client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13; -use nym_config::NymConfig; use serde::{Deserialize, Serialize}; use std::path::PathBuf; @@ -16,45 +15,46 @@ pub struct OldConfigV1_1_13 { socket: Socket, } -impl NymConfig for OldConfigV1_1_13 { - fn template() -> &'static str { - // not intended to be used - unimplemented!() - } - - fn default_root_directory() -> PathBuf { - dirs::home_dir() - .expect("Failed to evaluate $HOME value") - .join(".nym") - .join("clients") - } - - fn try_default_root_directory() -> Option { - dirs::home_dir().map(|path| path.join(".nym").join("clients")) - } - - fn root_directory(&self) -> PathBuf { - self.base.client.nym_root_directory.clone() - } - - fn config_directory(&self) -> PathBuf { - self.root_directory() - .join(&self.base.client.id) - .join("config") - } - - fn data_directory(&self) -> PathBuf { - self.root_directory() - .join(&self.base.client.id) - .join("data") - } -} +// impl NymConfig for OldConfigV1_1_13 { +// fn template() -> &'static str { +// // not intended to be used +// unimplemented!() +// } +// +// fn default_root_directory() -> PathBuf { +// dirs::home_dir() +// .expect("Failed to evaluate $HOME value") +// .join(".nym") +// .join("clients") +// } +// +// fn try_default_root_directory() -> Option { +// dirs::home_dir().map(|path| path.join(".nym").join("clients")) +// } +// +// fn root_directory(&self) -> PathBuf { +// self.base.client.nym_root_directory.clone() +// } +// +// fn config_directory(&self) -> PathBuf { +// self.root_directory() +// .join(&self.base.client.id) +// .join("config") +// } +// +// fn data_directory(&self) -> PathBuf { +// self.root_directory() +// .join(&self.base.client.id) +// .join("data") +// } +// } impl From for Config { fn from(value: OldConfigV1_1_13) -> Self { - Config { - base: value.base.into(), - socket: value.socket, - } + todo!() + // Config { + // base: value.base.into(), + // socket: value.socket, + // } } } diff --git a/clients/native/src/client/config/old_config_v1_1_19.rs b/clients/native/src/client/config/old_config_v1_1_19.rs new file mode 100644 index 0000000000..38dc36ebc3 --- /dev/null +++ b/clients/native/src/client/config/old_config_v1_1_19.rs @@ -0,0 +1,2 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 diff --git a/clients/native/src/client/config/template.rs b/clients/native/src/client/config/template.rs index 1c9a19f061..0e9b36587f 100644 --- a/clients/native/src/client/config/template.rs +++ b/clients/native/src/client/config/template.rs @@ -1,7 +1,7 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -pub(crate) fn config_template() -> &'static str { +pub(crate) const CONFIG_TEMPLATE: &str = // While using normal toml marshalling would have been way simpler with less overhead, // I think it's useful to have comments attached to the saved config file to explain behaviour of // particular fields. @@ -120,5 +120,4 @@ average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}' [debug.cover_traffic] loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}' -"# -} +"#; diff --git a/clients/native/src/client/mod.rs b/clients/native/src/client/mod.rs index c520521587..5223212ab2 100644 --- a/clients/native/src/client/mod.rs +++ b/clients/native/src/client/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2021-2022 - Nym Technologies SA +// Copyright 2021-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 use crate::client::config::Config; @@ -50,11 +50,11 @@ impl SocketClient { config: &Config, ) -> BandwidthController, PersistentStorage> { let storage = nym_credential_storage::initialise_persistent_storage( - config.get_base().get_database_path(), + &config.paths.credentials_database, ) .await; - create_bandwidth_controller(config.get_base(), storage) + create_bandwidth_controller(&config.base, storage) } fn start_websocket_listener( @@ -93,7 +93,7 @@ impl SocketClient { Some(packet_type), ); - websocket::Listener::new(config.get_listening_ip(), config.get_listening_port()) + websocket::Listener::new(config.socket.host, config.socket.listening_port) .start(websocket_handler, shutdown); } @@ -107,26 +107,25 @@ impl SocketClient { } fn key_store(&self) -> OnDiskKeys { - let pathfinder = ClientKeysPathfinder::new_from_config(self.config.get_base()); - OnDiskKeys::new(pathfinder) + OnDiskKeys::new(self.config.paths.key_pathfinder.clone()) } // TODO: see if this could also be shared with socks5 client / nym-sdk maybe async fn create_base_client_builder(&self) -> Result { // don't create bandwidth controller if credentials are disabled - let bandwidth_controller = if self.config.get_base().get_disabled_credentials_mode() { + let bandwidth_controller = if self.config.base.client.disabled_credentials_mode { None } else { Some(Self::create_bandwidth_controller(&self.config).await) }; let base_client = BaseClientBuilder::new_from_base_config( - self.config.get_base(), + &self.config.base, self.key_store(), bandwidth_controller, non_wasm_helpers::setup_fs_reply_surb_backend( - self.config.get_base().get_reply_surb_database_path(), - &self.config.get_debug_settings().reply_surbs, + &self.config.paths.reply_surb_database_path, + &self.config.base.debug.reply_surbs, ) .await?, ); @@ -135,7 +134,7 @@ impl SocketClient { } pub async fn start_socket(self) -> Result { - if !self.config.get_socket_type().is_websocket() { + if !self.config.socket.socket_type.is_websocket() { return Err(ClientError::InvalidSocketMode); } @@ -164,7 +163,7 @@ impl SocketClient { } pub async fn start_direct(self) -> Result { - if self.config.get_socket_type().is_websocket() { + if self.config.socket.socket_type.is_websocket() { return Err(ClientError::InvalidSocketMode); } diff --git a/clients/native/src/commands/init.rs b/clients/native/src/commands/init.rs index 293dbe93f4..5b92e73c90 100644 --- a/clients/native/src/commands/init.rs +++ b/clients/native/src/commands/init.rs @@ -1,6 +1,7 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use crate::client::config::default_config_filepath; use crate::commands::try_upgrade_v1_1_13_config; use crate::{ client::config::Config, @@ -10,7 +11,6 @@ use crate::{ use clap::Args; use nym_bin_common::output_format::OutputFormat; use nym_client_core::client::key_manager::persistence::OnDiskKeys; -use nym_config::NymConfig; use nym_crypto::asymmetric::identity; use nym_sphinx::addressing::clients::Recipient; use serde::Serialize; @@ -97,15 +97,15 @@ impl From for OverrideConfig { pub struct InitResults { #[serde(flatten)] client_core: nym_client_core::init::InitResults, - client_listening_port: String, + client_listening_port: u16, client_address: String, } impl InitResults { fn new(config: &Config, address: &Recipient) -> Self { Self { - client_core: nym_client_core::init::InitResults::new(config.get_base(), address), - client_listening_port: config.get_listening_port().to_string(), + client_core: nym_client_core::init::InitResults::new(&config.base, address), + client_listening_port: config.socket.listening_port, client_address: address.to_string(), } } @@ -124,13 +124,15 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> { let id = &args.id; - let already_init = Config::default_config_file_path(id).exists(); - if already_init { + let already_init = if default_config_filepath(&id).exists() { // in case we're using old config, try to upgrade it // (if we're using the current version, it's a no-op) try_upgrade_v1_1_13_config(id)?; eprintln!("Client \"{id}\" was already initialised before"); - } + true + } else { + false + }; // Usually you only register with the gateway on the first init, however you can force // re-registering if wanted. @@ -152,42 +154,37 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> { // Setup gateway by either registering a new one, or creating a new config from the selected // one but with keys kept, or reusing the gateway configuration. - let key_store = OnDiskKeys::from_config(config.get_base()); - let gateway = nym_client_core::init::setup_gateway_from_config::( + let key_store = OnDiskKeys::new(config.paths.key_pathfinder.clone()); + let gateway = nym_client_core::init::setup_gateway_from_config::<_>( &key_store, register_gateway, user_chosen_gateway_id, - config.get_base(), + &config.base, args.latency_based_selection, ) .await .tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?; - config.get_base_mut().set_gateway_endpoint(gateway); + config.base.set_gateway_endpoint(gateway); - config.save_to_file(None).tap_err(|_| { + let config_save_location = config.default_location(); + config.save_to_default_location().tap_err(|_| { log::error!("Failed to save the config file"); })?; + eprintln!( + "Saved configuration file to {}", + config_save_location.display() + ); - print_saved_config(&config); + let address = nym_client_core::init::get_client_address_from_stored_ondisk_keys( + &config.paths.key_pathfinder, + &config.base.client.gateway_endpoint, + )?; + + eprintln!("Client configuration completed.\n"); - let address = - nym_client_core::init::get_client_address_from_stored_ondisk_keys(config.get_base())?; let init_results = InitResults::new(&config, &address); println!("{}", args.output.format(&init_results)); Ok(()) } - -fn print_saved_config(config: &Config) { - let config_save_location = config.get_config_file_save_location(); - eprintln!("Saved configuration file to {config_save_location:?}"); - eprintln!("Using gateway: {}", config.get_base().get_gateway_id()); - log::debug!("Gateway id: {}", config.get_base().get_gateway_id()); - log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner()); - log::debug!( - "Gateway listener: {}", - config.get_base().get_gateway_listener() - ); - eprintln!("Client configuration completed.\n"); -} diff --git a/clients/native/src/commands/mod.rs b/clients/native/src/commands/mod.rs index b2227a2795..0a89125dc7 100644 --- a/clients/native/src/commands/mod.rs +++ b/clients/native/src/commands/mod.rs @@ -9,7 +9,7 @@ use lazy_static::lazy_static; use log::info; use nym_bin_common::build_information::BinaryBuildInformation; use nym_bin_common::completions::{fig_generate, ArgShell}; -use nym_config::{NymConfig, OptionalSet}; +use nym_config::OptionalSet; use std::error::Error; use std::net::IpAddr; @@ -105,17 +105,18 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config { } fn try_upgrade_v1_1_13_config(id: &str) -> std::io::Result<()> { - // explicitly load it as v1.1.13 (which is incompatible with the current, i.e. 1.1.14+) - let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else { - // if we failed to load it, there might have been nothing to upgrade - // or maybe it was an even older file. in either way. just ignore it and carry on with our day - return Ok(()); - }; - info!("It seems the client is using <= v1.1.13 config template."); - info!("It is going to get updated to the current specification."); - - let updated: Config = old_config.into(); - updated.save_to_file(None) + todo!() + // // explicitly load it as v1.1.13 (which is incompatible with the current, i.e. 1.1.14+) + // let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else { + // // if we failed to load it, there might have been nothing to upgrade + // // or maybe it was an even older file. in either way. just ignore it and carry on with our day + // return Ok(()); + // }; + // info!("It seems the client is using <= v1.1.13 config template."); + // info!("It is going to get updated to the current specification."); + // + // let updated: Config = old_config.into(); + // updated.save_to_file(None) } #[cfg(test)] diff --git a/clients/native/src/commands/run.rs b/clients/native/src/commands/run.rs index 93936a7d24..d73743ca4f 100644 --- a/clients/native/src/commands/run.rs +++ b/clients/native/src/commands/run.rs @@ -13,7 +13,6 @@ use crate::{ use clap::Args; use log::*; use nym_bin_common::version_checker::is_minor_version_compatible; -use nym_config::NymConfig; use nym_crypto::asymmetric::identity; #[derive(Args, Clone)] @@ -82,7 +81,7 @@ impl From for OverrideConfig { // network version. It might do so in the future. fn version_check(cfg: &Config) -> bool { let binary_version = env!("CARGO_PKG_VERSION"); - let config_version = cfg.get_base().get_version(); + let config_version = &cfg.base.client.version; if binary_version == config_version { true } else { @@ -104,7 +103,7 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box cfg, Err(err) => { error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id); @@ -119,10 +118,6 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box // SPDX-License-Identifier: Apache-2.0 -use crate::client::config::{Config, MISSING_VALUE}; - -use nym_bin_common::version_checker::Version; -use nym_config::NymConfig; - +use crate::client::config::Config; use clap::Args; +use nym_bin_common::version_checker::Version; use std::fmt::Display; use std::process; @@ -40,6 +37,12 @@ fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> ! process::exit(1) } +fn unimplemented_upgrade(current_version: &Version, config_version: &Version) -> ! { + eprintln!("Cannot perform upgrade from {config_version} to {current_version} as it hasn't been implemented yet"); + todo!(); + process::exit(1) +} + #[derive(Args, Clone)] pub(crate) struct Upgrade { /// Id of the nym-client we want to upgrade @@ -48,7 +51,7 @@ pub(crate) struct Upgrade { } fn parse_config_version(config: &Config) -> Version { - let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| { + let version = Version::parse(&config.base.client.version).unwrap_or_else(|err| { eprintln!("failed to parse client version! - {err}"); process::exit(1) }); @@ -77,35 +80,6 @@ fn parse_package_version() -> Version { version } -fn minor_0_12_upgrade( - mut config: Config, - _matches: &Upgrade, - config_version: &Version, - package_version: &Version, -) -> Config { - let to_version = if package_version.major == 0 && package_version.minor == 12 { - package_version.clone() - } else { - Version::new(0, 12, 0) - }; - - print_start_upgrade(config_version, &to_version); - - config - .get_base_mut() - .set_custom_version(to_version.to_string().as_ref()); - - config.save_to_file(None).unwrap_or_else(|err| { - eprintln!("failed to overwrite config file! - {err}"); - print_failed_upgrade(config_version, &to_version); - process::exit(1); - }); - - print_successful_upgrade(config_version, to_version); - - config -} - fn do_upgrade(mut config: Config, args: &Upgrade, package_version: &Version) { loop { let config_version = parse_config_version(&config); @@ -116,9 +90,10 @@ fn do_upgrade(mut config: Config, args: &Upgrade, package_version: &Version) { } config = match config_version.major { - 0 => match config_version.minor { - 9 | 10 => outdated_upgrade(&config_version, package_version), - 11 => minor_0_12_upgrade(config, args, &config_version, package_version), + 0 => outdated_upgrade(&config_version, package_version), + 1 => match config_version.minor { + n if n <= 13 => outdated_upgrade(&config_version, package_version), + n if n > 13 && n < 19 => unimplemented_upgrade(&config_version, package_version), _ => unsupported_upgrade(&config_version, package_version), }, _ => unsupported_upgrade(&config_version, package_version), @@ -131,12 +106,12 @@ pub(crate) fn execute(args: &Upgrade) { let id = &args.id; - let existing_config = Config::load_from_file(id).unwrap_or_else(|err| { + let existing_config = Config::read_from_default_path(id).unwrap_or_else(|err| { eprintln!("failed to load existing config file! - {err}"); process::exit(1) }); - if existing_config.get_base().get_version() == MISSING_VALUE { + if existing_config.base.client.version.is_empty() { eprintln!("the existing configuration file does not seem to contain version number."); process::exit(1); } diff --git a/common/client-core/src/client/base_client/mod.rs b/common/client-core/src/client/base_client/mod.rs index bf4803140a..243c144732 100644 --- a/common/client-core/src/client/base_client/mod.rs +++ b/common/client-core/src/client/base_client/mod.rs @@ -176,15 +176,15 @@ where C: DkgQueryClient + Send + Sync + 'static, { // TODO: combine all storages - pub fn new_from_base_config( - base_config: &'a Config, + pub fn new_from_base_config( + base_config: &'a Config, key_store: S::KeyStore, bandwidth_controller: Option>, reply_storage_backend: S::ReplyStore, ) -> BaseClientBuilder<'a, C, S> { BaseClientBuilder { gateway_config: base_config.get_gateway_endpoint_config(), - debug_config: base_config.get_debug_config(), + debug_config: &base_config.debug, disabled_credentials: base_config.get_disabled_credentials_mode(), nym_api_endpoints: base_config.get_nym_api_endpoints(), bandwidth_controller, diff --git a/common/client-core/src/client/base_client/non_wasm_helpers.rs b/common/client-core/src/client/base_client/non_wasm_helpers.rs index b3e9ae4cf1..8d34a50b11 100644 --- a/common/client-core/src/client/base_client/non_wasm_helpers.rs +++ b/common/client-core/src/client/base_client/non_wasm_helpers.rs @@ -101,8 +101,8 @@ pub async fn setup_fs_reply_surb_backend>( } } -pub fn create_bandwidth_controller( - config: &Config, +pub fn create_bandwidth_controller( + config: &Config, storage: St, ) -> BandwidthController, St> { let nyxd_url = config diff --git a/common/client-core/src/config/disk_persistence/key_pathfinder.rs b/common/client-core/src/config/disk_persistence/key_pathfinder.rs index 6677f278e0..a434778961 100644 --- a/common/client-core/src/config/disk_persistence/key_pathfinder.rs +++ b/common/client-core/src/config/disk_persistence/key_pathfinder.rs @@ -63,49 +63,49 @@ impl ClientKeysPathfinder { } pub fn any_file_exists(&self) -> bool { - matches!(self.identity_public_key.try_exists(), Ok(true)) - || matches!(self.identity_private_key.try_exists(), Ok(true)) - || matches!(self.encryption_public_key.try_exists(), Ok(true)) - || matches!(self.encryption_private_key.try_exists(), Ok(true)) - || matches!(self.gateway_shared_key.try_exists(), Ok(true)) - || matches!(self.ack_key.try_exists(), Ok(true)) + matches!(self.public_identity_key_file.try_exists(), Ok(true)) + || matches!(self.private_identity_key_file.try_exists(), Ok(true)) + || matches!(self.public_encryption_key_file.try_exists(), Ok(true)) + || matches!(self.private_encryption_key_file.try_exists(), Ok(true)) + || matches!(self.gateway_shared_key_file.try_exists(), Ok(true)) + || matches!(self.ack_key_file.try_exists(), Ok(true)) } pub fn any_file_exists_and_return(&self) -> Option { - file_exists(&self.identity_public_key) - .or_else(|| file_exists(&self.identity_private_key)) - .or_else(|| file_exists(&self.encryption_public_key)) - .or_else(|| file_exists(&self.encryption_private_key)) - .or_else(|| file_exists(&self.gateway_shared_key)) - .or_else(|| file_exists(&self.ack_key)) + file_exists(&self.public_identity_key_file) + .or_else(|| file_exists(&self.private_identity_key_file)) + .or_else(|| file_exists(&self.public_encryption_key_file)) + .or_else(|| file_exists(&self.private_encryption_key_file)) + .or_else(|| file_exists(&self.gateway_shared_key_file)) + .or_else(|| file_exists(&self.ack_key_file)) } pub fn gateway_key_file_exists(&self) -> bool { - matches!(self.gateway_shared_key.try_exists(), Ok(true)) + matches!(self.gateway_shared_key_file.try_exists(), Ok(true)) } pub fn private_identity_key(&self) -> &Path { - &self.identity_private_key + &self.private_identity_key_file } pub fn public_identity_key(&self) -> &Path { - &self.identity_public_key + &self.public_identity_key_file } pub fn private_encryption_key(&self) -> &Path { - &self.encryption_private_key + &self.private_encryption_key_file } pub fn public_encryption_key(&self) -> &Path { - &self.encryption_public_key + &self.public_encryption_key_file } pub fn gateway_shared_key(&self) -> &Path { - &self.gateway_shared_key + &self.gateway_shared_key_file } pub fn ack_key(&self) -> &Path { - &self.ack_key + &self.ack_key_file } } diff --git a/common/client-core/src/config/mod.rs b/common/client-core/src/config/mod.rs index 23035a465f..b9481272aa 100644 --- a/common/client-core/src/config/mod.rs +++ b/common/client-core/src/config/mod.rs @@ -55,7 +55,7 @@ const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 6 // 24 hours const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60); -#[derive(Debug, Default, Clone, Deserialize, PartialEq, Serialize)] +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct Config { pub client: Client, @@ -180,14 +180,6 @@ impl Config { pub fn get_gateway_endpoint_config(&self) -> &GatewayEndpointConfig { &self.client.gateway_endpoint } - - pub fn get_database_path(&self) -> PathBuf { - self.client.database_path.clone() - } - - pub fn get_reply_surb_database_path(&self) -> PathBuf { - self.client.reply_surb_database_path.clone() - } } #[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)] @@ -281,7 +273,7 @@ impl Client { Client { version: env!("CARGO_PKG_VERSION").to_string(), - id: "DEFAULT-CLIENT".to_string(), + id: id.into(), disabled_credentials_mode: true, nyxd_urls, nym_api_urls, diff --git a/common/client-core/src/config/old_config_v1_1_13.rs b/common/client-core/src/config/old_config_v1_1_13.rs index 9c06f885b0..54addf2dcf 100644 --- a/common/client-core/src/config/old_config_v1_1_13.rs +++ b/common/client-core/src/config/old_config_v1_1_13.rs @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use crate::config::{ - Acknowledgements, Client, Config, CoverTraffic, DebugConfig, GatewayConnection, Logging, - ReplySurbs, Topology, Traffic, DEFAULT_ACK_WAIT_ADDITION, DEFAULT_ACK_WAIT_MULTIPLIER, + Acknowledgements, Client, Config, CoverTraffic, DebugConfig, GatewayConnection, ReplySurbs, + Topology, Traffic, DEFAULT_ACK_WAIT_ADDITION, DEFAULT_ACK_WAIT_MULTIPLIER, DEFAULT_AVERAGE_PACKET_DELAY, DEFAULT_GATEWAY_RESPONSE_TIMEOUT, DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY, DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE, DEFAULT_MAXIMUM_REPLY_KEY_AGE, DEFAULT_MAXIMUM_REPLY_SURB_AGE, @@ -13,12 +13,13 @@ use crate::config::{ DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE, DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD, DEFAULT_TOPOLOGY_REFRESH_RATE, DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT, }; -use nym_config::NymConfig; use nym_sphinx::params::PacketSize; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; use std::time::Duration; +// use nym_config::NymConfig; + #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "lowercase")] pub enum ExtendedPacketSize { @@ -40,21 +41,22 @@ impl From for PacketSize { #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct OldConfigV1_1_13 { - pub client: Client, - - #[serde(default)] - logging: Logging, + pub client: PhantomData, + // pub client: Client, + // #[serde(default)] + // logging: Logging, #[serde(default)] debug: OldDebugConfigV1_1_13, } -impl Default for OldConfigV1_1_13 { +impl Default for OldConfigV1_1_13 { fn default() -> Self { - OldConfigV1_1_13 { - client: Client::::default(), - logging: Default::default(), - debug: Default::default(), - } + todo!() + // OldConfigV1_1_13 { + // client: Client::::default(), + // logging: Default::default(), + // debug: Default::default(), + // } } } @@ -125,7 +127,6 @@ impl From for DebugConfig { .disable_main_poisson_packet_distribution, primary_packet_size: PacketSize::RegularPacket, secondary_packet_size: value.use_extended_packet_size.map(Into::into), - packet_type: None, }, cover_traffic: CoverTraffic { loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay, @@ -192,30 +193,31 @@ impl Default for OldDebugConfigV1_1_13 { } } -impl From> for Config { +impl From> for Config { fn from(value: OldConfigV1_1_13) -> Self { - Config { - client: Client { - version: value.client.version, - id: value.client.id, - disabled_credentials_mode: value.client.disabled_credentials_mode, - nyxd_urls: value.client.nyxd_urls, - nym_api_urls: value.client.nym_api_urls, - private_identity_key_file: value.client.private_identity_key_file, - public_identity_key_file: value.client.public_identity_key_file, - private_encryption_key_file: value.client.private_encryption_key_file, - public_encryption_key_file: value.client.public_encryption_key_file, - gateway_shared_key_file: value.client.gateway_shared_key_file, - ack_key_file: value.client.ack_key_file, - gateway_endpoint: value.client.gateway_endpoint, - database_path: value.client.database_path, - reply_surb_database_path: value.client.reply_surb_database_path, - nym_root_directory: value.client.nym_root_directory, - super_struct: PhantomData, - packet_type: Some(nym_sphinx::params::PacketType::Mix), - }, - logging: value.logging, - debug: value.debug.into(), - } + todo!() + // Config { + // client: Client { + // version: value.client.version, + // id: value.client.id, + // disabled_credentials_mode: value.client.disabled_credentials_mode, + // nyxd_urls: value.client.nyxd_urls, + // nym_api_urls: value.client.nym_api_urls, + // private_identity_key_file: value.client.private_identity_key_file, + // public_identity_key_file: value.client.public_identity_key_file, + // private_encryption_key_file: value.client.private_encryption_key_file, + // public_encryption_key_file: value.client.public_encryption_key_file, + // gateway_shared_key_file: value.client.gateway_shared_key_file, + // ack_key_file: value.client.ack_key_file, + // gateway_endpoint: value.client.gateway_endpoint, + // database_path: value.client.database_path, + // reply_surb_database_path: value.client.reply_surb_database_path, + // nym_root_directory: value.client.nym_root_directory, + // + // super_struct: PhantomData, + // }, + // logging: value.logging, + // debug: value.debug.into(), + // } } } diff --git a/common/client-core/src/init/mod.rs b/common/client-core/src/init/mod.rs index e77ff57456..1a6d44d2a2 100644 --- a/common/client-core/src/init/mod.rs +++ b/common/client-core/src/init/mod.rs @@ -120,13 +120,10 @@ pub struct InitResults { } impl InitResults { - pub fn new(config: &Config, address: &Recipient) -> Self - where - T: NymConfig, - { + pub fn new(config: &Config, address: &Recipient) -> Self { Self { - version: config.get_version().to_string(), - id: config.get_id(), + version: config.client.version.clone(), + id: config.client.id.clone(), identity_key: address.identity().to_base58_string(), encryption_key: address.encryption_key().to_base58_string(), gateway_id: config.get_gateway_id(), @@ -204,26 +201,22 @@ where /// b. Create a new gateway configuration but keep existing keys. This assumes that the caller /// knows what they are doing and that the keys match the requested gateway. /// c. Create a new gateway configuration with a newly registered gateway and keys. -pub async fn setup_gateway_from_config( +pub async fn setup_gateway_from_config( key_store: &KSt, register_gateway: bool, user_chosen_gateway_id: Option, - config: &Config, + config: &Config, by_latency: bool, ) -> Result where - C: NymConfig + ClientCoreConfigTrait, - T: NymConfig, KSt: KeyStore, ::StorageError: Send + Sync + 'static, { - let id = config.get_id(); - // If we are not going to register gateway, and an explicitly chosen gateway is not passed in, // load the existing configuration file if !register_gateway && user_chosen_gateway_id.is_none() { eprintln!("Not registering gateway, will reuse existing config and keys"); - return load_existing_gateway_config::(&id); + return Ok(config.client.gateway_endpoint.clone()); } let gateway_setup = GatewaySetup::new( @@ -264,25 +257,6 @@ where Ok(gateway) } -/// Read and reuse the existing gateway configuration from a file that was generate earlier. -pub fn load_existing_gateway_config(id: &str) -> Result -where - T: NymConfig + ClientCoreConfigTrait, -{ - T::load_from_file(id) - .map(|existing_config| existing_config.get_gateway_endpoint().clone()) - .map_err(|err| { - log::error!( - "Unable to configure gateway: {err}. \n - Seems like the client was already initialized but it was not possible to read \ - the existing configuration file. \n - CAUTION: Consider backing up your gateway keys and try force gateway registration, or \ - removing the existing configuration and starting over." - ); - ClientCoreError::CouldNotLoadExistingGatewayConfiguration(err) - }) -} - /// Get the full client address from the client keys and the gateway identity pub fn get_client_address( key_manager: &KeyManager, @@ -299,40 +273,21 @@ pub fn get_client_address( /// Get the client address by loading the keys from stored files. // TODO: rethink that sucker -pub fn get_client_address_from_stored_ondisk_keys( - config: &Config, -) -> Result -where - T: nym_config::NymConfig, -{ - fn load_identity_keys( - pathfinder: &ClientKeysPathfinder, - ) -> Result { - let identity_keypair: identity::KeyPair = - nym_pemstore::load_keypair(&pathfinder.identity_key_pair_path()) - .tap_err(|_| log::error!("Failed to read stored identity key files"))?; - Ok(identity_keypair) - } - - fn load_sphinx_keys( - pathfinder: &ClientKeysPathfinder, - ) -> Result { - let sphinx_keypair: encryption::KeyPair = - nym_pemstore::load_keypair(&pathfinder.encryption_key_pair_path()) - .tap_err(|_| log::error!("Failed to read stored sphinx key files"))?; - Ok(sphinx_keypair) - } - - let pathfinder = ClientKeysPathfinder::new_from_config(config); - let identity_keypair = load_identity_keys(&pathfinder)?; - let sphinx_keypair = load_sphinx_keys(&pathfinder)?; +pub fn get_client_address_from_stored_ondisk_keys( + pathfinder: &ClientKeysPathfinder, + gateway_config: &GatewayEndpointConfig, +) -> Result { + let public_identity: identity::PublicKey = + nym_pemstore::load_key(&pathfinder.public_identity_key_file)?; + let public_encryption: encryption::PublicKey = + nym_pemstore::load_key(&pathfinder.public_encryption_key_file)?; let client_recipient = Recipient::new( - *identity_keypair.public_key(), - *sphinx_keypair.public_key(), + public_identity, + public_encryption, // TODO: below only works under assumption that gateway address == gateway id // (which currently is true) - NodeIdentity::from_base58_string(config.get_gateway_id())?, + NodeIdentity::from_base58_string(&gateway_config.gateway_id)?, ); Ok(client_recipient) diff --git a/common/config/src/helpers.rs b/common/config/src/helpers.rs index df2717bb57..cfed0dc1c7 100644 --- a/common/config/src/helpers.rs +++ b/common/config/src/helpers.rs @@ -128,6 +128,71 @@ pub trait OptionalSet { } } +// helper for when we want to use `OptionalSet` on an inner field +// (used by clients wanting to set the `BaseConfig` values) +#[macro_export] +macro_rules! define_optional_set_inner { + ( $x: ident, $inner_field_name: ident, $inner_field_typ: ty ) => { + impl $x { + pub fn with_optional_inner(mut self, f: F, val: Option) -> Self + where + F: Fn($inner_field_typ, T) -> $inner_field_typ, + { + self.$inner_field_name = self.$inner_field_name.with_optional(f, val); + self + } + + pub fn with_validated_optional_inner( + mut self, + f: F, + value: Option, + validate: V, + ) -> Result + where + F: Fn($inner_field_typ, T) -> $inner_field_typ, + V: Fn(&T) -> Result<(), E>, + { + self.$inner_field_name = self + .$inner_field_name + .with_validated_optional(f, value, validate)?; + Ok(self) + } + + pub fn with_optional_env_inner( + mut self, + f: F, + val: Option, + env_var: &str, + ) -> Self + where + F: Fn($inner_field_typ, T) -> $inner_field_typ, + T: FromStr, + ::Err: Debug, + { + self.$inner_field_name = self.$inner_field_name.with_optional_env(f, val, env_var); + self + } + + pub fn with_optional_custom_env_inner( + mut self, + f: F, + val: Option, + env_var: &str, + parser: G, + ) -> Self + where + F: Fn($inner_field_typ, T) -> $inner_field_typ, + G: Fn(&str) -> T, + { + self.$inner_field_name = self + .$inner_field_name + .with_optional_custom_env(f, val, env_var, parser); + self + } + } + }; +} + // this function is only used for parsing values from the network defaults and thus the "expect" there are fine pub fn parse_urls(raw: &str) -> Vec { raw.split(',') diff --git a/common/credential-storage/src/lib.rs b/common/credential-storage/src/lib.rs index 34376e67e7..7c47a4d6ad 100644 --- a/common/credential-storage/src/lib.rs +++ b/common/credential-storage/src/lib.rs @@ -6,6 +6,7 @@ use crate::ephemeral_storage::EphemeralStorage; #[cfg(not(target_arch = "wasm32"))] use crate::persistent_storage::PersistentStorage; +use std::path::Path; mod backends; pub mod ephemeral_storage; @@ -16,7 +17,7 @@ pub mod persistent_storage; pub mod storage; #[cfg(not(target_arch = "wasm32"))] -pub async fn initialise_persistent_storage(path: std::path::PathBuf) -> PersistentStorage { +pub async fn initialise_persistent_storage>(path: P) -> PersistentStorage { match persistent_storage::PersistentStorage::init(path).await { Err(err) => panic!("failed to initialise credential storage - {err}"), Ok(storage) => storage, diff --git a/common/credential-storage/src/persistent_storage.rs b/common/credential-storage/src/persistent_storage.rs index e5e454bbde..f214e40345 100644 --- a/common/credential-storage/src/persistent_storage.rs +++ b/common/credential-storage/src/persistent_storage.rs @@ -23,7 +23,7 @@ impl PersistentStorage { /// # Arguments /// /// * `database_path`: path to the database. - pub async fn init + Send>(database_path: P) -> Result { + pub async fn init>(database_path: P) -> Result { debug!( "Attempting to connect to database {:?}", database_path.as_ref().as_os_str() diff --git a/gateway/src/commands/sign.rs b/gateway/src/commands/sign.rs index c322fd4390..49aad1adb6 100644 --- a/gateway/src/commands/sign.rs +++ b/gateway/src/commands/sign.rs @@ -98,7 +98,7 @@ fn print_signed_text( let signature = private_key.sign_text(text); let sign_output = ConsoleSigningOutput::new(text, signature); - println!("{}", output.format(&sign_output)); + println!("{}", output.format(&sign_outpuant)); Ok(()) } diff --git a/mixnode/src/commands/init.rs b/mixnode/src/commands/init.rs index ccfb413f13..7850d5eef5 100644 --- a/mixnode/src/commands/init.rs +++ b/mixnode/src/commands/init.rs @@ -96,11 +96,14 @@ pub(crate) fn execute(args: &Init) { eprintln!("Saved mixnet identity and sphinx keypairs"); } - let config_save_location = default_config_filepath(id); + let config_save_location = config.default_location(); config .save_to_default_location() .expect("Failed to save the config file"); - eprintln!("Saved configuration file to {config_save_location:?}"); + eprintln!( + "Saved configuration file to {}", + config_save_location.display() + ); eprintln!("Mixnode configuration completed.\n\n\n"); MixNode::new(config).print_node_details(args.output) diff --git a/mixnode/src/config/mod.rs b/mixnode/src/config/mod.rs index 3deba570da..c328d751ec 100644 --- a/mixnode/src/config/mod.rs +++ b/mixnode/src/config/mod.rs @@ -105,8 +105,12 @@ impl Config { Self::read_from_toml_file(default_config_filepath(id)) } + pub fn default_location(&self) -> PathBuf { + default_config_filepath(&self.mixnode.id) + } + pub fn save_to_default_location(&self) -> io::Result<()> { - let config_save_location: PathBuf = default_config_filepath(&self.mixnode.id); + let config_save_location: PathBuf = self.default_location(); save_formatted_config_to_file(self, config_save_location) }