Optional Tor Send/Listen Functionality (#226)
* udpate for beta release * initial tor explorations * rustfmt * basic tor tx send working * rustfmt * add tor proxy info to config file * rustfmt * add utilities to output tor hidden service configuration files * output tor config as part of listener startup * rustfmt * fully automate config and startup of tor process * rustfmt * remove unnecessary process kill commands from listener * rustfmt * assume defaults for tor sending config if section doesn't exist in grin-wallet.toml * rustfmt * ignore tor dev test * update default paths output by config, compilation + confirmed working on windows * rustfmt * fix on osx/unix * add timeout to tor connector, remove unwrap in client * allow specifiying tor address without 'http://[].onion' on the command line * fix api test * rustfmt * update address derivation path as per spec * rustfmt * move tor init to separate function * rustfmt * re-ignore tor dev test * listen on tor by default if tor available * rustfmt * test fix * remove explicit send via tor flag, and assume tor if address fits * rustfmt
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
//! Grin wallet command-line function implementations
|
||||
|
||||
use crate::api::TLSConfig;
|
||||
use crate::config::{WalletConfig, WALLET_CONFIG_FILE_NAME};
|
||||
use crate::config::{TorConfig, WalletConfig, WALLET_CONFIG_FILE_NAME};
|
||||
use crate::core::{core, global};
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use crate::impls::{create_sender, KeybaseAllChannels, SlateGetter as _, SlateReceiver as _};
|
||||
@@ -75,7 +75,13 @@ where
|
||||
{
|
||||
let mut w_lock = wallet.lock();
|
||||
let p = w_lock.lc_provider()?;
|
||||
p.create_config(&g_args.chain_type, WALLET_CONFIG_FILE_NAME, None, None)?;
|
||||
p.create_config(
|
||||
&g_args.chain_type,
|
||||
WALLET_CONFIG_FILE_NAME,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)?;
|
||||
p.create_wallet(
|
||||
None,
|
||||
args.recovery_phrase,
|
||||
@@ -125,6 +131,7 @@ pub fn listen<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K>>>>,
|
||||
keychain_mask: Arc<Mutex<Option<SecretKey>>>,
|
||||
config: &WalletConfig,
|
||||
tor_config: &TorConfig,
|
||||
args: &ListenArgs,
|
||||
g_args: &GlobalArgs,
|
||||
) -> Result<(), Error>
|
||||
@@ -139,6 +146,7 @@ where
|
||||
keychain_mask,
|
||||
&config.api_listen_addr(),
|
||||
g_args.tls_conf.clone(),
|
||||
tor_config.use_tor_listener,
|
||||
),
|
||||
"keybase" => KeybaseAllChannels::new()?.listen(
|
||||
config.clone(),
|
||||
@@ -251,6 +259,7 @@ pub struct SendArgs {
|
||||
pub fn send<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
tor_config: Option<TorConfig>,
|
||||
args: SendArgs,
|
||||
dark_scheme: bool,
|
||||
) -> Result<(), Error>
|
||||
@@ -327,7 +336,7 @@ where
|
||||
})?;
|
||||
}
|
||||
method => {
|
||||
let sender = create_sender(method, &args.dest)?;
|
||||
let sender = create_sender(method, &args.dest, tor_config)?;
|
||||
slate = sender.send_tx(&slate)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
}
|
||||
@@ -514,6 +523,7 @@ pub struct ProcessInvoiceArgs {
|
||||
pub fn process_invoice<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
tor_config: Option<TorConfig>,
|
||||
args: ProcessInvoiceArgs,
|
||||
dark_scheme: bool,
|
||||
) -> Result<(), Error>
|
||||
@@ -594,7 +604,7 @@ where
|
||||
})?;
|
||||
}
|
||||
method => {
|
||||
let sender = create_sender(method, &args.dest)?;
|
||||
let sender = create_sender(method, &args.dest, tor_config)?;
|
||||
slate = sender.send_tx(&slate)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ use std::collections::HashMap;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::impls::tor::config as tor_config;
|
||||
use crate::impls::tor::process as tor_process;
|
||||
|
||||
use crate::apiwallet::{
|
||||
EncryptedRequest, EncryptedResponse, EncryptionErrorResponse, Foreign,
|
||||
ForeignCheckMiddlewareFn, ForeignRpc, Owner, OwnerRpc, OwnerRpcS,
|
||||
@@ -75,6 +78,47 @@ fn check_middleware(
|
||||
}
|
||||
}
|
||||
|
||||
/// initiate the tor listener
|
||||
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,
|
||||
) -> Result<tor_process::TorProcess, Error>
|
||||
where
|
||||
L: WalletLCProvider<'static, C, K> + 'static,
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
let mut process = tor_process::TorProcess::new();
|
||||
let mask = keychain_mask.lock();
|
||||
// eventually want to read a list of service config keys
|
||||
let mut w_lock = wallet.lock();
|
||||
let lc = w_lock.lc_provider()?;
|
||||
let w_inst = lc.wallet_inst()?;
|
||||
let k = w_inst.keychain((&mask).as_ref())?;
|
||||
let parent_key_id = w_inst.parent_key_id();
|
||||
let tor_dir = format!("{}/tor/listener", lc.get_top_level_directory()?);
|
||||
let sec_key = tor_config::address_derivation_path(&k, &parent_key_id, 0)
|
||||
.map_err(|e| ErrorKind::TorConfig(format!("{:?}", e).into()))?;
|
||||
let onion_address = tor_config::onion_address_from_seckey(&sec_key)
|
||||
.map_err(|e| ErrorKind::TorConfig(format!("{:?}", e).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()))?;
|
||||
// Start TOR process
|
||||
process
|
||||
.torrc_path(&format!("{}/torrc", tor_dir))
|
||||
.working_dir(&tor_dir)
|
||||
.timeout(20)
|
||||
.completion_percent(100)
|
||||
.launch()
|
||||
.map_err(|e| ErrorKind::TorProcess(format!("{:?}", e).into()))?;
|
||||
Ok(process)
|
||||
}
|
||||
|
||||
/// Instantiate wallet Owner API for a single-use (command line) call
|
||||
/// Return a function containing a loaded API context to call
|
||||
pub fn owner_single_use<'a, L, F, C, K>(
|
||||
@@ -188,14 +232,28 @@ pub fn foreign_listener<L, C, K>(
|
||||
keychain_mask: Arc<Mutex<Option<SecretKey>>>,
|
||||
addr: &str,
|
||||
tls_config: Option<TLSConfig>,
|
||||
use_tor: bool,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
L: WalletLCProvider<'static, C, K> + 'static,
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
let api_handler_v2 = ForeignAPIHandlerV2::new(wallet, keychain_mask);
|
||||
// need to keep in scope while the main listener is running
|
||||
let _tor_process = match use_tor {
|
||||
true => match init_tor_listener(wallet.clone(), keychain_mask.clone(), addr) {
|
||||
Ok(tp) => Some(tp),
|
||||
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
|
||||
}
|
||||
},
|
||||
false => None,
|
||||
};
|
||||
|
||||
let api_handler_v2 = ForeignAPIHandlerV2::new(wallet, keychain_mask);
|
||||
let mut router = Router::new();
|
||||
|
||||
router
|
||||
@@ -210,6 +268,7 @@ where
|
||||
.context(ErrorKind::GenericError(
|
||||
"API thread failed to start".to_string(),
|
||||
))?;
|
||||
|
||||
warn!("HTTP Foreign listener started.");
|
||||
|
||||
api_thread
|
||||
@@ -679,7 +738,7 @@ where
|
||||
Box::new(parse_body(req).and_then(move |val: serde_json::Value| {
|
||||
let foreign_api = &api as &dyn ForeignRpc;
|
||||
match foreign_api.handle_request(val) {
|
||||
MaybeReply::Reply(r) => ok(r),
|
||||
MaybeReply::Reply(r) => ok({ r }),
|
||||
MaybeReply::DontReply => {
|
||||
// Since it's http, we need to return something. We return [] because jsonrpc
|
||||
// clients will parse it as an empty batch response.
|
||||
|
||||
Reference in New Issue
Block a user