From c59688a0451fe37f72d2eec943abb597b85f6342 Mon Sep 17 00:00:00 2001 From: scilio Date: Thu, 13 Oct 2022 11:15:52 -0400 Subject: [PATCH 1/2] switch to x25519 for onion encryption --- Cargo.lock | 26 ++++----- Cargo.toml | 8 ++- src/main.rs | 40 +++++++------ src/onion.rs | 157 ++++++++++++++++++++++++++++++-------------------- src/secp.rs | 7 +-- src/server.rs | 9 ++- 6 files changed, 136 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed8c4a8..1bb4713 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,7 +45,7 @@ dependencies = [ "nom 7.1.0", "pin-project", "rand 0.7.3", - "rand 0.8.4", + "rand 0.8.5", "rust-embed", "scrypt", "sha2 0.9.8", @@ -65,7 +65,7 @@ dependencies = [ "cookie-factory", "hkdf", "nom 7.1.0", - "rand 0.8.4", + "rand 0.8.5", "secrecy 0.8.0", "sha2 0.9.8", ] @@ -2475,7 +2475,9 @@ dependencies = [ "bytes 0.5.6", "chacha20", "clap", + "curve25519-dalek 2.1.3", "dirs", + "ed25519-dalek", "futures 0.3.17", "grin_api 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)", "grin_chain 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)", @@ -2488,6 +2490,7 @@ dependencies = [ "grin_wallet_api", "grin_wallet_impls", "grin_wallet_libwallet", + "grin_wallet_util", "hmac 0.12.0", "hyper 0.14.14", "itertools", @@ -2496,7 +2499,7 @@ dependencies = [ "jsonrpc-http-server", "lazy_static", "pbkdf2 0.8.0", - "rand 0.8.4", + "rand 0.7.3", "ring", "rpassword", "serde", @@ -2506,6 +2509,7 @@ dependencies = [ "thiserror", "tokio 1.12.0", "toml", + "x25519-dalek 0.6.0", ] [[package]] @@ -3033,14 +3037,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", "rand_core 0.6.3", - "rand_hc 0.3.1", ] [[package]] @@ -3124,15 +3127,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core 0.6.3", -] - [[package]] name = "rand_isaac" version = "0.1.1" @@ -3854,7 +3848,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", - "rand 0.8.4", + "rand 0.8.5", "redox_syscall 0.2.10", "remove_dir_all", "winapi 0.3.9", diff --git a/Cargo.toml b/Cargo.toml index e9ef822..7078fb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,9 @@ byteorder = "1" bytes = "0.5.6" chacha20 = "0.8.1" clap = { version = "2.33", features = ["yaml"] } +curve25519-dalek = "2.1" dirs = "2.0" +ed25519-dalek = "1.0.1" futures = "0.3" hmac = { version = "0.12.0", features = ["std"]} hyper = { version = "0.14", features = ["full"] } @@ -21,7 +23,7 @@ jsonrpc-derive = "18.0" jsonrpc-http-server = "18.0" lazy_static = "1" pbkdf2 = "0.8.0" -rand = "0.8.4" +rand = "0.7.3" ring = "0.16" rpassword = "4.0" serde = { version = "1", features= ["derive"]} @@ -31,6 +33,7 @@ sha2 = "0.10.0" thiserror = "1.0.31" tokio = { version = "1", features = ["full"] } toml = "0.5" +x25519-dalek = "0.6.0" grin_secp256k1zkp = { version = "0.7.11", features = ["bullet-proof-sizing"]} grin_util = "5" grin_api = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" } @@ -41,4 +44,5 @@ grin_servers = { git = "https://github.com/mimblewimble/grin", version = "5.2.0- grin_store = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" } grin_wallet_api = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" } grin_wallet_impls = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" } -grin_wallet_libwallet = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" } \ No newline at end of file +grin_wallet_libwallet = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" } +grin_wallet_util = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 2644a68..cb2eb2a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -190,28 +190,30 @@ fn real_main() -> Result<(), Box> { ) } +#[cfg(unix)] async fn build_signals_fut() { - if cfg!(unix) { - use tokio::signal::unix::{signal, SignalKind}; + use tokio::signal::unix::{signal, SignalKind}; - // Listen for SIGINT, SIGQUIT, and SIGTERM - let mut terminate_signal = - signal(SignalKind::terminate()).expect("failed to create terminate signal"); - let mut quit_signal = signal(SignalKind::quit()).expect("failed to create quit signal"); - let mut interrupt_signal = - signal(SignalKind::interrupt()).expect("failed to create interrupt signal"); + // Listen for SIGINT, SIGQUIT, and SIGTERM + let mut terminate_signal = + signal(SignalKind::terminate()).expect("failed to create terminate signal"); + let mut quit_signal = signal(SignalKind::quit()).expect("failed to create quit signal"); + let mut interrupt_signal = + signal(SignalKind::interrupt()).expect("failed to create interrupt signal"); - futures::future::select_all(vec![ - Box::pin(terminate_signal.recv()), - Box::pin(quit_signal.recv()), - Box::pin(interrupt_signal.recv()), - ]) - .await; - } else { - tokio::signal::ctrl_c() - .await - .expect("failed to install CTRL+C signal handler"); - } + futures::future::select_all(vec![ + Box::pin(terminate_signal.recv()), + Box::pin(quit_signal.recv()), + Box::pin(interrupt_signal.recv()), + ]) + .await; +} + +#[cfg(not(unix))] +async fn build_signals_fut() { + tokio::signal::ctrl_c() + .await + .expect("failed to install CTRL+C signal handler"); } fn prompt_password() -> ZeroingString { diff --git a/src/onion.rs b/src/onion.rs index 80309da..ff61971 100644 --- a/src/onion.rs +++ b/src/onion.rs @@ -1,34 +1,62 @@ -use crate::secp::{self, Commitment, PublicKey, Secp256k1, SecretKey, SharedSecret}; +use crate::secp::{self, Commitment, SecretKey}; use crate::types::Payload; use crate::onion::OnionError::{InvalidKeyLength, SerializationError}; use chacha20::cipher::{NewCipher, StreamCipher}; use chacha20::{ChaCha20, Key, Nonce}; -use grin_core::ser::{self, ProtocolVersion, Readable, Reader, Writeable, Writer}; +use grin_core::ser::{self, Readable, Reader, Writeable, Writer}; use grin_util::{self, ToHex}; use hmac::digest::InvalidLength; use hmac::{Hmac, Mac}; use serde::ser::SerializeStruct; use serde::Deserialize; use sha2::{Digest, Sha256}; +use std::convert::TryInto; use std::fmt; +use std::hash::{Hash, Hasher}; use std::result::Result; use thiserror::Error; +use x25519_dalek::{PublicKey as xPublicKey, SharedSecret, StaticSecret}; type HmacSha256 = Hmac; type RawBytes = Vec; /// A data packet with layers of encryption -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug)] pub struct Onion { /// The onion originator's portion of the shared secret - pub ephemeral_pubkey: PublicKey, + pub ephemeral_pubkey: xPublicKey, /// The pedersen commitment before adjusting the excess and subtracting the fee pub commit: Commitment, /// The encrypted payloads which represent the layers of the onion pub enc_payloads: Vec, } +impl PartialEq for Onion { + fn eq(&self, other: &Onion) -> bool { + *self.ephemeral_pubkey.as_bytes() == *other.ephemeral_pubkey.as_bytes() + && self.commit == other.commit + && self.enc_payloads == other.enc_payloads + } +} + +impl Eq for Onion {} + +impl Hash for Onion { + fn hash(&self, state: &mut H) { + state.write(self.ephemeral_pubkey.as_bytes()); + state.write(self.commit.as_ref()); + state.write_usize(self.enc_payloads.len()); + for p in &self.enc_payloads { + state.write(p.as_slice()); + } + } +} + +fn vec_to_32_byte_arr(v: Vec) -> Result<[u8; 32], OnionError> { + v.try_into().map_err(|_| InvalidKeyLength) +} + impl Onion { pub fn serialize(&self) -> Result, ser::Error> { let mut vec = vec![]; @@ -38,9 +66,7 @@ impl Onion { /// Peel a single layer off of the Onion, returning the peeled Onion and decrypted Payload pub fn peel_layer(&self, secret_key: &SecretKey) -> Result<(Payload, Onion), OnionError> { - let secp = Secp256k1::new(); - - let shared_secret = SharedSecret::new(&secp, &self.ephemeral_pubkey, &secret_key); + let shared_secret = StaticSecret::from(secret_key.0).diffie_hellman(&self.ephemeral_pubkey); let mut cipher = new_stream_cipher(&shared_secret)?; let mut decrypted_bytes = self.enc_payloads[0].clone(); @@ -62,10 +88,12 @@ impl Onion { let blinding_factor = calc_blinding_factor(&shared_secret, &self.ephemeral_pubkey)?; - let mut ephemeral_pubkey = self.ephemeral_pubkey.clone(); - ephemeral_pubkey - .mul_assign(&secp, &blinding_factor) - .map_err(|e| OnionError::CalcPubKeyError(e))?; + let ephemeral_key = StaticSecret::from( + *blinding_factor + .diffie_hellman(&self.ephemeral_pubkey) + .as_bytes(), + ); + let ephemeral_pubkey = xPublicKey::from(&ephemeral_key); let mut commitment = self.commit.clone(); commitment = secp::add_excess(&commitment, &decrypted_payload.excess) @@ -84,23 +112,23 @@ impl Onion { fn calc_blinding_factor( shared_secret: &SharedSecret, - ephemeral_pubkey: &PublicKey, -) -> Result { - let serialized_pubkey = ser::ser_vec(&ephemeral_pubkey, ProtocolVersion::local())?; - + ephemeral_pubkey: &xPublicKey, +) -> Result { let mut hasher = Sha256::default(); - hasher.update(&serialized_pubkey); - hasher.update(&shared_secret[0..32]); + hasher.update(ephemeral_pubkey.as_bytes()); + hasher.update(shared_secret.as_bytes()); + let hashed: [u8; 32] = hasher + .finalize() + .as_slice() + .try_into() + .map_err(|_| InvalidKeyLength)?; - let secp = Secp256k1::new(); - let blind = SecretKey::from_slice(&secp, &hasher.finalize()) - .map_err(|e| OnionError::CalcBlindError(e))?; - Ok(blind) + Ok(StaticSecret::from(hashed)) } fn new_stream_cipher(shared_secret: &SharedSecret) -> Result { let mut mu_hmac = HmacSha256::new_from_slice(b"MWIXNET")?; - mu_hmac.update(&shared_secret[0..32]); + mu_hmac.update(shared_secret.as_bytes()); let mukey = mu_hmac.finalize().into_bytes(); let key = Key::from_slice(&mukey[0..32]); @@ -111,7 +139,7 @@ fn new_stream_cipher(shared_secret: &SharedSecret) -> Result(&self, writer: &mut W) -> Result<(), ser::Error> { - self.ephemeral_pubkey.write(writer)?; + writer.write_fixed_bytes(self.ephemeral_pubkey.as_bytes())?; writer.write_fixed_bytes(&self.commit)?; writer.write_u64(self.enc_payloads.len() as u64)?; for p in &self.enc_payloads { @@ -124,7 +152,9 @@ impl Writeable for Onion { impl Readable for Onion { fn read(reader: &mut R) -> Result { - let ephemeral_pubkey = PublicKey::read(reader)?; + let pubkey_bytes: [u8; 32] = + vec_to_32_byte_arr(reader.read_fixed_bytes(32)?).map_err(|_| ser::Error::CountError)?; + let ephemeral_pubkey = xPublicKey::from(pubkey_bytes); let commit = Commitment::read(reader)?; let mut enc_payloads: Vec = Vec::new(); let len = reader.read_u64()?; @@ -148,11 +178,7 @@ impl serde::ser::Serialize for Onion { { let mut state = serializer.serialize_struct("Onion", 3)?; - let secp = Secp256k1::new(); - state.serialize_field( - "pubkey", - &self.ephemeral_pubkey.serialize_vec(&secp, true).to_hex(), - )?; + state.serialize_field("pubkey", &self.ephemeral_pubkey.as_bytes().to_hex())?; state.serialize_field("commit", &self.commit.to_hex())?; let hex_payloads: Vec = self.enc_payloads.iter().map(|v| v.to_hex()).collect(); @@ -197,11 +223,10 @@ impl<'de> serde::de::Deserialize<'de> for Onion { let val: String = map.next_value()?; let vec = grin_util::from_hex(&val).map_err(serde::de::Error::custom)?; - let secp = Secp256k1::new(); - pubkey = Some( - PublicKey::from_slice(&secp, &vec[..]) - .map_err(serde::de::Error::custom)?, - ); + pubkey = + Some(xPublicKey::from(vec_to_32_byte_arr(vec).map_err(|_| { + serde::de::Error::custom("Invalid length pubkey") + })?)); } Field::Commit => { let val: String = map.next_value()?; @@ -267,40 +292,49 @@ impl From for OnionError { #[cfg(test)] pub mod test_util { use super::{Onion, OnionError, RawBytes}; - use crate::secp::test_util::{rand_commit, rand_proof, rand_pubkey}; - use crate::secp::{self, Commitment, PublicKey, Secp256k1, SecretKey, SharedSecret}; + use crate::secp::test_util::{rand_commit, rand_proof}; + use crate::secp::{random_secret, Commitment, SecretKey}; use crate::types::Payload; use chacha20::cipher::StreamCipher; use grin_core::core::FeeFields; - use rand::RngCore; + use rand::{thread_rng, RngCore}; + use x25519_dalek::PublicKey as xPublicKey; + use x25519_dalek::{SharedSecret, StaticSecret}; #[derive(Clone)] pub struct Hop { - pub pubkey: PublicKey, + pub pubkey: xPublicKey, pub payload: Payload, } + /* + Choose random xi for each node ni and create a Payload (Pi) for each containing xi + Build a rangeproof for Cn=Cin+(Σx1...n)*G and include it in payload Pn + Choose random initial ephemeral keypair (r1, R1) + Derive remaining ephemeral keypairs such that ri+1=ri*Sha256(Ri||si) where si=ECDH(Ri, Ki) + For each node ni, use ChaCha20 stream cipher with key=HmacSha256("MWIXNET"||si) and nonce "NONCE1234567" to encrypt payloads Pi...n + */ /// Create an Onion for the Commitment, encrypting the payload for each hop pub fn create_onion(commitment: &Commitment, hops: &Vec) -> Result { - let secp = Secp256k1::new(); - let session_key = secp::random_secret(); - let mut ephemeral_key = session_key.clone(); + let initial_key = StaticSecret::new(&mut thread_rng()); + let mut ephemeral_key = initial_key.clone(); let mut shared_secrets: Vec = Vec::new(); let mut enc_payloads: Vec = Vec::new(); for hop in hops { - let shared_secret = SharedSecret::new(&secp, &hop.pubkey, &ephemeral_key); + let shared_secret = ephemeral_key.diffie_hellman(&hop.pubkey); - let ephemeral_pubkey = PublicKey::from_secret_key(&secp, &ephemeral_key) - .map_err(|e| OnionError::CalcPubKeyError(e))?; + let ephemeral_pubkey = xPublicKey::from(&ephemeral_key); let blinding_factor = super::calc_blinding_factor(&shared_secret, &ephemeral_pubkey)?; shared_secrets.push(shared_secret); enc_payloads.push(hop.payload.serialize()?); - ephemeral_key - .mul_assign(&secp, &blinding_factor) - .map_err(|e| OnionError::CalcPubKeyError(e))?; + ephemeral_key = StaticSecret::from( + *ephemeral_key + .diffie_hellman(&xPublicKey::from(&blinding_factor)) + .as_bytes(), + ); } for i in (0..shared_secrets.len()).rev() { @@ -311,8 +345,7 @@ pub mod test_util { } let onion = Onion { - ephemeral_pubkey: PublicKey::from_secret_key(&secp, &session_key) - .map_err(|e| OnionError::CalcPubKeyError(e))?, + ephemeral_pubkey: xPublicKey::from(&initial_key), commit: commitment.clone(), enc_payloads, }; @@ -322,13 +355,13 @@ pub mod test_util { pub fn rand_onion() -> Onion { let commit = rand_commit(); let mut hops = Vec::new(); - let k = (rand::thread_rng().next_u64() % 5) + 1; + let k = (thread_rng().next_u64() % 5) + 1; for i in 0..k { let hop = Hop { - pubkey: rand_pubkey(), + pubkey: xPublicKey::from(random_secret().0), payload: Payload { - excess: secp::random_secret(), - fee: FeeFields::from(rand::thread_rng().next_u32()), + excess: random_secret(), + fee: FeeFields::from(thread_rng().next_u32()), rangeproof: if i == (k - 1) { Some(rand_proof()) } else { @@ -346,15 +379,12 @@ pub mod test_util { pub fn next_ephemeral_pubkey( onion: &Onion, server_key: &SecretKey, - ) -> Result { - let secp = Secp256k1::new(); - let mut ephemeral_pubkey = onion.ephemeral_pubkey.clone(); - let shared_secret = SharedSecret::new(&secp, &ephemeral_pubkey, &server_key); - let blinding_factor = super::calc_blinding_factor(&shared_secret, &ephemeral_pubkey)?; - ephemeral_pubkey - .mul_assign(&secp, &blinding_factor) - .map_err(|e| OnionError::CalcPubKeyError(e))?; - Ok(ephemeral_pubkey) + ) -> Result { + let shared_secret = + StaticSecret::from(server_key.0.clone()).diffie_hellman(&onion.ephemeral_pubkey); + let blinding_factor = super::calc_blinding_factor(&shared_secret, &onion.ephemeral_pubkey)?; + let mul = blinding_factor.diffie_hellman(&onion.ephemeral_pubkey); + Ok(xPublicKey::from(&StaticSecret::from(*mul.as_bytes()))) } } @@ -365,6 +395,7 @@ pub mod tests { use crate::types::Payload; use grin_core::core::FeeFields; + use x25519_dalek::{PublicKey as xPublicKey, StaticSecret}; /// Test end-to-end Onion creation and unwrapping logic. #[test] @@ -405,7 +436,7 @@ pub mod tests { }; hops.push(Hop { - pubkey: secp::PublicKey::from_secret_key(&secp, &keys[i]).unwrap(), + pubkey: xPublicKey::from(&StaticSecret::from(keys[i].0.clone())), payload: Payload { excess, fee: FeeFields::from(fee_per_hop as u32), diff --git a/src/secp.rs b/src/secp.rs index 815654d..72fd14d 100644 --- a/src/secp.rs +++ b/src/secp.rs @@ -218,7 +218,7 @@ pub fn sign(sk: &SecretKey, msg: &Message) -> Result PublicKey { - let secp = Secp256k1::new(); - PublicKey::from_secret_key(&secp, &secp::random_secret()).unwrap() - } } #[cfg(test)] diff --git a/src/server.rs b/src/server.rs index e12e2ec..3b388d3 100644 --- a/src/server.rs +++ b/src/server.rs @@ -270,9 +270,7 @@ mod tests { use crate::node::mock::MockGrinNode; use crate::onion::test_util::{self, Hop}; use crate::onion::Onion; - use crate::secp::{ - self, ComSignature, Commitment, PublicKey, RangeProof, Secp256k1, SecretKey, - }; + use crate::secp::{self, ComSignature, Commitment, RangeProof, Secp256k1, SecretKey}; use crate::server::{Server, ServerImpl, SwapError}; use crate::store::{SwapData, SwapStatus, SwapStore}; use crate::types::Payload; @@ -283,6 +281,8 @@ mod tests { use grin_core::global::{self, ChainTypes}; use std::net::TcpListener; use std::sync::Arc; + use x25519_dalek::PublicKey as xPublicKey; + use x25519_dalek::StaticSecret; macro_rules! assert_error_type { ($result:expr, $error_type:pat) => { @@ -351,9 +351,8 @@ mod tests { fee: u64, proof: Option, ) -> Hop { - let secp = Secp256k1::new(); Hop { - pubkey: PublicKey::from_secret_key(&secp, &server_key).unwrap(), + pubkey: xPublicKey::from(&StaticSecret::from(server_key.0.clone())), payload: Payload { excess: hop_excess.clone(), fee: FeeFields::from(fee as u32), From 9ec200f548be46f5bd555ca03ca938e07b57269a Mon Sep 17 00:00:00 2001 From: scilio Date: Thu, 13 Oct 2022 15:13:38 -0400 Subject: [PATCH 2/2] use tor --- mwixnet.yml | 2 +- src/main.rs | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/rpc.rs | 1 - 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/mwixnet.yml b/mwixnet.yml index 871b204..bd1c5d8 100644 --- a/mwixnet.yml +++ b/mwixnet.yml @@ -35,7 +35,7 @@ args: long: wallet_pass takes_value: true - bind_addr: - help: Address to bind the rpc server to (e.g. 0.0.0.0:3000) + help: Address to bind the rpc server to (e.g. 127.0.0.1:3000) long: bind_addr takes_value: true subcommands: diff --git a/src/main.rs b/src/main.rs index cb2eb2a..19e5348 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use config::ServerConfig; use node::HttpGrinNode; +use std::collections::HashMap; use store::SwapStore; use wallet::HttpWallet; @@ -9,6 +10,9 @@ use clap::App; use grin_core::global; use grin_core::global::ChainTypes; use grin_util::{StopState, ZeroingString}; +use grin_wallet_impls::tor::config as tor_config; +use grin_wallet_impls::tor::process as tor_process; +use grin_wallet_util::OnionV3Address; use rpassword; use std::path::PathBuf; use std::sync::Arc; @@ -74,7 +78,7 @@ fn real_main() -> Result<(), Box> { let server_config = ServerConfig { key: secp::random_secret(), interval_s: round_time.unwrap_or(DEFAULT_INTERVAL), - addr: bind_addr.unwrap_or("0.0.0.0:3000").parse()?, + addr: bind_addr.unwrap_or("127.0.0.1:3000").parse()?, grin_node_url: match grin_node_url { Some(u) => u.parse()?, None => config::grin_node_url(&chain_type), @@ -171,12 +175,15 @@ fn real_main() -> Result<(), Box> { )))?, )?; + let mut tor_process = init_tor_listener(&server_config)?; + let stop_state = Arc::new(StopState::new()); let stop_state_clone = stop_state.clone(); let rt = Runtime::new()?; rt.spawn(async move { futures::executor::block_on(build_signals_fut()); + let _ = tor_process.kill(); stop_state_clone.stop(); }); @@ -238,3 +245,39 @@ fn prompt_wallet_password(wallet_pass: &Option<&str>) -> ZeroingString { } } } + +fn init_tor_listener( + server_config: &ServerConfig, +) -> Result> { + let mut tor_dir = config::get_grin_path(&global::get_chain_type()); + tor_dir.push("tor/listener"); + + let mut torrc_dir = tor_dir.clone(); + torrc_dir.push("torrc"); + + tor_config::output_tor_listener_config( + tor_dir.to_str().unwrap(), + server_config.addr.to_string().as_str(), + &vec![server_config.key.clone()], + HashMap::new(), + HashMap::new(), + ) + .unwrap(); + + // Start TOR process + let mut process = tor_process::TorProcess::new(); + process + .torrc_path(torrc_dir.to_str().unwrap()) + .working_dir(tor_dir.to_str().unwrap()) + .timeout(20) + .completion_percent(100) + .launch() + .unwrap(); + + let onion_address = OnionV3Address::from_private(&server_config.key.0).unwrap(); + println!( + "Server listening at http://{}.onion", + onion_address.to_ov3_str() + ); + Ok(process) +} diff --git a/src/rpc.rs b/src/rpc.rs index 58bc426..c4e2c32 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -100,7 +100,6 @@ pub fn listen( }; let http_server = rpc_server.start_http(); - println!("Server listening on {}", server_config.addr); let close_handle = http_server.close_handle(); let round_handle = spawn(move || {