mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-10-17 15:21:39 +02:00
Integrated Tor arti Client (#750)
* tor: integrated client for listener, update tokio to last version * tor: send transaction with integrated client * build: code format * tor: optimize bootstrap percent check * tor: handle config build error * tor: do not show slatepack address if tor not launched * tor: handle keystore errors * tor: keep service launched * tor: bootstrap timeout, clean cache before client launch * tor: post request timeout * fix: post timeout * build: update deps after merge * tor: store arti runtime * tor: do not send over tor if `manual` arg presents or `skip_send_attempt` set at config * fix: arg name * tor: handle arti runtime creation error * tor: handle connection error * tor: handle bootstrap error * tor: handle start service name error * tor: handle service config creation error * tor: service proxy errors * tor: handle service key creation emptiness * build: format code * build: update arti to 0.43, hyper to 0.10.1 * api: start foreign listener before tor connection * tor: handle json parse errors * tor: prevent to create several client runtimes, ability to recreate * tor: return bootstrap error * tor: handle host parse error * tor: restart proxy on error * tor: do not use integrated client when config value use_integrated is missing, add logging * build: update lock file
This commit is contained in:
@@ -224,7 +224,7 @@ where
|
||||
g_args.tls_conf.clone(),
|
||||
tor_config.use_tor_listener,
|
||||
test_mode,
|
||||
Some(tor_config.clone()),
|
||||
tor_config,
|
||||
);
|
||||
if let Err(e) = res {
|
||||
error!("Error starting listener: {}", e);
|
||||
@@ -335,7 +335,7 @@ pub struct SendArgs {
|
||||
pub target_slate_version: Option<u16>,
|
||||
pub payment_proof_address: Option<SlatepackAddress>,
|
||||
pub ttl_blocks: Option<u64>,
|
||||
pub skip_tor: bool,
|
||||
pub skip_tor: Option<bool>,
|
||||
pub outfile: Option<String>,
|
||||
pub bridge: Option<String>,
|
||||
pub slatepack_qr: bool,
|
||||
@@ -431,7 +431,9 @@ where
|
||||
if let Some(b) = args.bridge.clone() {
|
||||
c.bridge.bridge_line = Some(b);
|
||||
}
|
||||
c.skip_send_attempt = Some(args.skip_tor);
|
||||
if let Some(s) = args.skip_tor {
|
||||
c.skip_send_attempt = Some(s);
|
||||
}
|
||||
Some(c)
|
||||
}
|
||||
None => None,
|
||||
@@ -630,7 +632,7 @@ where
|
||||
pub struct ReceiveArgs {
|
||||
pub input_file: Option<String>,
|
||||
pub input_slatepack_message: Option<String>,
|
||||
pub skip_tor: bool,
|
||||
pub skip_tor: Option<bool>,
|
||||
pub outfile: Option<String>,
|
||||
pub bridge: Option<String>,
|
||||
pub slatepack_qr: bool,
|
||||
@@ -666,7 +668,9 @@ where
|
||||
if let Some(b) = args.bridge {
|
||||
c.bridge.bridge_line = Some(b);
|
||||
}
|
||||
c.skip_send_attempt = Some(args.skip_tor);
|
||||
if let Some(s) = args.skip_tor {
|
||||
c.skip_send_attempt = Some(s);
|
||||
}
|
||||
Some(c)
|
||||
}
|
||||
None => None,
|
||||
@@ -688,7 +692,7 @@ where
|
||||
Ok(Some(_)) => {
|
||||
println!();
|
||||
println!(
|
||||
"Transaction recieved and sent back to sender at {} for finalization.",
|
||||
"Transaction received and sent back to sender at {} for finalization.",
|
||||
dest
|
||||
);
|
||||
println!();
|
||||
@@ -925,7 +929,7 @@ pub struct ProcessInvoiceArgs {
|
||||
pub slate: Slate,
|
||||
pub estimate_selection_strategies: bool,
|
||||
pub ttl_blocks: Option<u64>,
|
||||
pub skip_tor: bool,
|
||||
pub skip_tor: Option<bool>,
|
||||
pub outfile: Option<String>,
|
||||
pub bridge: Option<String>,
|
||||
pub slatepack_qr: bool,
|
||||
@@ -1008,7 +1012,9 @@ where
|
||||
if let Some(b) = args.bridge {
|
||||
c.bridge.bridge_line = Some(b);
|
||||
}
|
||||
c.skip_send_attempt = Some(args.skip_tor);
|
||||
if let Some(skip_tor) = args.skip_tor {
|
||||
c.skip_send_attempt = Some(skip_tor);
|
||||
}
|
||||
Some(c)
|
||||
}
|
||||
None => None,
|
||||
|
||||
@@ -48,6 +48,8 @@ use crate::apiwallet::{
|
||||
};
|
||||
use easy_jsonrpc_mw;
|
||||
use easy_jsonrpc_mw::{Handler, MaybeReply};
|
||||
use grin_wallet_impls::tor::arti::start_tor_service;
|
||||
use grin_wallet_impls::tor::Tor;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref GRIN_OWNER_BASIC_REALM: HeaderValue =
|
||||
@@ -82,32 +84,16 @@ 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>>>,
|
||||
fn init_tor_listener(
|
||||
sec_key: SecretKey,
|
||||
tor_dir: String,
|
||||
addr: &str,
|
||||
bridge: TorBridgeConfig,
|
||||
tor_proxy: TorProxyConfig,
|
||||
) -> Result<(tor_process::TorProcess, SlatepackAddress), Error>
|
||||
where
|
||||
L: WalletLCProvider<'static, C, K> + 'static,
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
) -> Result<Tor, Error> {
|
||||
info!("Starting external Tor Process listener.");
|
||||
|
||||
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 = address::address_from_derivation_path(&k, &parent_key_id, 0)
|
||||
.map_err(|e| Error::TorConfig(format!("{:?}", e)))?;
|
||||
let onion_address = OnionV3Address::from_private(&sec_key.0)
|
||||
.map_err(|e| Error::TorConfig(format!("{:?}", e)))?;
|
||||
let sp_address = SlatepackAddress::try_from(onion_address.clone())?;
|
||||
|
||||
let mut hm_tor_bridge: HashMap<String, String> = HashMap::new();
|
||||
let mut tor_timeout = 20;
|
||||
@@ -129,10 +115,6 @@ where
|
||||
.map_err(|e| Error::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,
|
||||
@@ -149,7 +131,11 @@ where
|
||||
.completion_percent(100)
|
||||
.launch()
|
||||
.map_err(|e| Error::TorProcess(format!("{:?}", e)))?;
|
||||
Ok((process, sp_address))
|
||||
Ok(Tor {
|
||||
process: Some(process),
|
||||
service: None,
|
||||
client: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Instantiate wallet Owner API for a single-use (command line) call
|
||||
@@ -285,7 +271,7 @@ pub fn foreign_listener<L, C, K>(
|
||||
tls_config: Option<TLSConfig>,
|
||||
use_tor: bool,
|
||||
test_mode: bool,
|
||||
tor_config: Option<TorConfig>,
|
||||
tor_config: TorConfig,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
L: WalletLCProvider<'static, C, K> + 'static,
|
||||
@@ -293,41 +279,27 @@ where
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
// Check if wallet has been opened first
|
||||
{
|
||||
let (sec_key, tor_dir, onion_address) = {
|
||||
let mask = keychain_mask.lock();
|
||||
let mut w_lock = wallet.lock();
|
||||
let lc = w_lock.lc_provider()?;
|
||||
let _ = lc.wallet_inst()?;
|
||||
}
|
||||
|
||||
let (tor_bridge, tor_proxy) = match tor_config.clone() {
|
||||
Some(s) => (s.bridge, s.proxy),
|
||||
None => (TorBridgeConfig::default(), TorProxyConfig::default()),
|
||||
let w_inst = lc.wallet_inst()?;
|
||||
let k = w_inst.keychain((&mask).as_ref())?;
|
||||
let parent_key_id = w_inst.parent_key_id();
|
||||
let sec_key = address::address_from_derivation_path(&k, &parent_key_id, 0)
|
||||
.map_err(|e| Error::TorConfig(format!("{:?}", e)))?;
|
||||
let tor_dir = format!("{}/tor/listener", lc.get_top_level_directory()?);
|
||||
let onion_address = OnionV3Address::from_private(&sec_key.0)
|
||||
.map_err(|e| Error::TorConfig(format!("{:?}", e)))?;
|
||||
(sec_key, tor_dir, onion_address)
|
||||
};
|
||||
|
||||
// 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,
|
||||
tor_bridge,
|
||||
tor_proxy,
|
||||
) {
|
||||
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),
|
||||
};
|
||||
|
||||
let api_handler_v2 =
|
||||
ForeignAPIHandlerV2::new(wallet, keychain_mask, test_mode, Mutex::new(tor_config));
|
||||
let api_handler_v2 = ForeignAPIHandlerV2::new(
|
||||
wallet,
|
||||
keychain_mask,
|
||||
test_mode,
|
||||
Mutex::new(Some(tor_config.clone())),
|
||||
);
|
||||
let mut router = Router::new();
|
||||
|
||||
router
|
||||
@@ -343,14 +315,52 @@ where
|
||||
let api_thread = apis
|
||||
.start(socket_addr, router, tls_config, api_chan)
|
||||
.map_err(|_| Error::GenericError("API thread failed to start".to_string()))?;
|
||||
|
||||
warn!("HTTP Foreign listener started.");
|
||||
if let Some(a) = address {
|
||||
let qr_string = match QrCode::new(a.to_string()) {
|
||||
Ok(qr) => qr.to_string(false, 3),
|
||||
Err(_) => "Failed to generate QR code!".to_string(),
|
||||
|
||||
// Need to keep external process in scope while the listener is running.
|
||||
let tor_service = if use_tor {
|
||||
let use_integrated = tor_config.use_integrated.unwrap_or(false);
|
||||
let res = if use_integrated {
|
||||
start_tor_service(sec_key, &tor_dir, addr, tor_config.clone())
|
||||
} else {
|
||||
init_tor_listener(
|
||||
sec_key,
|
||||
tor_dir,
|
||||
addr,
|
||||
tor_config.bridge.clone(),
|
||||
tor_config.proxy.clone(),
|
||||
)
|
||||
};
|
||||
warn!("Slatepack Address is: {}\n{}", a, qr_string);
|
||||
match res {
|
||||
Ok(service) => {
|
||||
warn!(
|
||||
"Starting Tor Hidden Service for API listener at address {}, binding to {}",
|
||||
onion_address, addr
|
||||
);
|
||||
Ok(Some(service))
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Unable to start TOR listener");
|
||||
error!("Tor Error: {}", e);
|
||||
warn!("Listener is available on {}", addr);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
};
|
||||
|
||||
if tor_service.is_ok() {
|
||||
if let Some(_) = tor_service.as_ref().unwrap() {
|
||||
let sp_address = SlatepackAddress::try_from(onion_address.clone())?;
|
||||
let qr_string = match QrCode::new(sp_address.to_string()) {
|
||||
Ok(qr) => qr.to_string(false, 3),
|
||||
Err(_) => "Failed to generate QR code!".to_string(),
|
||||
};
|
||||
warn!("Slatepack Address is: {}\n{}", sp_address, qr_string);
|
||||
} else {
|
||||
warn!("Listener is available on {}", addr);
|
||||
}
|
||||
}
|
||||
|
||||
api_thread
|
||||
|
||||
Reference in New Issue
Block a user