Feature/socks client config (#316)
* Made base client_core config * Updated socks5 config with mandatory provider field
This commit is contained in:
committed by
GitHub
parent
9efc195046
commit
993d3d10a1
Generated
+20
-9
@@ -443,7 +443,7 @@ dependencies = [
|
||||
"config",
|
||||
"crypto",
|
||||
"directory-client",
|
||||
"dirs",
|
||||
"dirs 2.0.2",
|
||||
"futures 0.3.4",
|
||||
"gateway-client",
|
||||
"gateway-requests",
|
||||
@@ -721,12 +721,20 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.4"
|
||||
name = "dirs"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
|
||||
checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi 0.3.8",
|
||||
@@ -1639,7 +1647,7 @@ dependencies = [
|
||||
"config",
|
||||
"crypto",
|
||||
"directory-client",
|
||||
"dirs",
|
||||
"dirs 3.0.1",
|
||||
"dotenv",
|
||||
"futures 0.3.4",
|
||||
"gateway-client",
|
||||
@@ -1687,7 +1695,7 @@ dependencies = [
|
||||
"config",
|
||||
"crypto",
|
||||
"directory-client",
|
||||
"dirs",
|
||||
"dirs 2.0.2",
|
||||
"dotenv",
|
||||
"futures 0.3.4",
|
||||
"gateway-requests",
|
||||
@@ -1717,7 +1725,7 @@ dependencies = [
|
||||
"crypto",
|
||||
"curve25519-dalek",
|
||||
"directory-client",
|
||||
"dirs",
|
||||
"dirs 2.0.2",
|
||||
"dotenv",
|
||||
"futures 0.3.4",
|
||||
"log 0.4.8",
|
||||
@@ -1742,7 +1750,7 @@ dependencies = [
|
||||
"byteorder",
|
||||
"clap",
|
||||
"config",
|
||||
"dirs",
|
||||
"dirs 2.0.2",
|
||||
"dotenv",
|
||||
"futures 0.3.4",
|
||||
"iron",
|
||||
@@ -2856,6 +2864,7 @@ dependencies = [
|
||||
"config",
|
||||
"crypto",
|
||||
"directory-client",
|
||||
"dirs 3.0.1",
|
||||
"dotenv",
|
||||
"futures 0.3.4",
|
||||
"gateway-client",
|
||||
@@ -2865,8 +2874,10 @@ dependencies = [
|
||||
"pin-project",
|
||||
"pretty_env_logger",
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"simple-socks5-requests",
|
||||
"snafu",
|
||||
"tempfile",
|
||||
"tokio 0.2.22",
|
||||
"topology",
|
||||
"url 2.1.1",
|
||||
|
||||
@@ -12,17 +12,15 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::config::template::config_template;
|
||||
use config::NymConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::PathBuf;
|
||||
use std::time;
|
||||
|
||||
pub mod persistence;
|
||||
mod template;
|
||||
|
||||
// 'CLIENT'
|
||||
const DEFAULT_LISTENING_PORT: u16 = 1977;
|
||||
const DEFAULT_DIRECTORY_SERVER: &str = "https://directory.nymtech.net";
|
||||
// 'DEBUG'
|
||||
// where applicable, the below are defined in milliseconds
|
||||
@@ -40,29 +38,10 @@ const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: u64 = 5_000; // 5s
|
||||
|
||||
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: u64 = 1_500; // 1.5s
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize, Clone, Copy)]
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub enum SocketType {
|
||||
WebSocket,
|
||||
None,
|
||||
}
|
||||
|
||||
impl SocketType {
|
||||
pub fn from_string<S: Into<String>>(val: S) -> Self {
|
||||
let mut upper = val.into();
|
||||
upper.make_ascii_uppercase();
|
||||
match upper.as_ref() {
|
||||
"WEBSOCKET" | "WS" => SocketType::WebSocket,
|
||||
_ => SocketType::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
client: Client,
|
||||
socket: Socket,
|
||||
pub struct Config<T> {
|
||||
client: Client<T>,
|
||||
|
||||
#[serde(default)]
|
||||
logging: Logging,
|
||||
@@ -70,58 +49,24 @@ pub struct Config {
|
||||
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("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")
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
impl<T: NymConfig> Config<T> {
|
||||
pub fn new<S: Into<String>>(id: S) -> Self {
|
||||
Config::default().with_id(id)
|
||||
let mut cfg = Config::default();
|
||||
cfg.with_id(id);
|
||||
cfg
|
||||
}
|
||||
|
||||
// builder methods
|
||||
pub fn with_id<S: Into<String>>(mut self, id: S) -> Self {
|
||||
pub fn with_id<S: Into<String>>(&mut self, id: S) {
|
||||
let id = id.into();
|
||||
|
||||
// identity key setting
|
||||
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);
|
||||
self::Client::<T>::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::<T>::default_public_identity_key_file(&id);
|
||||
}
|
||||
|
||||
// encryption key setting
|
||||
@@ -132,7 +77,7 @@ impl Config {
|
||||
.is_empty()
|
||||
{
|
||||
self.client.private_encryption_key_file =
|
||||
self::Client::default_private_encryption_key_file(&id);
|
||||
self::Client::<T>::default_private_encryption_key_file(&id);
|
||||
}
|
||||
if self
|
||||
.client
|
||||
@@ -141,18 +86,18 @@ impl Config {
|
||||
.is_empty()
|
||||
{
|
||||
self.client.public_encryption_key_file =
|
||||
self::Client::default_public_encryption_key_file(&id);
|
||||
self::Client::<T>::default_public_encryption_key_file(&id);
|
||||
}
|
||||
|
||||
// shared gateway key setting
|
||||
if self.client.gateway_shared_key_file.as_os_str().is_empty() {
|
||||
self.client.gateway_shared_key_file =
|
||||
self::Client::default_gateway_shared_key_file(&id);
|
||||
self::Client::<T>::default_gateway_shared_key_file(&id);
|
||||
}
|
||||
|
||||
// ack key setting
|
||||
if self.client.ack_key_file.as_os_str().is_empty() {
|
||||
self.client.ack_key_file = self::Client::default_ack_key_file(&id);
|
||||
self.client.ack_key_file = self::Client::<T>::default_ack_key_file(&id);
|
||||
}
|
||||
|
||||
if self
|
||||
@@ -162,48 +107,36 @@ impl Config {
|
||||
.is_empty()
|
||||
{
|
||||
self.client.reply_encryption_key_store_path =
|
||||
self::Client::default_reply_encryption_key_store_path(&id);
|
||||
self::Client::<T>::default_reply_encryption_key_store_path(&id);
|
||||
}
|
||||
|
||||
self.client.id = id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_gateway_id<S: Into<String>>(mut self, id: S) -> Self {
|
||||
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
|
||||
self.client.gateway_id = id.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_gateway_listener<S: Into<String>>(mut self, gateway_listener: S) -> Self {
|
||||
pub fn with_gateway_listener<S: Into<String>>(&mut self, gateway_listener: S) {
|
||||
self.client.gateway_listener = gateway_listener.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_custom_directory<S: Into<String>>(mut self, directory_server: S) -> Self {
|
||||
pub fn with_custom_directory<S: Into<String>>(&mut self, directory_server: S) {
|
||||
self.client.directory_server = directory_server.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_socket(mut self, socket_type: SocketType) -> Self {
|
||||
self.socket.socket_type = socket_type;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_port(mut self, port: u16) -> Self {
|
||||
self.socket.listening_port = port;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_high_default_traffic_volume(mut self) -> Self {
|
||||
pub fn set_high_default_traffic_volume(&mut self) {
|
||||
self.debug.average_packet_delay = 10;
|
||||
self.debug.loop_cover_traffic_average_delay = 20; // 50 cover messages / s
|
||||
self.debug.message_sending_average_delay = 5; // 200 "real" messages / s
|
||||
self
|
||||
}
|
||||
|
||||
// getters
|
||||
pub fn get_config_file_save_location(&self) -> PathBuf {
|
||||
self.config_directory().join(Self::config_file_name())
|
||||
pub fn get_id(&self) -> String {
|
||||
self.client.id.clone()
|
||||
}
|
||||
|
||||
pub fn get_nym_root_directory(&self) -> PathBuf {
|
||||
self.client.nym_root_directory.clone()
|
||||
}
|
||||
|
||||
pub fn get_private_identity_key_file(&self) -> PathBuf {
|
||||
@@ -246,14 +179,6 @@ impl Config {
|
||||
self.client.gateway_listener.clone()
|
||||
}
|
||||
|
||||
pub fn get_socket_type(&self) -> SocketType {
|
||||
self.socket.socket_type
|
||||
}
|
||||
|
||||
pub fn get_listening_port(&self) -> u16 {
|
||||
self.socket.listening_port
|
||||
}
|
||||
|
||||
// Debug getters
|
||||
pub fn get_average_packet_delay(&self) -> time::Duration {
|
||||
time::Duration::from_millis(self.debug.average_packet_delay)
|
||||
@@ -292,9 +217,19 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NymConfig> Default for Config<T> {
|
||||
fn default() -> Self {
|
||||
Config {
|
||||
client: Client::<T>::default(),
|
||||
logging: Default::default(),
|
||||
debug: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Client {
|
||||
pub struct Client<T> {
|
||||
/// ID specifies the human readable ID of this particular client.
|
||||
id: String,
|
||||
|
||||
@@ -335,9 +270,12 @@ 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_root_directory: PathBuf,
|
||||
|
||||
#[serde(skip)]
|
||||
super_struct: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl Default for Client {
|
||||
impl<T: NymConfig> Default for Client<T> {
|
||||
fn default() -> Self {
|
||||
// there must be explicit checks for whether id is not empty later
|
||||
Client {
|
||||
@@ -352,54 +290,39 @@ impl Default for Client {
|
||||
reply_encryption_key_store_path: Default::default(),
|
||||
gateway_id: "".to_string(),
|
||||
gateway_listener: "".to_string(),
|
||||
nym_root_directory: Config::default_root_directory(),
|
||||
nym_root_directory: T::default_root_directory(),
|
||||
super_struct: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
impl<T: NymConfig> Client<T> {
|
||||
fn default_private_identity_key_file(id: &str) -> PathBuf {
|
||||
Config::default_data_directory(Some(id)).join("private_identity.pem")
|
||||
T::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")
|
||||
T::default_data_directory(Some(id)).join("public_identity.pem")
|
||||
}
|
||||
|
||||
fn default_private_encryption_key_file(id: &str) -> PathBuf {
|
||||
Config::default_data_directory(Some(id)).join("private_encryption.pem")
|
||||
T::default_data_directory(Some(id)).join("private_encryption.pem")
|
||||
}
|
||||
|
||||
fn default_public_encryption_key_file(id: &str) -> PathBuf {
|
||||
Config::default_data_directory(Some(id)).join("public_encryption.pem")
|
||||
T::default_data_directory(Some(id)).join("public_encryption.pem")
|
||||
}
|
||||
|
||||
fn default_gateway_shared_key_file(id: &str) -> PathBuf {
|
||||
Config::default_data_directory(Some(id)).join("gateway_shared.pem")
|
||||
T::default_data_directory(Some(id)).join("gateway_shared.pem")
|
||||
}
|
||||
|
||||
fn default_ack_key_file(id: &str) -> PathBuf {
|
||||
Config::default_data_directory(Some(id)).join("ack_key.pem")
|
||||
T::default_data_directory(Some(id)).join("ack_key.pem")
|
||||
}
|
||||
|
||||
fn default_reply_encryption_key_store_path(id: &str) -> PathBuf {
|
||||
Config::default_data_directory(Some(id)).join("reply_key_store")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socket {
|
||||
socket_type: SocketType,
|
||||
listening_port: u16,
|
||||
}
|
||||
|
||||
impl Default for Socket {
|
||||
fn default() -> Self {
|
||||
Socket {
|
||||
socket_type: SocketType::WebSocket,
|
||||
listening_port: DEFAULT_LISTENING_PORT,
|
||||
}
|
||||
T::default_data_directory(Some(id)).join("reply_key_store")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,23 +408,3 @@ impl Default for Debug {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod client_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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::config::Config;
|
||||
use config::NymConfig;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -39,7 +40,7 @@ impl ClientKeyPathfinder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_config(config: &Config) -> Self {
|
||||
pub fn new_from_config<T: NymConfig>(config: &Config<T>) -> Self {
|
||||
ClientKeyPathfinder {
|
||||
identity_private_key: config.get_private_identity_key_file(),
|
||||
identity_public_key: config.get_public_identity_key_file(),
|
||||
|
||||
@@ -20,7 +20,7 @@ futures = "0.3" # bunch of futures stuff, however, now that I think about it, it
|
||||
url = "2.1" # I think we should just replace it with String
|
||||
|
||||
clap = "2.33.0" # for the command line arguments
|
||||
dirs = "2.0.2" # for determining default store directories in config
|
||||
dirs = "3.0" # for determining default store directories in config
|
||||
dotenv = "0.15.0" # for obtaining environmental variables (only used for RUST_LOG for time being)
|
||||
log = "0.4" # self explanatory
|
||||
pretty_env_logger = "0.3" # for formatting log messages
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::client::config::template::config_template;
|
||||
use client_core::config::Config as BaseConfig;
|
||||
use config::NymConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
mod template;
|
||||
|
||||
const DEFAULT_LISTENING_PORT: u16 = 1977;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize, Clone, Copy)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub enum SocketType {
|
||||
WebSocket,
|
||||
None,
|
||||
}
|
||||
|
||||
impl SocketType {
|
||||
pub fn from_string<S: Into<String>>(val: S) -> Self {
|
||||
let mut upper = val.into();
|
||||
upper.make_ascii_uppercase();
|
||||
match upper.as_ref() {
|
||||
"WEBSOCKET" | "WS" => SocketType::WebSocket,
|
||||
_ => SocketType::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
#[serde(flatten)]
|
||||
base: BaseConfig<Config>,
|
||||
|
||||
socket: Socket,
|
||||
}
|
||||
|
||||
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("clients")
|
||||
}
|
||||
|
||||
fn root_directory(&self) -> PathBuf {
|
||||
self.base.get_nym_root_directory()
|
||||
}
|
||||
|
||||
fn config_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(self.base.get_id())
|
||||
.join("config")
|
||||
}
|
||||
|
||||
fn data_directory(&self) -> PathBuf {
|
||||
self.root_directory().join(self.base.get_id()).join("data")
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new<S: Into<String>>(id: S) -> Self {
|
||||
Config {
|
||||
base: BaseConfig::new(id),
|
||||
socket: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_socket(mut self, socket_type: SocketType) -> Self {
|
||||
self.socket.socket_type = socket_type;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_port(mut self, port: u16) -> Self {
|
||||
self.socket.listening_port = port;
|
||||
self
|
||||
}
|
||||
|
||||
// getters
|
||||
pub fn get_config_file_save_location(&self) -> PathBuf {
|
||||
self.config_directory().join(Self::config_file_name())
|
||||
}
|
||||
|
||||
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_socket_type(&self) -> SocketType {
|
||||
self.socket.socket_type
|
||||
}
|
||||
|
||||
pub fn get_listening_port(&self) -> u16 {
|
||||
self.socket.listening_port
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socket {
|
||||
socket_type: SocketType,
|
||||
listening_port: u16,
|
||||
}
|
||||
|
||||
impl Default for Socket {
|
||||
fn default() -> Self {
|
||||
Socket {
|
||||
socket_type: SocketType::WebSocket,
|
||||
listening_port: DEFAULT_LISTENING_PORT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod client_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::new("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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
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 client config options #####
|
||||
|
||||
[client]
|
||||
# Human readable ID of this particular client.
|
||||
id = '{{ client.id }}'
|
||||
|
||||
# URL to the directory server.
|
||||
directory_server = '{{ client.directory_server }}'
|
||||
|
||||
# Path to file containing 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_file }}'
|
||||
|
||||
# Path to file containing private encryption key.
|
||||
private_encryption_key_file = '{{ client.private_encryption_key_file }}'
|
||||
|
||||
# Path to file containing public encryption key.
|
||||
public_encryption_key_file = '{{ client.public_encryption_key_file }}'
|
||||
|
||||
# Full path to file containing reply encryption keys of all reply-SURBs we have ever
|
||||
# sent but not received back.
|
||||
reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
|
||||
|
||||
##### additional client config options #####
|
||||
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ client.gateway_id }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ client.gateway_listener }}'
|
||||
|
||||
# A gateway specific, optional, base58 stringified shared key used for
|
||||
# communication with particular gateway.
|
||||
gateway_shared_key_file = '{{ client.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 }}'
|
||||
|
||||
##### advanced configuration options #####
|
||||
|
||||
# Absolute path to the home Nym Clients directory.
|
||||
nym_root_directory = '{{ client.nym_root_directory }}'
|
||||
|
||||
|
||||
##### socket config options #####
|
||||
|
||||
[socket]
|
||||
|
||||
# allowed values are 'WebSocket' or 'None'
|
||||
socket_type = '{{ socket.socket_type }}'
|
||||
|
||||
# if applicable (for the case of '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]
|
||||
|
||||
average_packet_delay = {{ debug.average_packet_delay }}
|
||||
average_ack_delay = {{ debug.average_ack_delay }}
|
||||
loop_cover_traffic_average_delay = {{ debug.loop_cover_traffic_average_delay }}
|
||||
message_sending_average_delay = {{ debug.message_sending_average_delay }}
|
||||
|
||||
"#
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::client::config::{Config, SocketType};
|
||||
use crate::websocket;
|
||||
use client_core::client::cover_traffic_stream::LoopCoverTrafficStream;
|
||||
use client_core::client::inbound_messages::{
|
||||
@@ -32,7 +33,6 @@ use client_core::client::topology_control::{
|
||||
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
|
||||
};
|
||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use client_core::config::{Config, SocketType};
|
||||
use crypto::asymmetric::identity;
|
||||
use futures::channel::mpsc;
|
||||
use gateway_client::{
|
||||
@@ -46,6 +46,8 @@ use nymsphinx::anonymous_replies::ReplySURB;
|
||||
use nymsphinx::receiver::ReconstructedMessage;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
pub(crate) mod config;
|
||||
|
||||
pub struct NymClient {
|
||||
/// Client configuration options, including, among other things, packet sending rates,
|
||||
/// key filepaths, etc.
|
||||
@@ -71,7 +73,7 @@ pub struct NymClient {
|
||||
|
||||
impl NymClient {
|
||||
pub fn new(config: Config) -> Self {
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(&config);
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
let key_manager = KeyManager::load_keys(&pathfinder).expect("failed to load stored keys");
|
||||
|
||||
NymClient {
|
||||
@@ -89,7 +91,7 @@ impl NymClient {
|
||||
self.key_manager.encryption_keypair().public_key().clone(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(self.config.get_gateway_id()).unwrap(),
|
||||
NodeIdentity::from_base58_string(self.config.get_base().get_gateway_id()).unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -107,9 +109,11 @@ impl NymClient {
|
||||
.enter(|| {
|
||||
LoopCoverTrafficStream::new(
|
||||
self.key_manager.ack_key(),
|
||||
self.config.get_average_ack_delay(),
|
||||
self.config.get_average_packet_delay(),
|
||||
self.config.get_loop_cover_traffic_average_delay(),
|
||||
self.config.get_base().get_average_ack_delay(),
|
||||
self.config.get_base().get_average_packet_delay(),
|
||||
self.config
|
||||
.get_base()
|
||||
.get_loop_cover_traffic_average_delay(),
|
||||
mix_tx,
|
||||
self.as_mix_recipient(),
|
||||
topology_accessor,
|
||||
@@ -128,11 +132,11 @@ impl NymClient {
|
||||
) {
|
||||
let controller_config = real_messages_control::Config::new(
|
||||
self.key_manager.ack_key(),
|
||||
self.config.get_ack_wait_multiplier(),
|
||||
self.config.get_ack_wait_addition(),
|
||||
self.config.get_average_ack_delay(),
|
||||
self.config.get_message_sending_average_delay(),
|
||||
self.config.get_average_packet_delay(),
|
||||
self.config.get_base().get_ack_wait_multiplier(),
|
||||
self.config.get_base().get_ack_wait_addition(),
|
||||
self.config.get_base().get_average_ack_delay(),
|
||||
self.config.get_base().get_message_sending_average_delay(),
|
||||
self.config.get_base().get_average_packet_delay(),
|
||||
self.as_mix_recipient(),
|
||||
);
|
||||
|
||||
@@ -176,11 +180,11 @@ impl NymClient {
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
ack_sender: AcknowledgementSender,
|
||||
) -> GatewayClient<'static, url::Url> {
|
||||
let gateway_id = self.config.get_gateway_id();
|
||||
let gateway_id = self.config.get_base().get_gateway_id();
|
||||
if gateway_id.is_empty() {
|
||||
panic!("The identity of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
let gateway_address_str = self.config.get_gateway_listener();
|
||||
let gateway_address_str = self.config.get_base().get_gateway_listener();
|
||||
if gateway_address_str.is_empty() {
|
||||
panic!("The address of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
@@ -200,7 +204,7 @@ impl NymClient {
|
||||
Some(self.key_manager.gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
self.config.get_gateway_response_timeout(),
|
||||
self.config.get_base().get_gateway_response_timeout(),
|
||||
);
|
||||
|
||||
self.runtime.block_on(async {
|
||||
@@ -217,8 +221,8 @@ impl NymClient {
|
||||
// the current global view of topology
|
||||
fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
|
||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||
self.config.get_directory_server(),
|
||||
self.config.get_topology_refresh_rate(),
|
||||
self.config.get_base().get_directory_server(),
|
||||
self.config.get_base().get_topology_refresh_rate(),
|
||||
);
|
||||
let mut topology_refresher =
|
||||
TopologyRefresher::new_directory_client(topology_refresher_config, topology_accessor);
|
||||
@@ -226,7 +230,7 @@ impl NymClient {
|
||||
// components depending on topology would see a non-empty view
|
||||
info!(
|
||||
"Obtaining initial network topology from {}",
|
||||
self.config.get_directory_server()
|
||||
self.config.get_base().get_directory_server()
|
||||
);
|
||||
self.runtime.block_on(topology_refresher.refresh());
|
||||
|
||||
@@ -357,7 +361,7 @@ impl NymClient {
|
||||
let shared_topology_accessor = TopologyAccessor::new();
|
||||
|
||||
let reply_key_storage =
|
||||
ReplyKeyStorage::load(self.config.get_reply_encryption_key_store_path())
|
||||
ReplyKeyStorage::load(self.config.get_base().get_reply_encryption_key_store_path())
|
||||
.expect("Failed to load reply key storage!");
|
||||
|
||||
// the components are started in very specific order. Unless you know what you are doing,
|
||||
@@ -413,7 +417,7 @@ impl NymClient {
|
||||
);
|
||||
info!(
|
||||
"Gateway identity public key is: {:?}",
|
||||
self.config.get_gateway_id()
|
||||
self.config.get_base().get_gateway_id()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::built_info;
|
||||
use crate::client::config::Config;
|
||||
use crate::commands::override_config;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use client_core::client::key_manager::KeyManager;
|
||||
@@ -149,48 +150,51 @@ pub fn execute(matches: &ArgMatches) {
|
||||
println!("Initialising client...");
|
||||
|
||||
let id = matches.value_of("id").unwrap(); // required for now
|
||||
let mut config = client_core::config::Config::new(id);
|
||||
let mut config = Config::new(id);
|
||||
let mut rng = OsRng;
|
||||
|
||||
config = override_config(config, matches);
|
||||
if matches.is_present("fastmode") {
|
||||
config = config.set_high_default_traffic_volume();
|
||||
config.get_base_mut().set_high_default_traffic_volume();
|
||||
}
|
||||
|
||||
// create identity, encryption and ack keys.
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
|
||||
// if there is no gateway chosen, get a random-ish one from the topology
|
||||
if config.get_gateway_id().is_empty() {
|
||||
if config.get_base().get_gateway_id().is_empty() {
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let (gateway_id, gateway_listener, shared_key) = rt.block_on(choose_gateway(
|
||||
config.get_directory_server(),
|
||||
config.get_base().get_directory_server(),
|
||||
key_manager.identity_keypair(),
|
||||
));
|
||||
|
||||
config = config
|
||||
.with_gateway_id(gateway_id)
|
||||
config.get_base_mut().with_gateway_id(gateway_id);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
|
||||
key_manager.insert_gateway_shared_key(shared_key)
|
||||
}
|
||||
|
||||
// we specified our gateway but don't know its physical address
|
||||
if config.get_gateway_listener().is_empty() {
|
||||
if config.get_base().get_gateway_listener().is_empty() {
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let gateway_listener = rt
|
||||
.block_on(get_gateway_listener(
|
||||
config.get_directory_server(),
|
||||
&config.get_gateway_id(),
|
||||
config.get_base().get_directory_server(),
|
||||
&config.get_base().get_gateway_id(),
|
||||
))
|
||||
.expect("No gateway with provided id exists!");
|
||||
|
||||
config = config.with_gateway_listener(gateway_listener);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
}
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(&config);
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
@@ -204,7 +208,7 @@ pub fn execute(matches: &ArgMatches) {
|
||||
|
||||
println!(
|
||||
"Unless overridden in all `nym-client run` we will be talking to the following gateway: {}...",
|
||||
config.get_gateway_id(),
|
||||
config.get_base().get_gateway_id(),
|
||||
);
|
||||
|
||||
println!("Client configuration completed.\n\n\n")
|
||||
|
||||
@@ -12,19 +12,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::client::config::{Config, SocketType};
|
||||
use clap::ArgMatches;
|
||||
use client_core::config::{Config, SocketType};
|
||||
|
||||
pub mod init;
|
||||
pub mod run;
|
||||
|
||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||
if let Some(directory) = matches.value_of("directory") {
|
||||
config = config.with_custom_directory(directory);
|
||||
config.get_base_mut().with_custom_directory(directory);
|
||||
}
|
||||
|
||||
if let Some(gateway_id) = matches.value_of("gateway") {
|
||||
config = config.with_gateway_id(gateway_id);
|
||||
config.get_base_mut().with_gateway_id(gateway_id);
|
||||
}
|
||||
|
||||
if matches.is_present("disable-socket") {
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::client::NymClient;
|
||||
use crate::commands::override_config;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use client_core::config::Config;
|
||||
use config::NymConfig;
|
||||
|
||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
|
||||
@@ -11,12 +11,14 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33.0"
|
||||
dirs = "3.0" # for determining default store directories in config
|
||||
dotenv = "0.15.0"
|
||||
futures = "0.3"
|
||||
log = "0.4"
|
||||
pin-project = "0.4"
|
||||
pretty_env_logger = "0.3"
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
serde = { version = "1.0", features = ["derive"] } # for config serialization/deserialization
|
||||
snafu = "0.4.1"
|
||||
tokio = { version = "0.2", features = ["rt-threaded"] }
|
||||
url = "2.1"
|
||||
@@ -35,3 +37,6 @@ utils = { path = "../../common/utils" }
|
||||
|
||||
[build-dependencies]
|
||||
built = "0.4.3"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
@@ -0,0 +1,154 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::client::config::template::config_template;
|
||||
use client_core::config::Config as BaseConfig;
|
||||
use config::NymConfig;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
mod template;
|
||||
|
||||
const DEFAULT_LISTENING_PORT: u16 = 1080;
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
#[serde(flatten)]
|
||||
base: BaseConfig<Config>,
|
||||
|
||||
socks5: Socks5,
|
||||
}
|
||||
|
||||
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("socks5-clients")
|
||||
}
|
||||
|
||||
fn root_directory(&self) -> PathBuf {
|
||||
self.base.get_nym_root_directory()
|
||||
}
|
||||
|
||||
fn config_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(self.base.get_id())
|
||||
.join("config")
|
||||
}
|
||||
|
||||
fn data_directory(&self) -> PathBuf {
|
||||
self.root_directory().join(self.base.get_id()).join("data")
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new<S: Into<String>>(id: S, provider_mix_address: S) -> Self {
|
||||
Config {
|
||||
base: BaseConfig::new(id),
|
||||
socks5: Socks5::new(provider_mix_address),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_port(mut self, port: u16) -> Self {
|
||||
self.socks5.listening_port = port;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_provider_mix_address(mut self, address: String) -> Self {
|
||||
self.socks5.provider_mix_address = address;
|
||||
self
|
||||
}
|
||||
|
||||
// getters
|
||||
pub fn get_config_file_save_location(&self) -> PathBuf {
|
||||
self.config_directory().join(Self::config_file_name())
|
||||
}
|
||||
|
||||
pub fn get_provider_mix_address(&self) -> Recipient {
|
||||
Recipient::try_from_base58_string(&self.socks5.provider_mix_address)
|
||||
.expect("malformed provider address")
|
||||
}
|
||||
|
||||
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_listening_port(&self) -> u16 {
|
||||
self.socks5.listening_port
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socks5 {
|
||||
/// The port on which the client will be listening for incoming requests
|
||||
listening_port: u16,
|
||||
|
||||
/// The mix address of the provider to which all requests are going to be sent.
|
||||
provider_mix_address: String,
|
||||
}
|
||||
|
||||
impl Socks5 {
|
||||
pub fn new<S: Into<String>>(provider_mix_address: S) -> Self {
|
||||
Socks5 {
|
||||
listening_port: DEFAULT_LISTENING_PORT,
|
||||
provider_mix_address: provider_mix_address.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Socks5 {
|
||||
fn default() -> Self {
|
||||
Socks5 {
|
||||
listening_port: DEFAULT_LISTENING_PORT,
|
||||
provider_mix_address: "".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod client_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 fake_address = "CytBseW6yFXUMzz4SGAKdNLGR7q3sJLLYxyBGvutNEQV.4QXYyEVc5fUDjmmi8PrHN9tdUFV4PCvSJE1278cHyvoe@FioFa8nMmPpQnYi7JyojoTuwGLeyNS8BF4ChPr29zUML";
|
||||
let default_config = Config::new("foomp", fake_address);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright 2020 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
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 client config options #####
|
||||
|
||||
[client]
|
||||
# Human readable ID of this particular client.
|
||||
id = '{{ client.id }}'
|
||||
|
||||
# URL to the directory server.
|
||||
directory_server = '{{ client.directory_server }}'
|
||||
|
||||
# Path to file containing 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_file }}'
|
||||
|
||||
# Path to file containing private encryption key.
|
||||
private_encryption_key_file = '{{ client.private_encryption_key_file }}'
|
||||
|
||||
# Path to file containing public encryption key.
|
||||
public_encryption_key_file = '{{ client.public_encryption_key_file }}'
|
||||
|
||||
# Full path to file containing reply encryption keys of all reply-SURBs we have ever
|
||||
# sent but not received back.
|
||||
reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
|
||||
|
||||
##### additional client config options #####
|
||||
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ client.gateway_id }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ client.gateway_listener }}'
|
||||
|
||||
# A gateway specific, optional, base58 stringified shared key used for
|
||||
# communication with particular gateway.
|
||||
gateway_shared_key_file = '{{ client.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 }}'
|
||||
|
||||
##### advanced configuration options #####
|
||||
|
||||
# Absolute path to the home Nym Clients directory.
|
||||
nym_root_directory = '{{ client.nym_root_directory }}'
|
||||
|
||||
|
||||
##### socket config options #####
|
||||
|
||||
[socks5]
|
||||
|
||||
# The mix address of the provider to which all requests are going to be sent.
|
||||
provider_mix_address = '{{ socks5.provider_mix_address }}'
|
||||
|
||||
# The port on which the client will be listening for incoming requests
|
||||
listening_port = {{ socks5.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]
|
||||
|
||||
average_packet_delay = {{ debug.average_packet_delay }}
|
||||
average_ack_delay = {{ debug.average_ack_delay }}
|
||||
loop_cover_traffic_average_delay = {{ debug.loop_cover_traffic_average_delay }}
|
||||
message_sending_average_delay = {{ debug.message_sending_average_delay }}
|
||||
|
||||
"#
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::socks::{
|
||||
authentication::{AuthenticationMethods, Authenticator, User},
|
||||
server::SphinxSocksServer,
|
||||
@@ -25,7 +26,6 @@ use client_core::client::mix_traffic::{
|
||||
MixMessageReceiver, MixMessageSender, MixTrafficController,
|
||||
};
|
||||
use client_core::client::real_messages_control::RealMessagesController;
|
||||
use client_core::client::received_buffer::{ReceivedBufferMessage, ReconstructedMessagesReceiver};
|
||||
use client_core::client::received_buffer::{
|
||||
ReceivedBufferRequestReceiver, ReceivedBufferRequestSender, ReceivedMessagesBufferController,
|
||||
};
|
||||
@@ -34,7 +34,6 @@ use client_core::client::topology_control::{
|
||||
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
|
||||
};
|
||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use client_core::config::{Config, SocketType};
|
||||
use crypto::asymmetric::identity;
|
||||
use futures::channel::mpsc;
|
||||
use gateway_client::{
|
||||
@@ -42,12 +41,12 @@ use gateway_client::{
|
||||
MixnetMessageSender,
|
||||
};
|
||||
use log::*;
|
||||
use nymsphinx::addressing::clients::{ClientEncryptionKey, ClientIdentity, Recipient};
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||
use nymsphinx::anonymous_replies::ReplySURB;
|
||||
use nymsphinx::receiver::ReconstructedMessage;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
pub(crate) mod config;
|
||||
|
||||
pub struct NymClient {
|
||||
/// Client configuration options, including, among other things, packet sending rates,
|
||||
/// key filepaths, etc.
|
||||
@@ -60,28 +59,17 @@ pub struct NymClient {
|
||||
|
||||
/// KeyManager object containing smart pointers to all relevant keys used by the client.
|
||||
key_manager: KeyManager,
|
||||
|
||||
/// Channel used for transforming 'raw' messages into sphinx packets and sending them
|
||||
/// through the mix network.
|
||||
/// It is only available if the client started with the websocket listener disabled.
|
||||
input_tx: Option<InputMessageSender>,
|
||||
|
||||
/// Channel used for obtaining reconstructed messages received from the mix network.
|
||||
/// It is only available if the client started with the websocket listener disabled.
|
||||
receive_tx: Option<ReconstructedMessagesReceiver>,
|
||||
}
|
||||
|
||||
impl NymClient {
|
||||
pub fn new(config: Config) -> Self {
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(&config);
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
let key_manager = KeyManager::load_keys(&pathfinder).expect("failed to load stored keys");
|
||||
|
||||
NymClient {
|
||||
runtime: Runtime::new().unwrap(),
|
||||
config,
|
||||
key_manager,
|
||||
input_tx: None,
|
||||
receive_tx: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +79,7 @@ impl NymClient {
|
||||
self.key_manager.encryption_keypair().public_key().clone(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(self.config.get_gateway_id()).unwrap(),
|
||||
NodeIdentity::from_base58_string(self.config.get_base().get_gateway_id()).unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -109,9 +97,11 @@ impl NymClient {
|
||||
.enter(|| {
|
||||
LoopCoverTrafficStream::new(
|
||||
self.key_manager.ack_key(),
|
||||
self.config.get_average_ack_delay(),
|
||||
self.config.get_average_packet_delay(),
|
||||
self.config.get_loop_cover_traffic_average_delay(),
|
||||
self.config.get_base().get_average_ack_delay(),
|
||||
self.config.get_base().get_average_packet_delay(),
|
||||
self.config
|
||||
.get_base()
|
||||
.get_loop_cover_traffic_average_delay(),
|
||||
mix_tx,
|
||||
self.as_mix_recipient(),
|
||||
topology_accessor,
|
||||
@@ -130,11 +120,11 @@ impl NymClient {
|
||||
) {
|
||||
let controller_config = client_core::client::real_messages_control::Config::new(
|
||||
self.key_manager.ack_key(),
|
||||
self.config.get_ack_wait_multiplier(),
|
||||
self.config.get_ack_wait_addition(),
|
||||
self.config.get_average_ack_delay(),
|
||||
self.config.get_message_sending_average_delay(),
|
||||
self.config.get_average_packet_delay(),
|
||||
self.config.get_base().get_ack_wait_multiplier(),
|
||||
self.config.get_base().get_ack_wait_addition(),
|
||||
self.config.get_base().get_average_ack_delay(),
|
||||
self.config.get_base().get_message_sending_average_delay(),
|
||||
self.config.get_base().get_average_packet_delay(),
|
||||
self.as_mix_recipient(),
|
||||
);
|
||||
|
||||
@@ -178,11 +168,11 @@ impl NymClient {
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
ack_sender: AcknowledgementSender,
|
||||
) -> GatewayClient<'static, url::Url> {
|
||||
let gateway_id = self.config.get_gateway_id();
|
||||
let gateway_id = self.config.get_base().get_gateway_id();
|
||||
if gateway_id.is_empty() {
|
||||
panic!("The identity of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
let gateway_address_str = self.config.get_gateway_listener();
|
||||
let gateway_address_str = self.config.get_base().get_gateway_listener();
|
||||
if gateway_address_str.is_empty() {
|
||||
panic!("The address of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
@@ -202,7 +192,7 @@ impl NymClient {
|
||||
Some(self.key_manager.gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
self.config.get_gateway_response_timeout(),
|
||||
self.config.get_base().get_gateway_response_timeout(),
|
||||
);
|
||||
|
||||
self.runtime.block_on(async {
|
||||
@@ -219,8 +209,8 @@ impl NymClient {
|
||||
// the current global view of topology
|
||||
fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
|
||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||
self.config.get_directory_server(),
|
||||
self.config.get_topology_refresh_rate(),
|
||||
self.config.get_base().get_directory_server(),
|
||||
self.config.get_base().get_topology_refresh_rate(),
|
||||
);
|
||||
let mut topology_refresher =
|
||||
TopologyRefresher::new_directory_client(topology_refresher_config, topology_accessor);
|
||||
@@ -228,7 +218,7 @@ impl NymClient {
|
||||
// components depending on topology would see a non-empty view
|
||||
info!(
|
||||
"Obtaining initial network topology from {}",
|
||||
self.config.get_directory_server()
|
||||
self.config.get_base().get_directory_server()
|
||||
);
|
||||
self.runtime.block_on(topology_refresher.refresh());
|
||||
|
||||
@@ -271,74 +261,15 @@ impl NymClient {
|
||||
let allowed_users: Vec<User> = Vec::new();
|
||||
|
||||
let authenticator = Authenticator::new(auth_methods, allowed_users);
|
||||
let recipient = self.load_socks5_service_provider();
|
||||
let mut sphinx_socks = SphinxSocksServer::new(
|
||||
1080,
|
||||
"127.0.0.1",
|
||||
self.config.get_listening_port(),
|
||||
authenticator,
|
||||
recipient,
|
||||
self.config.get_provider_mix_address(),
|
||||
self.as_mix_recipient(),
|
||||
);
|
||||
self.runtime
|
||||
.spawn(async move { sphinx_socks.serve(msg_input, buffer_requester).await });
|
||||
}
|
||||
// TODO: make this configurable in the client config file
|
||||
// TODO: Talk to JS about where I can easily find these.
|
||||
fn load_socks5_service_provider(&self) -> Recipient {
|
||||
// load from file here, or better yet, inject it
|
||||
let identity = "G3WSu7S3Jdm5HHQwZ3bT7NKoEBNSGr8JY2jngbUigqfz";
|
||||
let encryption_key = "6KUoz9gexdFziLrrh6M2gXpAW4Fdn3HBHss11WJDYKEL";
|
||||
let gateway_key = "5QAR66H9aMqaEo9y9G4hxAsvenJe13wJSRkwQ8qjsF6C";
|
||||
|
||||
let client_identity = ClientIdentity::from_base58_string(identity).unwrap();
|
||||
let client_encryption_key =
|
||||
ClientEncryptionKey::from_base58_string(encryption_key).unwrap();
|
||||
let gateway = NodeIdentity::from_base58_string(gateway_key).unwrap();
|
||||
Recipient::new(client_identity, client_encryption_key, gateway)
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL DIRECT RUST API
|
||||
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
|
||||
/// well enough in local tests)
|
||||
pub fn send_message(&mut self, recipient: Recipient, message: Vec<u8>, with_reply_surb: bool) {
|
||||
let input_msg = InputMessage::new_fresh(recipient, message, with_reply_surb);
|
||||
|
||||
self.input_tx
|
||||
.as_ref()
|
||||
.expect("start method was not called before!")
|
||||
.unbounded_send(input_msg)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL DIRECT RUST API
|
||||
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
|
||||
/// well enough in local tests)
|
||||
pub fn send_reply(&mut self, reply_surb: ReplySURB, message: Vec<u8>) {
|
||||
let input_msg = InputMessage::new_reply(reply_surb, message);
|
||||
|
||||
self.input_tx
|
||||
.as_ref()
|
||||
.expect("start method was not called before!")
|
||||
.unbounded_send(input_msg)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// EXPERIMENTAL DIRECT RUST API
|
||||
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
|
||||
/// well enough in local tests)
|
||||
/// Note: it waits for the first occurrence of messages being sent to ourselves. If you expect multiple
|
||||
/// messages, you might have to call this function repeatedly.
|
||||
// TODO: I guess this should really return something that `impl Stream<Item=ReconstructedMessage>`
|
||||
pub async fn wait_for_messages(&mut self) -> Vec<ReconstructedMessage> {
|
||||
use futures::StreamExt;
|
||||
|
||||
self.receive_tx
|
||||
.as_mut()
|
||||
.expect("start method was not called before!")
|
||||
.next()
|
||||
.await
|
||||
.expect("buffer controller seems to have somehow died!")
|
||||
}
|
||||
|
||||
/// blocking version of `start` method. Will run forever (or until SIGINT is sent)
|
||||
pub fn run_forever(&mut self) {
|
||||
@@ -382,7 +313,7 @@ impl NymClient {
|
||||
let shared_topology_accessor = TopologyAccessor::new();
|
||||
|
||||
let reply_key_storage =
|
||||
ReplyKeyStorage::load(self.config.get_reply_encryption_key_store_path())
|
||||
ReplyKeyStorage::load(self.config.get_base().get_reply_encryption_key_store_path())
|
||||
.expect("Failed to load reply key storage!");
|
||||
|
||||
// the components are started in very specific order. Unless you know what you are doing,
|
||||
@@ -405,27 +336,7 @@ impl NymClient {
|
||||
sphinx_message_sender.clone(),
|
||||
);
|
||||
self.start_cover_traffic_stream(shared_topology_accessor, sphinx_message_sender);
|
||||
|
||||
match self.config.get_socket_type() {
|
||||
SocketType::WebSocket => {
|
||||
self.start_socks5_listener(received_buffer_request_sender, input_sender)
|
||||
}
|
||||
SocketType::None => {
|
||||
// if we did not start the socket, it means we're running (supposedly) in the native mode
|
||||
// and hence we should announce 'ourselves' to the buffer
|
||||
let (reconstructed_sender, reconstructed_receiver) = mpsc::unbounded();
|
||||
|
||||
// tell the buffer to start sending stuff to us
|
||||
received_buffer_request_sender
|
||||
.unbounded_send(ReceivedBufferMessage::ReceiverAnnounce(
|
||||
reconstructed_sender,
|
||||
))
|
||||
.expect("the buffer request failed!");
|
||||
|
||||
self.receive_tx = Some(reconstructed_receiver);
|
||||
self.input_tx = Some(input_sender);
|
||||
}
|
||||
}
|
||||
self.start_socks5_listener(received_buffer_request_sender, input_sender);
|
||||
|
||||
info!("Client startup finished!");
|
||||
info!(
|
||||
@@ -438,7 +349,7 @@ impl NymClient {
|
||||
);
|
||||
info!(
|
||||
"Gateway identity public key is: {:?}",
|
||||
self.config.get_gateway_id()
|
||||
self.config.get_base().get_gateway_id()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::built_info;
|
||||
use crate::client::config::Config;
|
||||
use crate::commands::override_config;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use client_core::client::key_manager::KeyManager;
|
||||
@@ -37,6 +38,12 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
)
|
||||
.arg(Arg::with_name("provider")
|
||||
.long("provider")
|
||||
.help("Address of the socks5 provider to send messages to.")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
)
|
||||
.arg(Arg::with_name("gateway")
|
||||
.long("gateway")
|
||||
.help("Id of the gateway we have preference to connect to. If left empty, a random gateway will be chosen.")
|
||||
@@ -47,14 +54,10 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
.help("Address of the directory server the client is getting topology from")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(Arg::with_name("disable-socket")
|
||||
.long("disable-socket")
|
||||
.help("Whether to not start the websocket")
|
||||
)
|
||||
.arg(Arg::with_name("port")
|
||||
.short("p")
|
||||
.long("port")
|
||||
.help("Port for the socket (if applicable) to listen on in all subsequent runs")
|
||||
.help("Port for the socket to listen on in all subsequent runs")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(Arg::with_name("fastmode")
|
||||
@@ -149,48 +152,53 @@ pub fn execute(matches: &ArgMatches) {
|
||||
println!("Initialising client...");
|
||||
|
||||
let id = matches.value_of("id").unwrap(); // required for now
|
||||
let mut config = client_core::config::Config::new(id);
|
||||
let provider_address = matches.value_of("provider").unwrap();
|
||||
|
||||
let mut config = Config::new(id, provider_address);
|
||||
let mut rng = OsRng;
|
||||
|
||||
config = override_config(config, matches);
|
||||
if matches.is_present("fastmode") {
|
||||
config = config.set_high_default_traffic_volume();
|
||||
config.get_base_mut().set_high_default_traffic_volume();
|
||||
}
|
||||
|
||||
// create identity, encryption and ack keys.
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
|
||||
// if there is no gateway chosen, get a random-ish one from the topology
|
||||
if config.get_gateway_id().is_empty() {
|
||||
if config.get_base().get_gateway_id().is_empty() {
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let (gateway_id, gateway_listener, shared_key) = rt.block_on(choose_gateway(
|
||||
config.get_directory_server(),
|
||||
config.get_base().get_directory_server(),
|
||||
key_manager.identity_keypair(),
|
||||
));
|
||||
|
||||
config = config
|
||||
.with_gateway_id(gateway_id)
|
||||
config.get_base_mut().with_gateway_id(gateway_id);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
|
||||
key_manager.insert_gateway_shared_key(shared_key)
|
||||
}
|
||||
|
||||
// we specified our gateway but don't know its physical address
|
||||
if config.get_gateway_listener().is_empty() {
|
||||
if config.get_base().get_gateway_listener().is_empty() {
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let gateway_listener = rt
|
||||
.block_on(get_gateway_listener(
|
||||
config.get_directory_server(),
|
||||
&config.get_gateway_id(),
|
||||
config.get_base().get_directory_server(),
|
||||
&config.get_base().get_gateway_id(),
|
||||
))
|
||||
.expect("No gateway with provided id exists!");
|
||||
|
||||
config = config.with_gateway_listener(gateway_listener);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
}
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(&config);
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
@@ -204,7 +212,7 @@ pub fn execute(matches: &ArgMatches) {
|
||||
|
||||
println!(
|
||||
"Unless overridden in all `nym-client run` we will be talking to the following gateway: {}...",
|
||||
config.get_gateway_id(),
|
||||
config.get_base().get_gateway_id(),
|
||||
);
|
||||
|
||||
println!("Client configuration completed.\n\n\n")
|
||||
|
||||
@@ -12,23 +12,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::client::config::Config;
|
||||
use clap::ArgMatches;
|
||||
use client_core::config::{Config, SocketType};
|
||||
|
||||
pub mod init;
|
||||
pub mod run;
|
||||
|
||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||
if let Some(directory) = matches.value_of("directory") {
|
||||
config = config.with_custom_directory(directory);
|
||||
config.get_base_mut().with_custom_directory(directory);
|
||||
}
|
||||
|
||||
if let Some(gateway_id) = matches.value_of("gateway") {
|
||||
config = config.with_gateway_id(gateway_id);
|
||||
}
|
||||
|
||||
if matches.is_present("disable-socket") {
|
||||
config = config.with_socket(SocketType::None);
|
||||
config.get_base_mut().with_gateway_id(gateway_id);
|
||||
}
|
||||
|
||||
if let Some(port) = matches.value_of("port").map(|port| port.parse::<u16>()) {
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::client::NymClient;
|
||||
use crate::commands::override_config;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use client_core::config::Config;
|
||||
use config::NymConfig;
|
||||
|
||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
@@ -33,6 +33,11 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
.help("Custom path to the nym-mixnet-client configuration file")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(Arg::with_name("provider")
|
||||
.long("provider")
|
||||
.help("Address of the socks5 provider to send messages to.")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(Arg::with_name("directory")
|
||||
.long("directory")
|
||||
.help("Address of the directory server the client is getting topology from")
|
||||
@@ -43,14 +48,10 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
.help("Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(Arg::with_name("disable-socket")
|
||||
.long("disable-socket")
|
||||
.help("Whether to not start the websocket")
|
||||
)
|
||||
.arg(Arg::with_name("port")
|
||||
.short("p")
|
||||
.long("port")
|
||||
.help("Port for the socket (if applicable) to listen on")
|
||||
.help("Port for the socket to listen on")
|
||||
.takes_value(true)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,11 +25,13 @@ impl SphinxSocksServer {
|
||||
/// Create a new SphinxSocks instance
|
||||
pub(crate) fn new(
|
||||
port: u16,
|
||||
ip: &str,
|
||||
authenticator: Authenticator,
|
||||
service_provider: Recipient,
|
||||
self_address: Recipient,
|
||||
) -> Self {
|
||||
// hardcode ip as we (presumably) ONLY want to listen locally. If we change it, we can
|
||||
// just modify the config
|
||||
let ip = "127.0.0.1";
|
||||
info!("Listening on {}:{}", ip, port);
|
||||
SphinxSocksServer {
|
||||
authenticator,
|
||||
|
||||
Reference in New Issue
Block a user