diff --git a/p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java b/p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java index 9f696e733c1..82e26947209 100644 --- a/p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java +++ b/p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java @@ -53,7 +53,7 @@ public NetworkNodeProvider(NetworkProtoResolver networkProtoResolver, @Named(NetworkOptionKeys.EXTERNAL_TOR_USE_SAFECOOKIE) boolean useSafeCookieAuthentication ) { networkNode = useLocalhostForP2P ? new LocalhostNetworkNode(address, port, networkProtoResolver) : - new TorNetworkNode(port, torDir, networkProtoResolver, + new TorNetworkNode(port, networkProtoResolver, !controlPort.isEmpty() ? new RunningTor(torDir, Integer.parseInt(controlPort), password, cookieFile, useSafeCookieAuthentication) : new NewTor(torDir, torrcFile, torrcOptions, bridgeAddressProvider.getBridgeAddresses())); diff --git a/p2p/src/main/java/bisq/network/p2p/network/NewTor.java b/p2p/src/main/java/bisq/network/p2p/network/NewTor.java index a5cdb1018cc..69c0461699b 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/NewTor.java +++ b/p2p/src/main/java/bisq/network/p2p/network/NewTor.java @@ -30,8 +30,8 @@ import org.berndpruenster.netlayer.tor.Tor; import org.berndpruenster.netlayer.tor.TorCtlException; import org.berndpruenster.netlayer.tor.Torrc; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import lombok.extern.slf4j.Slf4j; /** * This class creates a brand new instance of the Tor onion router. @@ -44,20 +44,27 @@ * @author Florian Reimair * */ +@Slf4j public class NewTor extends TorMode { - private static final Logger log = LoggerFactory.getLogger(NewTor.class); + /** + * Netlayer stores its hidden service files in a custom + * subdirectory of $torDir/hiddenservice/. Note that the + * {@link HiddenServiceSocket} does add this part on its own, hence, + * {@link NewTor#getHiddenServiceDirectory()} returns only the custom + * subdirectory (which happens to be "") + */ + private static final String HIDDEN_SERVICE_DIRECTORY = "hiddenservice"; private final String torrcFile; private final String torrcOptions; private final Collection bridgeEntries; - private final File torWorkikngDirectory; public NewTor(File torWorkingDirectory, String torrcFile, String torrcOptions, Collection bridgeEntries) { + super(torWorkingDirectory, HIDDEN_SERVICE_DIRECTORY); this.torrcFile = torrcFile; this.torrcOptions = torrcOptions; this.bridgeEntries = bridgeEntries; - this.torWorkikngDirectory = torWorkingDirectory; } @Override @@ -103,7 +110,7 @@ public Tor getTor() throws IOException, TorCtlException { override = new Torrc(torrcOptionsMap); log.info("Starting tor"); - NativeTor result = new NativeTor(torWorkikngDirectory, bridgeEntries, override); + NativeTor result = new NativeTor(torDir, bridgeEntries, override); log.info( "\n################################################################\n" + "Tor started after {} ms. Start publishing hidden service.\n" diff --git a/p2p/src/main/java/bisq/network/p2p/network/RunningTor.java b/p2p/src/main/java/bisq/network/p2p/network/RunningTor.java index 62c5f43b10a..88aae8c4870 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/RunningTor.java +++ b/p2p/src/main/java/bisq/network/p2p/network/RunningTor.java @@ -24,8 +24,8 @@ import org.berndpruenster.netlayer.tor.ExternalTor; import org.berndpruenster.netlayer.tor.Tor; import org.berndpruenster.netlayer.tor.TorCtlException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import lombok.extern.slf4j.Slf4j; /** * This class creates a brand new instance of the Tor onion router. @@ -37,19 +37,19 @@ * @author Florian Reimair * */ +@Slf4j public class RunningTor extends TorMode { - private static final Logger log = LoggerFactory.getLogger(RunningTor.class); + private static final String EXTERNAL_TOR_HIDDEN_SERVICE = "externalTorHiddenService"; private final int controlPort; private final String password; - private final String torDir; private final File cookieFile; private final boolean useSafeCookieAuthentication; public RunningTor(final File torDir, final int controlPort, final String password, final String cookieFile, final boolean useSafeCookieAuthentication) { - this.torDir = torDir.getAbsolutePath(); + super(torDir, EXTERNAL_TOR_HIDDEN_SERVICE); this.controlPort = controlPort; this.password = password; this.cookieFile = new File(cookieFile); @@ -72,7 +72,7 @@ else if (cookieFile.exists()) log.info( "\n################################################################\n" - + "Tor started after {} ms. Start publishing hidden service.\n" + + "Connecting to Tor successful after {} ms. Start publishing hidden service.\n" + "################################################################", (new Date().getTime() - ts1)); // takes usually a few seconds @@ -81,7 +81,7 @@ else if (cookieFile.exists()) @Override public String getHiddenServiceDirectory() { - return torDir + File.separator + "externalTorHiddenService"; + return new File(torDir, EXTERNAL_TOR_HIDDEN_SERVICE).getAbsolutePath(); } } diff --git a/p2p/src/main/java/bisq/network/p2p/network/TorMode.java b/p2p/src/main/java/bisq/network/p2p/network/TorMode.java index 594312d51fc..1ddcda3e281 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/TorMode.java +++ b/p2p/src/main/java/bisq/network/p2p/network/TorMode.java @@ -23,6 +23,8 @@ import org.berndpruenster.netlayer.tor.Tor; import org.berndpruenster.netlayer.tor.TorCtlException; +import bisq.common.storage.FileUtil; + /** * Holds information on how tor should be created and delivers a respective * {@link Tor} object when asked. @@ -32,11 +34,31 @@ */ public abstract class TorMode { + /** + * The directory where the private_key file sits in. Kept private, + * because it is only valid for the {@link TorMode#doRollingBackup()} due to the + * inner workings of the Netlayer dependency. + */ + private final File hiddenServiceDirectory; + protected final File torDir; + + /** + * @param torDir points to the place, where we will persist private + * key and address data + * @param hiddenServiceDir The directory where the private_key file + * sits in. Note that, due to the inner workings of the + * Netlayer dependency, it does not + * necessarily equal + * {@link TorMode#getHiddenServiceDirectory()}. + */ + public TorMode(File torDir, String hiddenServiceDir) { + this.torDir = torDir; + this.hiddenServiceDirectory = new File(torDir, hiddenServiceDir); + } + /** * Returns a fresh {@link Tor} object. * - * @param torDir points to the place, where we will persist private key and - * address data * @return a fresh instance of {@link Tor} * @throws IOException * @throws TorCtlException @@ -49,12 +71,20 @@ public abstract class TorMode { * "") as a hidden service directory is fine. {@link ExternalTor}, * however, does not have a Tor installation path and thus, takes the hidden * service path literally. Hence, we set - * "torDir/ephemeralHiddenService" as the hidden service directory. + * "torDir/externalTorHiddenService" as the hidden service + * directory. * * @return "" in {@link NewTor} Mode, - * "torDir/ephemeralHiddenService" in {@link RunningTor} + * "torDir/externalTorHiddenService" in {@link RunningTor} * mode */ public abstract String getHiddenServiceDirectory(); + /** + * Do a rolling backup of the "private_key" file. + */ + protected void doRollingBackup() { + FileUtil.rollingBackup(hiddenServiceDirectory, "private_key", 20); + } + } diff --git a/p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java b/p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java index 940eec53176..c560cf409d3 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java +++ b/p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java @@ -24,7 +24,6 @@ import bisq.common.UserThread; import bisq.common.app.Log; import bisq.common.proto.network.NetworkProtoResolver; -import bisq.common.storage.FileUtil; import bisq.common.util.Utilities; import org.berndpruenster.netlayer.tor.HiddenServiceSocket; @@ -47,14 +46,9 @@ import java.net.Socket; -import java.nio.file.Paths; - -import java.io.File; import java.io.IOException; import java.util.Date; -import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,7 +68,6 @@ public class TorNetworkNode extends NetworkNode { private HiddenServiceSocket hiddenServiceSocket; - private final File torDir; private Timer shutDownTimeoutTimer; private int restartCounter; @SuppressWarnings("FieldCanBeLocal") @@ -87,9 +80,8 @@ public class TorNetworkNode extends NetworkNode { // Constructor /////////////////////////////////////////////////////////////////////////////////////////// - public TorNetworkNode(int servicePort, File torDir, NetworkProtoResolver networkProtoResolver, TorMode torMode) { + public TorNetworkNode(int servicePort, NetworkProtoResolver networkProtoResolver, TorMode torMode) { super(servicePort, networkProtoResolver); - this.torDir = torDir; this.torMode = torMode; } @@ -100,8 +92,7 @@ public TorNetworkNode(int servicePort, File torDir, NetworkProtoResolver network @Override public void start(@Nullable SetupListener setupListener) { - final File hiddenservice = new File(Paths.get(torDir.getAbsolutePath(), "hiddenservice").toString()); - FileUtil.rollingBackup(hiddenservice, "private_key", 20); + torMode.doRollingBackup(); if (setupListener != null) addSetupListener(setupListener); @@ -280,8 +271,8 @@ public void run() { log.error("Could not connect to running Tor: " + e.getMessage()); - // Seems a bit harsh, but since we cannot connect to Tor, we cannot do nothing - // furthermore, we have no hidden services started yet, so there is no graceful + // Seems a bit harsh, but since we cannot connect to Tor, we cannot do nothing. + // Furthermore, we have no hidden services started yet, so there is no graceful // shutdown needed either System.exit(1); } catch (Throwable ignore) { diff --git a/p2p/src/test/java/bisq/network/p2p/network/TorNetworkNodeTest.java b/p2p/src/test/java/bisq/network/p2p/network/TorNetworkNodeTest.java index 8d29cc3d623..083195bde47 100644 --- a/p2p/src/test/java/bisq/network/p2p/network/TorNetworkNodeTest.java +++ b/p2p/src/test/java/bisq/network/p2p/network/TorNetworkNodeTest.java @@ -53,8 +53,7 @@ public class TorNetworkNodeTest { public void testTorNodeBeforeSecondReady() throws InterruptedException, IOException { latch = new CountDownLatch(1); int port = 9001; - TorNetworkNode node1 = new TorNetworkNode(port, new File("torNode_" + port), - TestUtils.getNetworkProtoResolver(), + TorNetworkNode node1 = new TorNetworkNode(port, TestUtils.getNetworkProtoResolver(), new NewTor(new File("torNode_" + port), "", "", new ArrayList())); node1.start(new SetupListener() { @Override @@ -81,8 +80,7 @@ public void onRequestCustomBridges() { latch = new CountDownLatch(1); int port2 = 9002; - TorNetworkNode node2 = new TorNetworkNode(port2, new File("torNode_" + port2), - TestUtils.getNetworkProtoResolver(), + TorNetworkNode node2 = new TorNetworkNode(port2, TestUtils.getNetworkProtoResolver(), new NewTor(new File("torNode_" + port), "", "", new ArrayList())); node2.start(new SetupListener() { @Override @@ -140,8 +138,7 @@ public void onFailure(@NotNull Throwable throwable) { public void testTorNodeAfterBothReady() throws InterruptedException, IOException { latch = new CountDownLatch(2); int port = 9001; - TorNetworkNode node1 = new TorNetworkNode(port, new File("torNode_" + port), - TestUtils.getNetworkProtoResolver(), + TorNetworkNode node1 = new TorNetworkNode(port, TestUtils.getNetworkProtoResolver(), new NewTor(new File("torNode_" + port), "", "", new ArrayList())); node1.start(new SetupListener() { @Override @@ -167,8 +164,7 @@ public void onRequestCustomBridges() { }); int port2 = 9002; - TorNetworkNode node2 = new TorNetworkNode(port2, new File("torNode_" + port), - TestUtils.getNetworkProtoResolver(), + TorNetworkNode node2 = new TorNetworkNode(port2, TestUtils.getNetworkProtoResolver(), new NewTor(new File("torNode_" + port), "", "", new ArrayList())); node2.start(new SetupListener() { @Override