Initial fields for the client config

This commit is contained in:
Jedrzej Stuczynski
2020-01-29 16:04:57 +00:00
parent 00dc25a94f
commit 713a7a6fe8
4 changed files with 273 additions and 72 deletions
+5 -1
View File
@@ -18,7 +18,6 @@ curve25519-dalek = "1.2.3"
dirs = "2.0.2"
dotenv = "0.15.0"
futures = "0.3.1"
handlebars = "3.0.1"
log = "0.4"
pem = "0.7.0"
pretty_env_logger = "0.3"
@@ -30,6 +29,7 @@ tungstenite = "0.9.2"
## internal
addressing = {path = "../common/addressing" }
config = {path = "../common/config"}
crypto = {path = "../common/crypto"}
directory-client = { path = "../common/clients/directory-client" }
healthcheck = { path = "../common/healthcheck" }
@@ -48,3 +48,7 @@ tokio-tungstenite = { git = "https://github.com/snapview/tokio-tungstenite", rev
[build-dependencies]
built = "0.3.2"
[features]
qa = []
local = []
+3
View File
@@ -8,6 +8,7 @@ use directory_client::presence::Topology;
use futures::channel::mpsc;
use futures::join;
use log::*;
use serde::{Deserialize, Serialize};
use sfw_provider_requests::AuthToken;
use sphinx::route::Destination;
use std::marker::PhantomData;
@@ -31,6 +32,8 @@ const FETCH_MESSAGES_DELAY: f64 = 1.0; // seconds;
const TOPOLOGY_REFRESH_RATE: f64 = 10.0; // seconds
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub enum SocketType {
TCP,
WebSocket,
+194 -33
View File
@@ -1,82 +1,243 @@
use crate::config::persistance::pathfinder::ClientPathfinder;
use crate::client::SocketType;
use crate::config::template::config_template;
use config::NymConfig;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
pub mod persistance;
mod template;
#[derive(Serialize, Deserialize)]
// all of the below are defined in seconds
const DEFAULT_LOOP_COVER_SENDING_AVERAGE_DELAY: f64 = 1.0;
const DEFAULT_MESSAGE_SENDING_AVERAGE_DELAY: f64 = 0.5;
const DEFAULT_AVERAGE_PACKET_DELAY: f64 = 0.2;
const DEFAULT_FETCH_MESSAGES_DELAY: f64 = 1.0;
const DEFAULT_TOPOLOGY_REFRESH_RATE: f64 = 10.0;
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
client: Client,
socket: Socket,
#[serde(default)]
logging: Logging,
#[serde(default)]
debug: Debug,
}
impl Default for Config {
fn default() -> Self {
unimplemented!()
impl NymConfig for Config {
fn template() -> &'static str {
config_template()
}
fn default_root_directory() -> PathBuf {
dirs::home_dir()
.expect("Failed to evaluate $HOME value")
.join(".nym")
.join("clients")
}
fn root_directory(&self) -> PathBuf {
self.client.nym_root_directory.clone()
}
fn config_directory(&self) -> PathBuf {
self.client
.nym_root_directory
.join(&self.client.id)
.join("config")
}
fn data_directory(&self) -> PathBuf {
self.client
.nym_root_directory
.join(&self.client.id)
.join("data")
}
}
#[derive(Serialize, Deserialize)]
pub struct Client {
// nym_home_directory specifies absolute path to the home nym Clients directory.
// It is expected to use default value and hence .toml file should not redefine this field.
nym_home_directory: String,
impl Config {
pub fn new(id: String) -> Self {
Config::default().with_id(id)
}
// ID specifies the human readable ID of this particular client.
// If not provided a pseudorandom id will be generated instead.
pub fn with_id(mut self, id: String) -> Self {
if self.client.private_identity_key_file.as_os_str().is_empty() {
self.client.private_identity_key_file =
self::Client::default_private_identity_key_file(&id);
}
if self.client.public_identity_key_file.as_os_str().is_empty() {
self.client.public_identity_key_file =
self::Client::default_public_identity_key_file(&id);
}
self.client.id = id;
self
}
pub fn with_provider_id(mut self, id: String) -> Self {
self.client.provider_id = id;
self
}
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Client {
/// ID specifies the human readable ID of this particular client.
id: String,
// URL to the directory server.
/// URL to the directory server.
directory_server: String,
// Path to file containing private identity key.
/// Path to file containing private identity key.
private_identity_key_file: PathBuf,
// Path to file containing public identity key.
/// Path to file containing public identity key.
public_identity_key_file: PathBuf,
// mix_apps_directory specifies directory for mixapps, such as a chat client,
// to store their app-specific data.
mix_apps_directory: String,
// provider_id specifies ID of the provider to which the client should send messages.
// If initially omitted, a random provider will be chosen from the available topology.
/// provider_id specifies ID of the provider to which the client should send messages.
/// If initially omitted, a random provider will be chosen from the available topology.
provider_id: String,
/// nym_home_directory specifies absolute path to the home nym Clients directory.
/// It is expected to use default value and hence .toml file should not redefine this field.
nym_root_directory: PathBuf,
}
impl Default for Client {
fn default() -> Self {
unimplemented!()
// there must be explicit checks for whether id is not empty later
Client {
id: "".to_string(),
directory_server: Self::default_directory_server(),
private_identity_key_file: Default::default(),
public_identity_key_file: Default::default(),
provider_id: "".to_string(),
nym_root_directory: Config::default_root_directory(),
}
}
}
impl Client {
fn new() -> Self {
Default::default()
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 with_id(mut self, id: String) -> Self {
self.id = id;
self
fn default_private_identity_key_file(id: &str) -> PathBuf {
Config::default_data_directory()
.join(id)
.join("private_identity.pem")
}
fn with_pathfinder(mut self, pathfinder: ClientPathfinder) -> Self {
// pub config_dir: PathBuf,
// pub private_mix_key: PathBuf,
// pub public_mix_key: PathBuf,
self
fn default_public_identity_key_file(id: &str) -> PathBuf {
Config::default_data_directory()
.join(id)
.join("public_identity.pem")
}
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Socket {
socket_type: SocketType,
listening_port: u64,
}
impl Default for Socket {
fn default() -> Self {
Socket {
socket_type: SocketType::None,
listening_port: 0,
}
}
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Logging {}
impl Default for Logging {
fn default() -> Self {
unimplemented!()
Logging {}
}
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Debug {
/// The parameter of Poisson distribution determining how long, on average,
/// sent packet is going to be delayed at any given mix node.
/// So for a packet going through three mix nodes, on average, it will take three times this value
/// until the packet reaches its destination.
/// The provided value is interpreted as seconds.
average_packet_delay: f64,
/// The parameter of Poisson distribution determining how long, on average,
/// it is going to take for another loop cover traffic message to be sent.
/// If set to a negative value, the loop cover traffic stream will be disabled.
/// The provided value is interpreted as seconds.
loop_cover_traffic_average_delay: f64,
/// The uniform delay every which clients are querying the providers for received packets.
/// If set to a negative value, client will never try to fetch their messages.
/// The provided value is interpreted as seconds.
fetch_message_delay: f64,
/// The parameter of Poisson distribution determining how long, on average,
/// it is going to take another 'real traffic stream' message to be sent.
/// If no real packets are available and cover traffic is enabled,
/// a loop cover message is sent instead in order to preserve the rate.
/// If set to a negative value, client will never try to send real traffic data.
/// The provided value is interpreted as seconds.
message_sending_average_delay: f64,
/// Whether loop cover messages should be sent to respect message_sending_rate.
/// In the case of it being disabled and not having enough real traffic
/// waiting to be sent the actual sending rate is going be lower than the desired value
/// thus decreasing the anonymity.
rate_compliant_cover_messages_disabled: bool,
/// The uniform delay every which clients are querying the directory server
/// to try to obtain a compatible network topology to send sphinx packets through.
/// If set to a negative value, client will never try to refresh its topology,
/// meaning it will always try to use whatever it obtained on startup.
/// The provided value is interpreted as seconds.
topology_refresh_rate: f64,
}
impl Default for Debug {
fn default() -> Self {
Debug {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_SENDING_AVERAGE_DELAY,
fetch_message_delay: DEFAULT_FETCH_MESSAGES_DELAY,
message_sending_average_delay: DEFAULT_MESSAGE_SENDING_AVERAGE_DELAY,
rate_compliant_cover_messages_disabled: false,
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
}
}
}
#[cfg(test)]
mod client_config {
use super::*;
#[test]
fn after_saving_default_config_the_loaded_one_is_identical() {
let temp_location = std::env::temp_dir().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)).unwrap();
assert_eq!(default_config, loaded_config);
}
}
+71 -38
View File
@@ -1,7 +1,4 @@
use super::Config;
use handlebars::{Handlebars, TemplateRenderError};
fn config_template() -> &'static str {
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.
@@ -20,49 +17,85 @@ id = "{{ client.id }}"
directory_server = "{{ client.directory_server }}"
# Path to file containing private identity key.
private_identity_key_file = "{{ client.private_identity_key }}"
private_identity_key_file = "{{ client.private_identity_key_file }}"
# Path to file containing public identity key.
public_identity_key_file = "{{ client.public_identity_key }}"
public_identity_key_file = "{{ client.public_identity_key_file }}"
##### additional client config options #####
# ID of the provider to which the client should send messages.
# ID of the provider from which the client should be fetching messages.
provider_id = "{{ client.provider_id }}"
# directory for mixapps, such as a chat client, to store their app-specific data.
mixapps_directory = "{{ client.mix_apps_directory }}"
##### advanced configuration options #####
# Absolute path to the home Nym Clients directory.
nym_home_directory = "{{ client.home_directory }}"
nym_root_directory = "{{ client.nym_root_directory }}"
##### socket config options #####
[socket]
# allowed values are 'TCP', 'WebSocket' or 'None'
socket_type = "{{ socket.socket_type }}"
# if applicable (for the case of 'TCP' or 'WebSocket'), the port on which the client
# will be listening for incoming requests
listening_port = {{ socket.listening_port }}
##### 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]
# The parameter of Poisson distribution determining how long, on average,
# sent packet is going to be delayed at any given mix node.
# So for a packet going through three mix nodes, on average, it will take three times this value
# until the packet reaches its destination.
# The provided value is interpreted as seconds.
average_packet_delay = {{ debug.average_packet_delay }}
# The parameter of Poisson distribution determining how long, on average,
# it is going to take for another loop cover traffic message to be sent.
# If set to a negative value, the loop cover traffic stream will be disabled.
# The provided value is interpreted as seconds.
loop_cover_traffic_average_delay = {{ debug.loop_cover_traffic_average_delay }}
# The uniform delay every which clients are querying the providers for received packets.
# If set to a negative value, client will never try to fetch their messages.
# The provided value is interpreted as seconds.
fetch_message_delay = {{ debug.fetch_message_delay }}
# The parameter of Poisson distribution determining how long, on average,
# it is going to take another 'real traffic stream' message to be sent.
# If no real packets are available and cover traffic is enabled,
# a loop cover message is sent instead in order to preserve the rate.
# If set to a negative value, client will never try to send real traffic data.
# The provided value is interpreted as seconds.
message_sending_average_delay = {{ debug.message_sending_average_delay }}
# Whether loop cover messages should be sent to respect message_sending_rate.
# In the case of it being disabled and not having enough real traffic
# waiting to be sent the actual sending rate is going be lower than the desired value
# thus decreasing the anonymity.
rate_compliant_cover_messages_disabled = {{ debug.rate_compliant_cover_messages_disabled }}
# The uniform delay every which clients are querying the directory server
# to try to obtain a compatible network topology to send sphinx packets through.
# If set to a negative value, client will never try to refresh its topology,
# meaning it will always try to use whatever it obtained on startup.
# The provided value is interpreted as seconds.
topology_refresh_rate = {{ debug.topology_refresh_rate }}
"#
}
fn render_template(config: &Config) -> Result<String, TemplateRenderError> {
let reg = Handlebars::new();
reg.render_template(config_template(), &config)
}
#[cfg(test)]
mod config_template {
use super::*;
#[test]
fn it_works_for_default_config() {
render_template(&Default::default()).unwrap();
}
#[test]
fn it_works_for_dummy_config() {
let dummy_cfg = Config {
client: crate::config::Client {
id: "foomp".to_string(),
},
};
let render = render_template(&dummy_cfg).unwrap();
println!("{}", render);
}
}