From fad5c9862987fe418c485ceb116719e60c72f68e Mon Sep 17 00:00:00 2001 From: Jedrzej Stuczynski Date: Mon, 3 Feb 2020 15:02:13 +0000 Subject: [PATCH] Initial mix config with working default test --- Cargo.lock | 4 + mixnode/Cargo.toml | 10 ++ mixnode/src/config/mod.rs | 169 +++++++++++++++++++++++++++++++++ mixnode/src/config/template.rs | 48 ++++++++++ mixnode/src/node/runner.rs | 1 - 5 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 mixnode/src/config/mod.rs create mode 100644 mixnode/src/config/template.rs diff --git a/Cargo.lock b/Cargo.lock index 4af4244bdd..9ec38d5c16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1448,13 +1448,17 @@ dependencies = [ "bs58", "built", "clap", + "config", "curve25519-dalek", "directory-client", + "dirs", "dotenv", "futures 0.3.1", "log", "pretty_env_logger", + "serde", "sphinx", + "tempfile", "tokio 0.2.10", ] diff --git a/mixnode/Cargo.toml b/mixnode/Cargo.toml index 32a9e1aeeb..26ccefad3d 100644 --- a/mixnode/Cargo.toml +++ b/mixnode/Cargo.toml @@ -11,14 +11,17 @@ edition = "2018" bs58 = "0.3.0" clap = "2.33.0" curve25519-dalek = "1.2.3" +dirs = "2.0.2" dotenv = "0.15.0" futures = "0.3.1" log = "0.4" pretty_env_logger = "0.3" +serde = { version = "1.0.104", features = ["derive"] } tokio = { version = "0.2", features = ["full"] } ## internal addressing = {path = "../common/addressing" } +config = {path = "../common/config"} directory-client = { path = "../common/clients/directory-client" } ## will be moved to proper dependencies once released @@ -26,3 +29,10 @@ sphinx = { git = "https://github.com/nymtech/sphinx", rev="5862939c52e4dd76f8368 [build-dependencies] built = "0.3.2" + +[dev-dependencies] +tempfile = "3.1.0" + +[features] +qa = [] +local = [] \ No newline at end of file diff --git a/mixnode/src/config/mod.rs b/mixnode/src/config/mod.rs new file mode 100644 index 0000000000..35fefb5473 --- /dev/null +++ b/mixnode/src/config/mod.rs @@ -0,0 +1,169 @@ +use crate::config::template::config_template; +use config::NymConfig; +use serde::{Deserialize, Deserializer, Serialize}; +use std::path::PathBuf; + +mod template; + +#[derive(Debug, Default, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Config { + mixnode: MixNode, + + #[serde(default)] + logging: Logging, + #[serde(default)] + debug: Debug, +} + +impl NymConfig for Config { + fn template() -> &'static str { + config_template() + } + + fn config_file_name() -> String { + "config.toml".to_string() + } + + fn default_root_directory() -> PathBuf { + dirs::home_dir() + .expect("Failed to evaluate $HOME value") + .join(".nym") + .join("mixnodes") + } + + fn root_directory(&self) -> PathBuf { + self.mixnode.nym_root_directory.clone() + } + + fn config_directory(&self) -> PathBuf { + self.mixnode + .nym_root_directory + .join(&self.mixnode.id) + .join("config") + } + + fn data_directory(&self) -> PathBuf { + self.mixnode + .nym_root_directory + .join(&self.mixnode.id) + .join("data") + } +} + +impl Config { + pub fn new>(id: S) -> Self { + Config::default().with_id(id) + } + + // builder methods + pub fn with_id>(mut self, id: S) -> Self { + let id = id.into(); + if self + .mixnode + .private_identity_key_file + .as_os_str() + .is_empty() + { + self.mixnode.private_identity_key_file = + self::MixNode::default_private_identity_key_file(&id); + } + if self.mixnode.public_identity_key_file.as_os_str().is_empty() { + self.mixnode.public_identity_key_file = + self::MixNode::default_public_identity_key_file(&id); + } + self.mixnode.id = id; + self + } +} + +#[derive(Debug, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct MixNode { + /// ID specifies the human readable ID of this particular mixnode. + id: String, + + /// URL to the directory server. + directory_server: String, + + /// Path to file containing private identity key. + private_identity_key_file: PathBuf, + + /// Path to file containing public identity key. + public_identity_key_file: PathBuf, + + /// nym_home_directory specifies absolute path to the home nym MixNodes directory. + /// It is expected to use default value and hence .toml file should not redefine this field. + nym_root_directory: PathBuf, +} + +impl MixNode { + fn default_directory_server() -> String { + #[cfg(feature = "qa")] + return "https://qa-directory.nymtech.net".to_string(); + #[cfg(feature = "local")] + return "http://localhost:8080".to_string(); + + "https://directory.nymtech.net".to_string() + } + + fn default_private_identity_key_file(id: &str) -> PathBuf { + Config::default_data_directory(Some(id)).join("private_identity.pem") + } + + fn default_public_identity_key_file(id: &str) -> PathBuf { + Config::default_data_directory(Some(id)).join("public_identity.pem") + } +} + +impl Default for MixNode { + fn default() -> Self { + MixNode { + id: "".to_string(), + directory_server: Self::default_directory_server(), + private_identity_key_file: Default::default(), + public_identity_key_file: Default::default(), + nym_root_directory: Config::default_root_directory(), + } + } +} + +#[derive(Debug, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Logging {} + +impl Default for Logging { + fn default() -> Self { + Logging {} + } +} + +#[derive(Debug, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Debug {} + +impl Default for Debug { + fn default() -> Self { + Debug {} + } +} + +#[cfg(test)] +mod mixnode_config { + use super::*; + + #[test] + fn after_saving_default_config_the_loaded_one_is_identical() { + // need to figure out how to do something similar but without touching the disk + // or the file system at all... + let temp_location = tempfile::tempdir().unwrap().path().join("config.toml"); + let default_config = Config::default().with_id("foomp".to_string()); + default_config + .save_to_file(Some(temp_location.clone())) + .unwrap(); + + let loaded_config = Config::load_from_file(Some(temp_location), None).unwrap(); + + assert_eq!(default_config, loaded_config); + } +} diff --git a/mixnode/src/config/template.rs b/mixnode/src/config/template.rs new file mode 100644 index 0000000000..d5170ba6fc --- /dev/null +++ b/mixnode/src/config/template.rs @@ -0,0 +1,48 @@ +pub(crate) fn config_template() -> &'static 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. + // Note: any changes to the template must be reflected in the appropriate structs in mod.rs. + r#" +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +##### main base mixnode config options ##### + +[mixnode] +# Human readable ID of this particular mixnode. +id = "{{ mixnode.id }}" + +# URL to the directory server. +directory_server = "{{ mixnode.directory_server }}" + +# Path to file containing private identity key. +private_identity_key_file = "{{ mixnode.private_identity_key_file }}" + +# Path to file containing public identity key. +public_identity_key_file = "{{ mixnode.public_identity_key_file }}" + +##### additional mixnode config options ##### + + +##### advanced configuration options ##### + +# Absolute path to the home Nym Clients directory. +nym_root_directory = "{{ mixnode.nym_root_directory }}" + + +##### logging configuration options ##### + +[logging] + +# TODO + + +##### debug configuration options ##### +# The following options should not be modified unless you know EXACTLY what you are doing +# as if set incorrectly, they may impact your anonymity. + +[debug] + +"# +} diff --git a/mixnode/src/node/runner.rs b/mixnode/src/node/runner.rs index 669b8d3c58..eec5496238 100644 --- a/mixnode/src/node/runner.rs +++ b/mixnode/src/node/runner.rs @@ -1,4 +1,3 @@ -use crate::banner; use crate::node; use crate::node::MixNode; use clap::ArgMatches;