From 7761ff181c57faa4a2df1ae3e0b5cee087e798f5 Mon Sep 17 00:00:00 2001
From: TheCharlatan <seb.kung@gmail.com>
Date: Tue, 27 Dec 2022 16:01:34 +0100
Subject: [PATCH] Farcasterd: Add config for Tor hidden service creation

---
 src/config.rs                         | 33 +++++++++++++++++++++++++++
 src/farcasterd/runtime.rs             |  3 +--
 src/farcasterd/trade_state_machine.rs | 16 +++++++++++--
 3 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/src/config.rs b/src/config.rs
index 079a654d4..4f2b830cd 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -139,6 +139,32 @@ impl Config {
         }
     }
 
+    /// Returns the addr of the tor control socket if it is set, or the default
+    /// socket at localhost:9051 if not.
+    pub fn get_tor_control_socket(&self) -> Result<InetSocketAddr, Error> {
+        if let Some(FarcasterdConfig {
+            tor_control_socket: Some(addr),
+            ..
+        }) = &self.farcasterd
+        {
+            Ok(InetSocketAddr::from_str(addr)?)
+        } else {
+            Ok(InetSocketAddr::from_str("127.0.0.1:9051")?)
+        }
+    }
+
+    pub fn create_hidden_service(&self) -> bool {
+        if let Some(FarcasterdConfig {
+            create_hidden_service: Some(create_hidden_service),
+            ..
+        }) = &self.farcasterd
+        {
+            *create_hidden_service
+        } else {
+            false
+        }
+    }
+
     /// Returns the swap config for the specified network and arbitrating/accordant blockchains
     pub fn get_swap_config(
         &self,
@@ -230,6 +256,11 @@ pub struct FarcasterdConfig {
     pub bind_ip: Option<String>,
     /// Whether checkpoints should be auto restored at start-up, or not
     pub auto_restore: Option<bool>,
+    /// Tor control socket for creating the hidden service
+    pub tor_control_socket: Option<String>,
+    /// Whether to create a hidden service or not. If set, the node will only
+    /// run in hidden service mode
+    pub create_hidden_service: Option<bool>,
 }
 
 #[derive(Deserialize, Serialize, Debug, Clone)]
@@ -432,6 +463,8 @@ impl Default for FarcasterdConfig {
             // write the default port and ip in the generated config
             bind_port: Some(FARCASTER_BIND_PORT),
             bind_ip: Some(FARCASTER_BIND_IP.to_string()),
+            tor_control_socket: None,
+            create_hidden_service: None,
         }
     }
 }
diff --git a/src/farcasterd/runtime.rs b/src/farcasterd/runtime.rs
index ead9d1294..7860c8c26 100644
--- a/src/farcasterd/runtime.rs
+++ b/src/farcasterd/runtime.rs
@@ -1134,7 +1134,6 @@ impl Runtime {
         endpoints: &mut Endpoints,
         bind_addr: InetSocketAddr,
         public_port: u16,
-        tor_control_socket: InetSocketAddr,
     ) -> Result<(InetSocketAddr, NodeId), Error> {
         self.services_ready()?;
         let (peer_secret_key, peer_public_key) = self.peer_keys_ready()?;
@@ -1165,7 +1164,7 @@ impl Runtime {
         let public_onion_address = create_v3_onion_service(
             bind_addr,
             public_port,
-            tor_control_socket,
+            self.config.get_tor_control_socket()?,
             &self.old_hidden_services,
         )
         .unwrap();
diff --git a/src/farcasterd/trade_state_machine.rs b/src/farcasterd/trade_state_machine.rs
index 3f0c04e5c..6133d6ba6 100644
--- a/src/farcasterd/trade_state_machine.rs
+++ b/src/farcasterd/trade_state_machine.rs
@@ -459,7 +459,19 @@ fn attempt_transition_to_make_deal(
                 }
                 Ok(bind_addr) => bind_addr,
             };
-            match runtime.listen(bind_addr) {
+            let res = if runtime.config.create_hidden_service() {
+                runtime.listen_tor(
+                    event.endpoints,
+                    bind_addr,
+                    public_addr.port().ok_or(Error::Farcaster(
+                        "Cannot combine create hidden service with passed in Tor public address"
+                            .to_string(),
+                    ))?,
+                )
+            } else {
+                runtime.listen(bind_addr).map(|n| (public_addr, n))
+            };
+            match res {
                 Err(err) => {
                     warn!("Failed to start peerd listen, cannot make deal: {}", err);
                     event.complete_client_ctl(CtlMsg::Failure(Failure {
@@ -468,7 +480,7 @@ fn attempt_transition_to_make_deal(
                     }))?;
                     Ok(None)
                 }
-                Ok(node_id) => {
+                Ok((public_addr, node_id)) => {
                     let deal = deal_parameters.to_v1(node_id.public_key(), public_addr);
                     let msg = s!("Deal registered, please share with taker.");
                     info!(