native client config revamping

This commit is contained in:
Jędrzej Stuczyński
2023-05-25 11:55:58 +01:00
parent aaa965937b
commit d5bc26d2e3
21 changed files with 336 additions and 354 deletions
+66 -74
View File
@@ -1,25 +1,26 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// 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<S: AsRef<str>>(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<P: AsRef<Path>>(path: P) -> io::Result<Self> {
read_config_from_toml_file(path)
}
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
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<F, T>(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> {
// &self.base
// }
//
// pub fn get_base_mut(&mut self) -> &mut BaseConfig<Self> {
// &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<F, T>(mut self, f: F, val: Option<T>) -> 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<F, T>(mut self, f: F, val: Option<T>, env_var: &str) -> Self
where
F: Fn(BaseConfig, T) -> BaseConfig,
T: FromStr,
<T as 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<F, T, G>(
mut self,
f: F,
val: Option<T>,
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<F, T>(mut self, f: F, val: T) -> Self
// where
// F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
// {
// 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<F, T>(mut self, f: F, val: Option<T>) -> Self
// where
// F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
// {
// self.base = self.base.with_optional(f, val);
// self
// }
//
// pub fn with_optional_env_ext<F, T>(mut self, f: F, val: Option<T>, env_var: &str) -> Self
// where
// F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
// T: FromStr,
// <T as FromStr>::Err: Debug,
// {
// self.base = self.base.with_optional_env(f, val, env_var);
// self
// }
//
// pub fn with_optional_custom_env_ext<F, T, G>(
// mut self,
// f: F,
// val: Option<T>,
// env_var: &str,
// parser: G,
// ) -> Self
// where
// F: Fn(BaseConfig<Self>, T) -> BaseConfig<Self>,
// 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 {}
@@ -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<PathBuf> {
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<PathBuf> {
// 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<OldConfigV1_1_13> 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,
// }
}
}
@@ -0,0 +1,2 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
+2 -3
View File
@@ -1,7 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// 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 }}'
"#
}
"#;
+11 -12
View File
@@ -1,4 +1,4 @@
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::Config;
@@ -50,11 +50,11 @@ impl SocketClient {
config: &Config,
) -> BandwidthController<Client<QueryNyxdClient>, 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<NativeClientBuilder, ClientError> {
// 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<TaskManager, ClientError> {
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<DirectClient, ClientError> {
if self.config.get_socket_type().is_websocket() {
if self.config.socket.socket_type.is_websocket() {
return Err(ClientError::InvalidSocketMode);
}
+25 -28
View File
@@ -1,6 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// 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<Init> 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::<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");
}
+13 -12
View File
@@ -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)]
+2 -7
View File
@@ -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<Run> 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<dyn Error + Send + Syn
// (if we're using the current version, it's a no-op)
try_upgrade_v1_1_13_config(id)?;
let mut config = match Config::load_from_file(id) {
let mut config = match Config::read_from_default_path(id) {
Ok(cfg) => 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<dyn Error + Send + Syn
let override_config_fields = OverrideConfig::from(args.clone());
config = override_config(config, override_config_fields);
if config.get_base_mut().set_empty_fields_to_defaults() {
warn!("some of the core config options were left unset. the default values are going to get used instead.");
}
if !version_check(&config) {
error!("failed the local version check");
return Err(Box::new(ClientError::FailedLocalVersionCheck));
+15 -40
View File
@@ -1,12 +1,9 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// 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);
}
@@ -176,15 +176,15 @@ where
C: DkgQueryClient + Send + Sync + 'static,
{
// TODO: combine all storages
pub fn new_from_base_config<T>(
base_config: &'a Config<T>,
pub fn new_from_base_config(
base_config: &'a Config,
key_store: S::KeyStore,
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
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,
@@ -101,8 +101,8 @@ pub async fn setup_fs_reply_surb_backend<P: AsRef<Path>>(
}
}
pub fn create_bandwidth_controller<T, St: CredentialStorage>(
config: &Config<T>,
pub fn create_bandwidth_controller<St: CredentialStorage>(
config: &Config,
storage: St,
) -> BandwidthController<Client<QueryNyxdClient>, St> {
let nyxd_url = config
@@ -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<PathBuf> {
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
}
}
+2 -10
View File
@@ -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,
@@ -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<ExtendedPacketSize> for PacketSize {
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct OldConfigV1_1_13<T> {
pub client: Client<T>,
#[serde(default)]
logging: Logging,
pub client: PhantomData<T>,
// pub client: Client<T>,
// #[serde(default)]
// logging: Logging,
#[serde(default)]
debug: OldDebugConfigV1_1_13,
}
impl<T: NymConfig> Default for OldConfigV1_1_13<T> {
impl<T> Default for OldConfigV1_1_13<T> {
fn default() -> Self {
OldConfigV1_1_13 {
client: Client::<T>::default(),
logging: Default::default(),
debug: Default::default(),
}
todo!()
// OldConfigV1_1_13 {
// client: Client::<T>::default(),
// logging: Default::default(),
// debug: Default::default(),
// }
}
}
@@ -125,7 +127,6 @@ impl From<OldDebugConfigV1_1_13> 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<T, U> From<OldConfigV1_1_13<T>> for Config<U> {
impl<T> From<OldConfigV1_1_13<T>> for Config {
fn from(value: OldConfigV1_1_13<T>) -> 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(),
// }
}
}
+17 -62
View File
@@ -120,13 +120,10 @@ pub struct InitResults {
}
impl InitResults {
pub fn new<T>(config: &Config<T>, 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<C, T, KSt>(
pub async fn setup_gateway_from_config<KSt>(
key_store: &KSt,
register_gateway: bool,
user_chosen_gateway_id: Option<identity::PublicKey>,
config: &Config<T>,
config: &Config,
by_latency: bool,
) -> Result<GatewayEndpointConfig, ClientCoreError>
where
C: NymConfig + ClientCoreConfigTrait,
T: NymConfig,
KSt: KeyStore,
<KSt as 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::<C>(&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<T>(id: &str) -> Result<GatewayEndpointConfig, ClientCoreError>
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<T>(
config: &Config<T>,
) -> Result<Recipient, ClientCoreError>
where
T: nym_config::NymConfig,
{
fn load_identity_keys(
pathfinder: &ClientKeysPathfinder,
) -> Result<identity::KeyPair, ClientCoreError> {
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<encryption::KeyPair, ClientCoreError> {
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<Recipient, ClientCoreError> {
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)
+65
View File
@@ -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<F, T>(mut self, f: F, val: Option<T>) -> 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<F, T, V, E>(
mut self,
f: F,
value: Option<T>,
validate: V,
) -> Result<Self, E>
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<F, T>(
mut self,
f: F,
val: Option<T>,
env_var: &str,
) -> Self
where
F: Fn($inner_field_typ, T) -> $inner_field_typ,
T: FromStr,
<T as 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<F, T, G>(
mut self,
f: F,
val: Option<T>,
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<url::Url> {
raw.split(',')
+2 -1
View File
@@ -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<P: AsRef<Path>>(path: P) -> PersistentStorage {
match persistent_storage::PersistentStorage::init(path).await {
Err(err) => panic!("failed to initialise credential storage - {err}"),
Ok(storage) => storage,
@@ -23,7 +23,7 @@ impl PersistentStorage {
/// # Arguments
///
/// * `database_path`: path to the database.
pub async fn init<P: AsRef<Path> + Send>(database_path: P) -> Result<Self, StorageError> {
pub async fn init<P: AsRef<Path>>(database_path: P) -> Result<Self, StorageError> {
debug!(
"Attempting to connect to database {:?}",
database_path.as_ref().as_os_str()
+1 -1
View File
@@ -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(())
}
+5 -2
View File
@@ -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)
+5 -1
View File
@@ -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)
}