stackmate/network/
tor.rs

1use std::io::{ Write};
2use std::io::{BufReader, BufRead};
3use std::net::TcpStream;
4use std::str;
5use std::path::Path;
6
7// use std::thread::JoinHandle;
8use crate::e::{ErrorKind, S5Error};
9
10use libtor::{Tor,TorFlag,log};
11
12use sha1::{Sha1, Digest};
13
14use bitcoin::secp256k1::rand::prelude::thread_rng;
15use bitcoin::secp256k1::rand::Rng;
16
17
18fn _tor_salted_password_hash(password: &str)->String{{
19  let salt = thread_rng().gen::<[u8; 8]>().to_vec();
20  let salt_hex = hex::encode(salt);
21  let to_hash = salt_hex.clone() + password;
22
23  let mut hasher = Sha1::new();
24  hasher.update(to_hash.as_bytes());
25  let hashed_password = hasher.finalize();
26  let mut hashed_password_hex = hex::encode(&hashed_password);
27  hashed_password_hex.insert_str(0, &salt_hex);
28  hashed_password_hex.insert_str(0, "16:");
29  hashed_password_hex
30}}
31
32
33pub fn start(tmp_path: &str) -> String {
34  let tmp_path = Path::new(tmp_path);
35  let exists = tmp_path.exists();
36  let tmp_path = if exists {
37    tmp_path.join("tor-rust")
38  } else {
39    eprintln!("Bad base path! using /tmp");
40    Path::new("/tmp/tor-rust").to_path_buf()
41  };
42    
43  // let control_key = aes::keygen();
44  // let _hash = tor_salted_password_hash(&control_key);
45
46  Tor::new()
47    .flag(TorFlag::DataDirectory(tmp_path.to_string_lossy().to_string()))
48    .flag(TorFlag::SocksPort(19050))
49    .flag(TorFlag::ControlPort(9000))
50    .flag(TorFlag::LogTo(log::LogLevel::Err,log::LogDestination::Stderr))
51    // .flag(TorFlag::HashedControlPassword(hash))
52    // .flag(TorFlag::HiddenServiceDir("/tmp/tor-rust/hs-dir".into()))
53    // .flag(TorFlag::HiddenServiceVersion(HiddenServiceVersion::V3))
54    // .flag(TorFlag::HiddenServicePort(
55    //   TorAddress::Port(8000),
56    //   None.into(),
57    // ))
58    .start_background();
59  "control_key".to_string()
60}
61
62pub fn bootstrap_progress(_control_key: &str) -> Result<usize, S5Error> {
63  let mut stream = match TcpStream::connect("127.0.0.1:9000") {
64    Ok(result) => result,
65    Err(_) => {
66      return Err(S5Error::new(
67        ErrorKind::Network,
68        "Could not connect to tor daemon.",
69      ))
70    }
71  };
72  // stream
73  //   .set_read_timeout(Some(Duration::from_millis(3000)))
74  //   .unwrap();
75  let _result = stream.write(b"AUTHENTICATE ").unwrap();
76  // let _result = stream.write(control_key.as_bytes()).unwrap();
77  let _result = stream.write(b"\r\n").unwrap();
78  let _result = stream.write(b"GETINFO status/bootstrap-phase").unwrap();
79  let _result = stream.write(b"\r\n").unwrap();
80
81  let mut reader = BufReader::new(&mut stream);
82  let received: Vec<u8> = reader.fill_buf().unwrap().to_vec();
83  // Mark the bytes read as consumed so the buffer will not return them in a subsequent read
84  reader.consume(received.len());
85
86  let response_string = str::from_utf8(&received).unwrap().to_string();
87  stream.flush().unwrap();
88  let parts = response_string.split("\r\n").collect::<Vec<&str>>();
89  println!("{:?}", parts[1]);
90  let progress = if !parts[1].is_empty() {parts[1].split(' ').collect::<Vec<&str>>()[2]}else{"PROGRESS=101"};
91  // let tag = parts[1].split(" ").collect::<Vec<&str>>()[3];
92  // let summary = parts[1].split(" ").collect::<Vec<&str>>()[4];
93  let progress_value = progress.split('=').collect::<Vec<&str>>()[1].parse::<usize>().unwrap_or(101);
94  println!("PV:{:?}", progress_value);
95  Ok(progress_value)
96}
97
98pub fn circuit_established(_control_key: &str) -> Result<bool, S5Error> {
99  let mut stream = match TcpStream::connect("127.0.0.1:9000") {
100    Ok(result) => result,
101    Err(_) => {
102      return Err(S5Error::new(
103        ErrorKind::Network,
104        "Could not connect to tor daemon.",
105      ))
106    }
107  };
108  // stream
109  //   .set_read_timeout(Some(Duration::from_millis(3000)))
110  //   .unwrap();
111  let _result = stream.write(b"AUTHENTICATE ").unwrap();
112  // let _result = stream.write(control_key.as_bytes()).unwrap();
113  let _result = stream.write(b"\r\n").unwrap();
114  let _result = stream.write(b"GETINFO status/circuit-established").unwrap();
115  let _result = stream.write(b"\r\n").unwrap();
116
117  let mut reader = BufReader::new(&mut stream);
118  let received: Vec<u8> = reader.fill_buf().unwrap().to_vec();
119  // Mark the bytes read as consumed so the buffer will not return them in a subsequent read
120  reader.consume(received.len());
121
122  let response_str = str::from_utf8(&received).unwrap();
123  Ok(response_str.contains("circuit-established=1"))
124}
125
126pub fn shutdown(_control_key: &str) -> Result<bool, S5Error> {
127  let mut stream = match TcpStream::connect("127.0.0.1:9000") {
128    Ok(result) => result,
129    Err(_) => {
130      return Err(S5Error::new(
131        ErrorKind::Network,
132        "Could not connect to tor daemon.",
133      ))
134    }
135  };
136
137  let _result = stream.write(b"AUTHENTICATE ").unwrap();
138  // let _result = stream.write(control_key.as_bytes()).unwrap();
139  let _result = stream.write(b"\r\n").unwrap();
140  let _result = stream.flush().unwrap();
141  let _result = stream.write(b"SIGNAL SHUTDOWN").unwrap();
142  let _result = stream.write(b"\r\n").unwrap();
143
144  let mut reader = BufReader::new(&mut stream);
145  let received: Vec<u8> = reader.fill_buf().unwrap().to_vec();
146  // Mark the bytes read as consumed so the buffer will not return them in a subsequent read
147  reader.consume(received.len());
148
149  let response_str = str::from_utf8(&received).unwrap();
150  Ok(response_str.contains("250 OK\r\n"))
151}
152
153#[cfg(test)]
154mod tests {
155  use super::*;
156  use crate::config::{WalletConfig, DEFAULT_MAINNET_NODE};
157  use crate::network::fees;
158  use std::thread::sleep;
159  use std::time;
160  /// This test might require more than 10 seconds of sleep duration if running for the first time.
161  /// Default uses 4 sleep cycles in total for CI. Comment out the last 2 if you have run this before locally.
162  #[test] #[ignore]
163  fn test_tor() {
164    let control_key = start("/tmp");
165    // handle.join().unwrap();
166
167    let duration = time::Duration::from_secs(1);
168    
169    sleep(duration);
170    sleep(duration);
171
172    println!("{:#?}", bootstrap_progress(&control_key).unwrap());
173    
174    sleep(duration);
175    println!("{:#?}", bootstrap_progress(&control_key).unwrap());
176
177    sleep(duration);
178    println!("{:#?}", bootstrap_progress(&control_key).unwrap());
179
180    sleep(duration);
181    println!("{:#?}", bootstrap_progress(&control_key).unwrap());
182
183    sleep(duration);
184    println!("{:#?}", bootstrap_progress(&control_key).unwrap());
185
186    sleep(duration);
187    println!("{:#?}", bootstrap_progress(&control_key).unwrap());
188
189    let deposit_desc = "/0/*";
190    let config = WalletConfig::new(
191      deposit_desc,
192      DEFAULT_MAINNET_NODE,
193      Some("127.0.0.1:19050".to_string()),
194    )
195    .unwrap();
196    let fees = fees::estimate_rate(config, 6).unwrap();
197    assert!(fees.rate > 0.1);
198
199    assert!( circuit_established(&control_key).unwrap());
200    assert!(shutdown(&control_key).unwrap());
201  }
202}