From 3916bbf632785c70f88fb89a2988367b1d2f4b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Fri, 2 Jun 2023 15:00:17 +0100 Subject: [PATCH] NR config migration --- common/socks5-client-core/src/config/mod.rs | 22 ---- .../network-requester/src/cli/init.rs | 4 +- .../network-requester/src/cli/mod.rs | 78 +++++++++--- .../network-requester/src/cli/run.rs | 31 +---- .../network-requester/src/config/mod.rs | 13 +- .../src/config/old_config_v1_1_13.rs | 68 ++++------ .../src/config/old_config_v1_1_19.rs | 117 ++++++++++++++++++ .../src/config/persistence.rs | 19 --- .../network-requester/src/config/template.rs | 62 +++++----- 9 files changed, 248 insertions(+), 166 deletions(-) create mode 100644 service-providers/network-requester/src/config/old_config_v1_1_19.rs diff --git a/common/socks5-client-core/src/config/mod.rs b/common/socks5-client-core/src/config/mod.rs index cb639a036a..2411f2fbbc 100644 --- a/common/socks5-client-core/src/config/mod.rs +++ b/common/socks5-client-core/src/config/mod.rs @@ -12,8 +12,6 @@ use std::str::FromStr; pub use nym_service_providers_common::interface::ProviderInterfaceVersion; pub use nym_socks5_requests::Socks5ProtocolVersion; -// pub mod old_config_v1_1_13; - const DEFAULT_CONNECTION_START_SURBS: u32 = 20; const DEFAULT_PER_REQUEST_SURBS: u32 = 3; @@ -140,26 +138,6 @@ impl Socks5 { } } - // pub fn with_port(&mut self, port: u16) { - // self.listening_port = port; - // } - // - // pub fn with_provider_mix_address(&mut self, address: String) { - // self.provider_mix_address = address; - // } - // - // pub fn with_provider_interface_version(&mut self, version: ProviderInterfaceVersion) { - // self.provider_interface_version = version; - // } - // - // pub fn with_socks5_protocol_version(&mut self, version: Socks5ProtocolVersion) { - // self.socks5_protocol_version = version; - // } - // - // pub fn with_anonymous_replies(&mut self, anonymous_replies: bool) { - // self.send_anonymously = anonymous_replies; - // } - pub fn get_provider_mix_address(&self) -> Recipient { Recipient::try_from_base58_string(&self.provider_mix_address) .expect("malformed provider address") diff --git a/service-providers/network-requester/src/cli/init.rs b/service-providers/network-requester/src/cli/init.rs index c5992ea2ee..3d127880b9 100644 --- a/service-providers/network-requester/src/cli/init.rs +++ b/service-providers/network-requester/src/cli/init.rs @@ -1,7 +1,7 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::cli::try_upgrade_v1_1_13_config; +use crate::cli::try_upgrade_config; use crate::config::{default_config_directory, default_config_filepath, default_data_directory}; use crate::{ cli::{override_config, OverrideConfig}, @@ -109,7 +109,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), NetworkRequesterError> { 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)?; + try_upgrade_config(id)?; eprintln!("Client \"{id}\" was already initialised before"); true } else { diff --git a/service-providers/network-requester/src/cli/mod.rs b/service-providers/network-requester/src/cli/mod.rs index 2d9bdcf44e..0a803eb2b2 100644 --- a/service-providers/network-requester/src/cli/mod.rs +++ b/service-providers/network-requester/src/cli/mod.rs @@ -2,12 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 use crate::config::old_config_v1_1_13::OldConfigV1_1_13; +use crate::config::old_config_v1_1_19::ConfigV1_1_19; use crate::{ config::{BaseClientConfig, Config}, error::NetworkRequesterError, }; use clap::{CommandFactory, Parser, Subcommand}; -use log::info; +use log::{error, info}; use nym_bin_common::build_information::BinaryBuildInformation; use nym_bin_common::completions::{fig_generate, ArgShell}; @@ -98,19 +99,68 @@ pub(crate) async fn execute(args: Cli) -> Result<(), NetworkRequesterError> { Ok(()) } -fn try_upgrade_v1_1_13_config(id: &str) -> std::io::Result<()> { - 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) +fn try_upgrade_v1_1_13_config(id: &str) -> Result { + use nym_config::legacy_helpers::nym_config::MigrationNymConfig; + + // explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19) + 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(false); + }; + 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_step1: ConfigV1_1_19 = old_config.into(); + let updated: Config = updated_step1.into(); + + updated.save_to_default_location()?; + Ok(true) +} + +fn try_upgrade_v1_1_19_config(id: &str) -> Result { + use nym_config::legacy_helpers::nym_config::MigrationNymConfig; + + // explicitly load it as v1.1.19 (which is incompatible with the current one, i.e. +1.1.20) + let Ok(old_config) = ConfigV1_1_19::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(false); + }; + + info!("It seems the client is using <= v1.1.19 config template."); + info!("It is going to get updated to the current specification."); + + let updated: Config = old_config.into(); + updated.save_to_default_location()?; + Ok(true) +} + +fn try_upgrade_config(id: &str) -> Result<(), NetworkRequesterError> { + let upgraded = try_upgrade_v1_1_13_config(id)?; + if !upgraded { + try_upgrade_v1_1_19_config(id)?; + } + + Ok(()) +} + +fn try_load_current_config(id: &str) -> Result { + try_upgrade_config(id)?; + + let config = match Config::read_from_default_path(id) { + Ok(cfg) => cfg, + Err(err) => { + error!("Failed to load config for {id}. Are you sure you have run `init` before? (Error was: {err})"); + return Err(NetworkRequesterError::FailedToLoadConfig(id.to_string())); + } + }; + + if !config.validate() { + return Err(NetworkRequesterError::ConfigValidationFailure); + } + + Ok(config) } #[cfg(test)] diff --git a/service-providers/network-requester/src/cli/run.rs b/service-providers/network-requester/src/cli/run.rs index f14df39793..992641ff88 100644 --- a/service-providers/network-requester/src/cli/run.rs +++ b/service-providers/network-requester/src/cli/run.rs @@ -1,13 +1,14 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::cli::try_upgrade_v1_1_13_config; +use crate::cli::try_load_current_config; use crate::{ cli::{override_config, OverrideConfig}, config::Config, error::NetworkRequesterError, }; use clap::Args; +use log::error; use nym_bin_common::version_checker; use nym_sphinx::addressing::clients::Recipient; @@ -107,33 +108,11 @@ pub(crate) async fn execute(args: &Run) -> Result<(), NetworkRequesterError> { ); } - let id = &args.id; - - // 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)?; - - let mut config = match Config::read_from_default_path(id) { - Ok(cfg) => cfg, - Err(err) => { - log::error!( - "Failed to load config for {}. \ - Are you sure you have run `init` before? (Error was: {err})", - id - ); - return Err(NetworkRequesterError::FailedToLoadConfig(id.to_string())); - } - }; - - if !config.validate() { - return Err(NetworkRequesterError::ConfigValidationFailure); - } - - let override_config_fields = OverrideConfig::from(args.clone()); - config = override_config(config, override_config_fields); + let mut config = try_load_current_config(&args.id)?; + config = override_config(config, OverrideConfig::from(args.clone())); if !version_check(&config) { - log::error!("Failed the local version check"); + error!("failed the local version check"); return Err(NetworkRequesterError::FailedLocalVersionCheck); } diff --git a/service-providers/network-requester/src/config/mod.rs b/service-providers/network-requester/src/config/mod.rs index c88e5fb751..872dd8f7c2 100644 --- a/service-providers/network-requester/src/config/mod.rs +++ b/service-providers/network-requester/src/config/mod.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::config::template::CONFIG_TEMPLATE; +use nym_bin_common::logging::LoggingSettings; use nym_config::{ 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, @@ -18,6 +19,7 @@ pub use nym_client_core::config::Config as BaseClientConfig; pub use nym_client_core::config::{DebugConfig, GatewayEndpointConfig}; pub mod old_config_v1_1_13; +pub mod old_config_v1_1_19; mod persistence; mod template; @@ -60,14 +62,14 @@ pub struct Config { pub base: BaseClientConfig, #[serde(default)] - pub network_requester_config: NetworkRequester, + pub network_requester: NetworkRequester, - // alias due to backwards compatibility - #[serde(alias = "network_requester")] pub storage_paths: NetworkRequesterPaths, #[serde(default)] pub network_requester_debug: Debug, + + pub logging: LoggingSettings, } impl NymConfigTemplate for Config { @@ -80,9 +82,10 @@ impl Config { pub fn new>(id: S) -> Self { Config { base: BaseClientConfig::new(id.as_ref()), - network_requester_config: Default::default(), + network_requester: Default::default(), storage_paths: NetworkRequesterPaths::new_default(default_data_directory(id.as_ref())), network_requester_debug: Default::default(), + logging: Default::default(), } } @@ -127,6 +130,7 @@ impl Config { self } + #[allow(unused)] pub fn with_optional_base_env(mut self, f: F, val: Option, env_var: &str) -> Self where F: Fn(BaseClientConfig, T) -> BaseClientConfig, @@ -137,6 +141,7 @@ impl Config { self } + #[allow(unused)] pub fn with_optional_base_custom_env( mut self, f: F, diff --git a/service-providers/network-requester/src/config/old_config_v1_1_13.rs b/service-providers/network-requester/src/config/old_config_v1_1_13.rs index 5935ecc42c..b307367cd4 100644 --- a/service-providers/network-requester/src/config/old_config_v1_1_13.rs +++ b/service-providers/network-requester/src/config/old_config_v1_1_13.rs @@ -1,61 +1,35 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::config::Config; +use crate::config::old_config_v1_1_19::ConfigV1_1_19; use nym_client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13; +use nym_config::legacy_helpers::nym_config::MigrationNymConfig; use serde::{Deserialize, Serialize}; use std::path::PathBuf; -#[derive(Debug, Default, Deserialize, PartialEq, Serialize)] +#[derive(Debug, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct OldConfigV1_1_13 { #[serde(flatten)] - base: OldBaseConfigV1_1_13, + pub base: OldBaseConfigV1_1_13, } -// impl NymConfig for OldConfigV1_1_13 { -// fn template() -> &'static str { -// // not intended to be used -// unimplemented!() -// } -// -// // TODO: merge base dir with `HostStore`. -// fn default_root_directory() -> PathBuf { -// dirs::home_dir() -// .expect("Failed to evaluate $HOME value") -// .join(".nym") -// .join("service-providers") -// .join("network-requester") -// } -// -// 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 { - todo!() - // Config { - // base: value.base.into(), - // network_requester: Default::default(), - // network_requester_debug: Default::default(), - // } +impl MigrationNymConfig for OldConfigV1_1_13 { + fn default_root_directory() -> PathBuf { + dirs::home_dir() + .expect("Failed to evaluate $HOME value") + .join(".nym") + .join("service-providers") + .join("network-requester") + } +} + +impl From for ConfigV1_1_19 { + fn from(value: OldConfigV1_1_13) -> Self { + ConfigV1_1_19 { + base: value.base.into(), + network_requester: Default::default(), + network_requester_debug: Default::default(), + } } } diff --git a/service-providers/network-requester/src/config/old_config_v1_1_19.rs b/service-providers/network-requester/src/config/old_config_v1_1_19.rs new file mode 100644 index 0000000000..b7cef30315 --- /dev/null +++ b/service-providers/network-requester/src/config/old_config_v1_1_19.rs @@ -0,0 +1,117 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::config::persistence::NetworkRequesterPaths; +use crate::config::{BaseClientConfig, Config, Debug}; +use nym_client_core::config::disk_persistence::keys_paths::ClientKeysPaths; +use nym_client_core::config::disk_persistence::CommonClientPaths; +use nym_client_core::config::old_config_v1_1_19::ConfigV1_1_19 as BaseConfigV1_1_19; +use nym_client_core::config::Client; +use nym_config::legacy_helpers::nym_config::MigrationNymConfig; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; +use std::time::Duration; + +const DEFAULT_STANDARD_LIST_UPDATE_INTERVAL: Duration = Duration::from_secs(30 * 60); + +#[derive(Debug, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV1_1_19 { + #[serde(flatten)] + pub base: BaseConfigV1_1_19, + + #[serde(default)] + pub network_requester: NetworkRequster, + + #[serde(default)] + pub network_requester_debug: DebugV1_1_19, +} + +impl From for Config { + fn from(value: ConfigV1_1_19) -> Self { + Config { + base: BaseClientConfig { + client: Client { + version: value.base.client.version, + id: value.base.client.id, + disabled_credentials_mode: value.base.client.disabled_credentials_mode, + nyxd_urls: value.base.client.nyxd_urls, + nym_api_urls: value.base.client.nym_api_urls, + gateway_endpoint: value.base.client.gateway_endpoint.into(), + }, + debug: Default::default(), + }, + network_requester: Default::default(), + storage_paths: NetworkRequesterPaths { + common_paths: CommonClientPaths { + keys: ClientKeysPaths { + private_identity_key_file: value.base.client.private_identity_key_file, + public_identity_key_file: value.base.client.public_identity_key_file, + private_encryption_key_file: value.base.client.private_encryption_key_file, + public_encryption_key_file: value.base.client.public_encryption_key_file, + gateway_shared_key_file: value.base.client.gateway_shared_key_file, + ack_key_file: value.base.client.ack_key_file, + }, + credentials_database: value.base.client.database_path, + reply_surb_database: value.base.client.reply_surb_database_path, + }, + allowed_list_location: value.network_requester.allowed_list_location, + unknown_list_location: value.network_requester.unknown_list_location, + }, + network_requester_debug: value.network_requester_debug.into(), + logging: Default::default(), + } + } +} + +impl MigrationNymConfig for ConfigV1_1_19 { + fn default_root_directory() -> PathBuf { + dirs::home_dir() + .expect("Failed to evaluate $HOME value") + .join(".nym") + .join("service-providers") + .join("network-requester") + } +} + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct NetworkRequster { + pub allowed_list_location: PathBuf, + pub unknown_list_location: PathBuf, +} + +impl Default for NetworkRequster { + fn default() -> Self { + // same defaults as we had in <= v1.1.13 + NetworkRequster { + allowed_list_location: ::default_root_directory() + .join("allowed.list"), + unknown_list_location: ::default_root_directory() + .join("unknown.list"), + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct DebugV1_1_19 { + #[serde(with = "humantime_serde")] + pub standard_list_update_interval: Duration, +} + +impl From for Debug { + fn from(value: DebugV1_1_19) -> Self { + Debug { + standard_list_update_interval: value.standard_list_update_interval, + } + } +} + +impl Default for DebugV1_1_19 { + fn default() -> Self { + DebugV1_1_19 { + standard_list_update_interval: DEFAULT_STANDARD_LIST_UPDATE_INTERVAL, + } + } +} diff --git a/service-providers/network-requester/src/config/persistence.rs b/service-providers/network-requester/src/config/persistence.rs index 2720275980..fe289e5c39 100644 --- a/service-providers/network-requester/src/config/persistence.rs +++ b/service-providers/network-requester/src/config/persistence.rs @@ -30,23 +30,4 @@ impl NetworkRequesterPaths { unknown_list_location: base_dir.join(DEFAULT_UNKNOWN_LIST_FILENAME), } } - - pub fn new_legacy>(base_data_directory: P) -> Self { - let base_dir = base_data_directory.as_ref(); - - // that's a bit disgusting... - // go from `$HOME/.nym/service-providers/network-requester//data` - // to `$HOME/.nym/service-providers/network-requester` - let root_dir = base_dir - .parent() - .expect("invalid legacy path configuration") - .parent() - .expect("invalid legacy path configuration"); - - NetworkRequesterPaths { - common_paths: CommonClientPaths::new_default(base_dir), - allowed_list_location: root_dir.join(DEFAULT_ALLOWED_LIST_FILENAME), - unknown_list_location: root_dir.join(DEFAULT_UNKNOWN_LIST_FILENAME), - } - } } diff --git a/service-providers/network-requester/src/config/template.rs b/service-providers/network-requester/src/config/template.rs index 7b5b6ae6da..628a521f9d 100644 --- a/service-providers/network-requester/src/config/template.rs +++ b/service-providers/network-requester/src/config/template.rs @@ -24,48 +24,55 @@ id = '{{ client.id }}' disabled_credentials_mode = {{ client.disabled_credentials_mode }} # Addresses to nyxd validators via which the client can communicate with the chain. -nyxd_urls = [{{#each client.nyxd_urls }} - '{{this}}', -{{/each}}] +nyxd_urls = [ + {{#each client.nyxd_urls }} + '{{this}}', + {{/each}} +] # Addresses to APIs running on validator from which the client gets the view of the network. -nym_api_urls = [{{#each client.nym_api_urls }} - '{{this}}', -{{/each}}] +nym_api_urls = [ + {{#each client.nym_api_urls }} + '{{this}}', + {{/each}} +] + +[storage_paths] # Path to file containing private identity key. -private_identity_key_file = '{{ client.private_identity_key_file }}' +keys.private_identity_key_file = '{{ storage_paths.keys.private_identity_key_file }}' # Path to file containing public identity key. -public_identity_key_file = '{{ client.public_identity_key_file }}' +keys.public_identity_key_file = '{{ storage_paths.keys.public_identity_key_file }}' # Path to file containing private encryption key. -private_encryption_key_file = '{{ client.private_encryption_key_file }}' +keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key_file }}' # Path to file containing public encryption key. -public_encryption_key_file = '{{ client.public_encryption_key_file }}' - -# Path to the database containing bandwidth credentials -database_path = '{{ client.database_path }}' - -# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags. -reply_surb_database_path = '{{ client.reply_surb_database_path }}' - -##### additional client config options ##### +keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}' # A gateway specific, optional, base58 stringified shared key used for # communication with particular gateway. -gateway_shared_key_file = '{{ client.gateway_shared_key_file }}' +keys.gateway_shared_key_file = '{{ storage_paths.keys.gateway_shared_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 = '{{ client.ack_key_file }}' +keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}' -##### advanced configuration options ##### +# Path to the database containing bandwidth credentials +credentials_database = '{{ storage_paths.credentials_database }}' -# Absolute path to the home Nym Clients directory. -nym_root_directory = '{{ client.nym_root_directory }}' +# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags. +reply_surb_database = '{{ storage_paths.reply_surb_database }}' +# Location of the file containing our allow.list +allowed_list_location = '{{ storage_paths.allowed_list_location }}' + +# Location of the file containing our unknown.list +unknown_list_location = '{{ storage_paths.unknown_list_location }}' + + +# DEPRECATED [client.gateway_endpoint] # ID of the gateway from which the client should be fetching messages. gateway_id = '{{ client.gateway_endpoint.gateway_id }}' @@ -76,15 +83,6 @@ gateway_owner = '{{ client.gateway_endpoint.gateway_owner }}' # Address of the gateway listener to which all client requests should be sent. gateway_listener = '{{ client.gateway_endpoint.gateway_listener }}' -##### network requester specific config options ##### - -[network_requester] -# Location of the file containing our allow.list -allowed_list_location = '{{ network_requester.allowed_list_location }}' - -# Location of the file containing our unknown.list -unknown_list_location = '{{ network_requester.unknown_list_location }}' - ##### logging configuration options ##### [logging]