Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TOR bridge + TOR Proxy + migration config_file_version #617

Merged
Merged
9 changes: 7 additions & 2 deletions api/src/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2369,6 +2369,7 @@ pub fn try_slatepack_sync_workflow(
&tor_addr.to_http_str(),
&tor_config.as_ref().unwrap().socks_proxy_addr,
&tor_config.as_ref().unwrap().send_config_dir,
&tor_config.as_ref().unwrap().bridge_line,
) {
Ok(s) => Some(s),
Err(e) => {
Expand All @@ -2391,8 +2392,12 @@ pub fn try_slatepack_sync_workflow(
match send_sync(s, "TOR") {
Ok(_) => return Ok(Some(ret_slate)),
Err(e) => {
debug!("Unable to send via TOR: {}", e);
warn!("Unable to send transaction via TOR");
if !tor_config.as_ref().unwrap().bridge_line.is_empty() {
warn!("Unable to send via TOR: {}", e);
} else {
debug!("Unable to send via TOR: {}", e);
warn!("Unable to send transaction via TOR");
}
}
}
}
Expand Down
19 changes: 15 additions & 4 deletions config/src/comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ use std::collections::HashMap;
fn comments() -> HashMap<String, String> {
let mut retval = HashMap::new();

retval.insert(
"config_file_version".to_string(),
"
#Version of the Generated Configuration File for Grin Wallet
"
.to_string(),
);

retval.insert(
"[wallet]".to_string(),
"
Expand Down Expand Up @@ -215,17 +223,20 @@ fn comments() -> HashMap<String, String> {
);

retval.insert(
"socks_proxy_addr".to_string(),
"send_config_dir".to_string(),
"
# TOR (SOCKS) proxy server address
#Directory to output TOR configuration to when sending
"
.to_string(),
);

retval.insert(
"send_config_dir".to_string(),
"bridge_line".to_string(),
"
#Directory to output TOR configuration to when sending
#TOR Bridge relays: Make possible to send and receive via TOR in a country where it is censored.
#Enable it by entering a single bridge line. To disable it, you must let it empty or comment it.
#Obfs4proxy binary must be installed and in the path.
#Bridge line must be in the following format: `obfs4 [IP:PORT] [FINGERPRINT] cert=[CERT] iat-mode=[IAT-MODE]`
"
.to_string(),
);
Expand Down
39 changes: 34 additions & 5 deletions config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::BufReader;
use std::io::Read;
use std::path::PathBuf;
use toml;

Expand Down Expand Up @@ -187,6 +186,7 @@ pub fn initial_setup_wallet(
impl Default for GlobalWalletConfigMembers {
fn default() -> GlobalWalletConfigMembers {
GlobalWalletConfigMembers {
config_file_version: Some(2),
logging: Some(LoggingConfig::default()),
tor: Some(TorConfig::default()),
wallet: WalletConfig::default(),
Expand Down Expand Up @@ -245,10 +245,13 @@ impl GlobalWalletConfig {

/// Read config
fn read_config(mut self) -> Result<GlobalWalletConfig, ConfigError> {
let mut file = File::open(self.config_file_path.as_mut().unwrap())?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let fixed = GlobalWalletConfig::fix_warning_level(contents);
let config_file_path = self.config_file_path.as_mut().unwrap();
let contents = fs::read_to_string(config_file_path.clone())?;
let migrated = GlobalWalletConfig::migrate_config_file_version_none_to_2(
contents,
config_file_path.to_owned(),
)?;
let fixed = GlobalWalletConfig::fix_warning_level(migrated);
let decoded: Result<GlobalWalletConfigMembers, toml::de::Error> = toml::from_str(&fixed);
match decoded {
Ok(gc) => {
Expand Down Expand Up @@ -314,6 +317,32 @@ impl GlobalWalletConfig {
file.write_all(commented_config.as_bytes())?;
Ok(())
}
/// This migration does the following:
/// - Adds "config_file_version = 2"
/// - Adds bridge_line = ""
/// - Migrate old config field/value to a new config file with missing new field/value
fn migrate_config_file_version_none_to_2(
config_str: String,
config_file_path: PathBuf,
) -> Result<String, ConfigError> {
let config: GlobalWalletConfigMembers =
toml::from_str(&GlobalWalletConfig::fix_warning_level(config_str.clone())).unwrap();
if config.config_file_version != None {
return Ok(config_str);
}
let adjusted_config = GlobalWalletConfigMembers {
config_file_version: GlobalWalletConfigMembers::default().config_file_version,
..config
};
let mut gc = GlobalWalletConfig {
members: Some(adjusted_config),
config_file_path: Some(config_file_path.clone()),
};
let str_path = config_file_path.into_os_string().into_string().unwrap();
gc.write_to_file(&str_path)?;
let adjusted_config_str = fs::read_to_string(str_path.clone())?;
Ok(adjusted_config_str)
}

// For forwards compatibility old config needs `Warning` log level changed to standard log::Level `WARN`
fn fix_warning_level(conf: String) -> String {
Expand Down
7 changes: 7 additions & 0 deletions config/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ pub struct TorConfig {
pub socks_proxy_addr: String,
/// Send configuration directory
pub send_config_dir: String,
/// Send configuration directory
#[serde(default)]
pub bridge_line: String,
}

impl Default for TorConfig {
Expand All @@ -173,6 +176,7 @@ impl Default for TorConfig {
use_tor_listener: true,
socks_proxy_addr: "127.0.0.1:59050".to_owned(),
send_config_dir: ".".into(),
bridge_line: "".to_string(),
}
}
}
Expand All @@ -197,6 +201,9 @@ pub struct GlobalWalletConfig {
/// Wallet internal members
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct GlobalWalletConfigMembers {
/// Config file version (None == version 1)
#[serde(default)]
pub config_file_version: Option<u32>,
/// Wallet configuration
#[serde(default)]
pub wallet: WalletConfig,
Expand Down
2 changes: 2 additions & 0 deletions controller/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ pub struct SendArgs {
pub ttl_blocks: Option<u64>,
pub skip_tor: bool,
pub outfile: Option<String>,
pub bridge: String,
}

pub fn send<L, C, K>(
Expand Down Expand Up @@ -338,6 +339,7 @@ where

let tor_config = match tor_config {
Some(mut c) => {
c.bridge_line = args.bridge.clone();
c.skip_send_attempt = Some(args.skip_tor);
Some(c)
}
Expand Down
41 changes: 31 additions & 10 deletions controller/src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ fn init_tor_listener<L, C, K>(
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K> + 'static>>>,
keychain_mask: Arc<Mutex<Option<SecretKey>>>,
addr: &str,
bridge_line: &str,
) -> Result<(tor_process::TorProcess, SlatepackAddress), Error>
where
L: WalletLCProvider<'static, C, K> + 'static,
Expand All @@ -103,12 +104,26 @@ where
let onion_address = OnionV3Address::from_private(&sec_key.0)
.map_err(|e| ErrorKind::TorConfig(format!("{:?}", e).into()))?;
let sp_address = SlatepackAddress::try_from(onion_address.clone())?;
let mut obfs4proxy_path = "".to_string();
if !bridge_line.is_empty() {
warn!("TOR Bridge relay configured");
tor_config::check_bridge_line(bridge_line)
.map_err(|e| ErrorKind::TorConfig(format!("{}", e.inner).into()))?;
obfs4proxy_path = tor_config::is_obfs4proxy_in_path()
.map_err(|e| ErrorKind::TorConfig(format!("{}", e.inner).into()))?;
}
warn!(
"Starting TOR Hidden Service for API listener at address {}, binding to {}",
onion_address, addr
);
tor_config::output_tor_listener_config(&tor_dir, addr, &vec![sec_key])
.map_err(|e| ErrorKind::TorConfig(format!("{:?}", e).into()))?;
tor_config::output_tor_listener_config(
&tor_dir,
addr,
&vec![sec_key],
bridge_line,
&obfs4proxy_path,
)
.map_err(|e| ErrorKind::TorConfig(format!("{:?}", e).into()))?;
// Start TOR process
process
.torrc_path(&format!("{}/torrc", tor_dir))
Expand Down Expand Up @@ -266,17 +281,23 @@ where
let lc = w_lock.lc_provider()?;
let _ = lc.wallet_inst()?;
}
let bridge_line = match tor_config.clone() {
Some(s) => s.bridge_line,
None => "".to_string(),
};
// need to keep in scope while the main listener is running
let (_tor_process, address) = match use_tor {
true => match init_tor_listener(wallet.clone(), keychain_mask.clone(), addr) {
Ok((tp, addr)) => (Some(tp), Some(addr)),
Err(e) => {
warn!("Unable to start TOR listener; Check that TOR executable is installed and on your path");
warn!("Tor Error: {}", e);
warn!("Listener will be available via HTTP only");
(None, None)
true => {
match init_tor_listener(wallet.clone(), keychain_mask.clone(), addr, &bridge_line) {
Ok((tp, addr)) => (Some(tp), Some(addr)),
Err(e) => {
warn!("Unable to start TOR listener; Check that TOR executable is installed and on your path");
error!("Tor Error: {}", e);
warn!("Listener will be available via HTTP only");
(None, None)
}
}
},
}
false => (None, None),
};

Expand Down
14 changes: 14 additions & 0 deletions impls/src/adapters/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub struct HttpSlateSender {
socks_proxy_addr: Option<SocketAddr>,
tor_config_dir: String,
process: Option<Arc<tor_process::TorProcess>>,
bridge_line: String,
}

impl HttpSlateSender {
Expand All @@ -49,6 +50,7 @@ impl HttpSlateSender {
socks_proxy_addr: None,
tor_config_dir: String::from(""),
process: None,
bridge_line: String::from(""),
})
}
}
Expand All @@ -58,12 +60,14 @@ impl HttpSlateSender {
base_url: &str,
proxy_addr: &str,
tor_config_dir: &str,
bridge_line: &str,
) -> Result<HttpSlateSender, SchemeNotHttp> {
let mut ret = Self::new(base_url)?;
ret.use_socks = true;
//TODO: Unwrap
ret.socks_proxy_addr = Some(SocketAddr::V4(proxy_addr.parse().unwrap()));
ret.tor_config_dir = tor_config_dir.into();
ret.bridge_line = bridge_line.into();
Ok(ret)
}

Expand All @@ -80,9 +84,19 @@ impl HttpSlateSender {
"Starting TOR Process for send at {:?}",
self.socks_proxy_addr
);
let mut obfs4proxy_path = "".to_string();
if !self.bridge_line.is_empty() {
warn!("TOR Bridge relay configured");
tor_config::check_bridge_line(&self.bridge_line)
.map_err(|e| ErrorKind::TorConfig(format!("{}", e.inner).into()))?;
obfs4proxy_path = tor_config::is_obfs4proxy_in_path()
.map_err(|e| ErrorKind::TorConfig(format!("{}", e.inner).into()))?;
}
tor_config::output_tor_sender_config(
&tor_dir,
&self.socks_proxy_addr.unwrap().to_string(),
&self.bridge_line,
&obfs4proxy_path,
)
.map_err(|e| ErrorKind::TorConfig(format!("{:?}", e)))?;
// Start TOR process
Expand Down
8 changes: 8 additions & 0 deletions impls/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ pub enum ErrorKind {
#[fail(display = "Onion V3 Address Error")]
OnionV3Address(OnionV3AddressError),

/// Error when obfs4proxy is not in the user path if TOR brigde is enabled
#[fail(display = "Unable to find obfs4proxy binary in your path; {}", _0)]
Obfs4proxyBin(String),

/// Error the bridge input is in bad format
#[fail(display = "Bridge line is in bad format; {}", _0)]
BridgeLine(String),

/// Error when formatting json
#[fail(display = "IO error")]
IO,
Expand Down
5 changes: 5 additions & 0 deletions impls/src/lifecycle/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ where
tor_config: Option<TorConfig>,
) -> Result<(), Error> {
let mut default_config = GlobalWalletConfig::for_chain(&chain_type);
let config_file_version = match default_config.members.as_ref() {
Some(m) => m.clone().config_file_version,
None => None,
};
let logging = match logging_config {
Some(l) => Some(l),
None => match default_config.members.as_ref() {
Expand All @@ -102,6 +106,7 @@ where
};
default_config = GlobalWalletConfig {
members: Some(GlobalWalletConfigMembers {
config_file_version,
wallet,
tor,
logging,
Expand Down
Loading