diff --git a/network/tor-local-network/build.gradle b/network/tor-local-network/build.gradle index ab1b6acfc3..7f3b1cf47e 100644 --- a/network/tor-local-network/build.gradle +++ b/network/tor-local-network/build.gradle @@ -1,6 +1,11 @@ plugins { id 'bisq.java-library' id 'bisq.java-integration-tests' + id 'application' +} + +application { + mainClass = 'bisq.tor.local_network.Main' } dependencies { diff --git a/network/tor-local-network/src/main/java/bisq/tor/local_network/Main.java b/network/tor-local-network/src/main/java/bisq/tor/local_network/Main.java new file mode 100644 index 0000000000..2d524cad4f --- /dev/null +++ b/network/tor-local-network/src/main/java/bisq/tor/local_network/Main.java @@ -0,0 +1,74 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.tor.local_network; + +import bisq.common.data.Pair; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; + +public class Main { + private static final String PASSPHRASE = "my_passphrase"; + + public static void main(String[] args) throws IOException, InterruptedException { + Pair dataDirAndStartArg = parseArgs(args); + if (!dataDirAndStartArg.getSecond()) { + System.out.println("--start argument is missing."); + } + + Path dataDir = dataDirAndStartArg.getFirst(); + new TorNetwork(dataDir) + .addDirAuth(PASSPHRASE) + .addDirAuth(PASSPHRASE) + .addDirAuth(PASSPHRASE) + + .addRelay() + .addRelay() + .addRelay() + .addRelay() + .addRelay() + + .addClient() + .addClient() + + .start(); + } + + private static Pair parseArgs(String[] allArgs) { + Optional dataDirPath = Optional.empty(); + boolean isStartCommand = false; + + for (int i = 0; i < allArgs.length; i++) { + switch (allArgs[i]) { + case "--dataDir": + dataDirPath = Optional.of( + Path.of(allArgs[i + 1]) + ); + break; + + case "--start": + isStartCommand = true; + break; + + } + } + + return new Pair<>(dataDirPath.orElseThrow(), isStartCommand); + } +} diff --git a/network/tor-local-network/src/main/java/bisq/tor/local_network/TorNetwork.java b/network/tor-local-network/src/main/java/bisq/tor/local_network/TorNetwork.java index 5085aac577..1f0ad69181 100644 --- a/network/tor-local-network/src/main/java/bisq/tor/local_network/TorNetwork.java +++ b/network/tor-local-network/src/main/java/bisq/tor/local_network/TorNetwork.java @@ -24,6 +24,7 @@ import bisq.tor.local_network.torrc.RelayTorrcGenerator; import bisq.tor.local_network.torrc.TorrcFileGenerator; +import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.HashSet; @@ -51,10 +52,7 @@ public TorNetwork addDirAuth(String passphrase) throws IOException, InterruptedE String nickname = "da" + dirAuthIndex++; Path nodeDataDir = rootDataDir.resolve(nickname); - boolean isSuccess = nodeDataDir.toFile().mkdir(); - if (!isSuccess) { - throw new IllegalStateException("Couldn't create data directory for " + nickname); - } + createDataDirIfNotPresent(nodeDataDir); var dirAuth = TorNode.builder() .type(TorNode.Type.DIRECTORY_AUTHORITY) @@ -74,10 +72,7 @@ public TorNetwork addRelay() { String nickname = "relay" + relayIndex++; Path nodeDataDir = rootDataDir.resolve(nickname); - boolean isSuccess = nodeDataDir.toFile().mkdir(); - if (!isSuccess) { - throw new IllegalStateException("Couldn't create data directory for " + nickname); - } + createDataDirIfNotPresent(nodeDataDir); TorNode firstRelay = TorNode.builder() .type(TorNode.Type.RELAY) @@ -97,10 +92,7 @@ public TorNetwork addClient() { String nickname = "client" + clientIndex++; Path nodeDataDir = rootDataDir.resolve(nickname); - boolean isSuccess = nodeDataDir.toFile().mkdir(); - if (!isSuccess) { - throw new IllegalStateException("Couldn't create data directory for " + nickname); - } + createDataDirIfNotPresent(nodeDataDir); TorNode firstClient = TorNode.builder() .type(TorNode.Type.CLIENT) @@ -121,24 +113,36 @@ public void start() throws IOException { startProcesses(); } + private void createDataDirIfNotPresent(Path nodeDataDirPath) { + File nodeDataDirFile = nodeDataDirPath.toFile(); + if (nodeDataDirFile.exists()) { + return; + } + + boolean isSuccess = nodeDataDirPath.toFile().mkdir(); + if (!isSuccess) { + throw new IllegalStateException("Couldn't create data directory: " + nodeDataDirPath.toAbsolutePath()); + } + } + private void generateTorrcFiles() throws IOException { Set allDAs = dirAuthFactory.getAllDirectoryAuthorities(); for (TorNode da : allDAs) { var torDaTorrcGenerator = new DirectoryAuthorityTorrcGenerator(da); var torrcFileGenerator = new TorrcFileGenerator(torDaTorrcGenerator, allDAs); - torrcFileGenerator.generate(); + generateTorrc(da, torrcFileGenerator); } for (TorNode relay : relays) { var relayTorrcGenerator = new RelayTorrcGenerator(relay); var torrcFileGenerator = new TorrcFileGenerator(relayTorrcGenerator, allDAs); - torrcFileGenerator.generate(); + generateTorrc(relay, torrcFileGenerator); } for (TorNode client : clients) { var clientTorrcGenerator = new ClientTorrcGenerator(client); var torrcFileGenerator = new TorrcFileGenerator(clientTorrcGenerator, allDAs); - torrcFileGenerator.generate(); + generateTorrc(client, torrcFileGenerator); } } @@ -168,4 +172,11 @@ private Process createAndStartTorProcess(TorNode torNode) throws IOException { processBuilder.redirectOutput(ProcessBuilder.Redirect.DISCARD); return processBuilder.start(); } + + private void generateTorrc(TorNode torNode, TorrcFileGenerator torrcFileGenerator) throws IOException { + if (torNode.getTorrcPath().toFile().exists()) { + return; + } + torrcFileGenerator.generate(); + } } diff --git a/network/tor-local-network/src/main/java/bisq/tor/local_network/da/DirectoryAuthorityFactory.java b/network/tor-local-network/src/main/java/bisq/tor/local_network/da/DirectoryAuthorityFactory.java index d1ac3ada98..e1253d329e 100644 --- a/network/tor-local-network/src/main/java/bisq/tor/local_network/da/DirectoryAuthorityFactory.java +++ b/network/tor-local-network/src/main/java/bisq/tor/local_network/da/DirectoryAuthorityFactory.java @@ -38,13 +38,15 @@ public void createDirectoryAuthority(TorNode directoryAuthority, createDataDirIfNotPresent(dataDir); Path keysPath = dataDir.resolve("keys"); - boolean isSuccess = keysPath.toFile().mkdirs(); - if (!isSuccess) { - throw new IllegalStateException("Couldn't create keys folder in data directory for directory authority."); + File keysDirFile = keysPath.toFile(); + if (!keysDirFile.exists()) { + boolean isSuccess = keysDirFile.mkdirs(); + if (!isSuccess) { + throw new IllegalStateException("Couldn't create keys folder in data directory for directory authority."); + } + DirectoryAuthorityKeyGenerator.generate(directoryAuthority, passphrase); } - DirectoryAuthorityKeyGenerator.generate(directoryAuthority, passphrase); - allDirectoryAuthorities.add(directoryAuthority); }