diff --git a/network/tor/tor/src/main/java/bisq/tor/controller/TorControlProtocol.java b/network/tor/tor/src/main/java/bisq/tor/controller/TorControlProtocol.java index 5b33d0011c..3e2140784e 100644 --- a/network/tor/tor/src/main/java/bisq/tor/controller/TorControlProtocol.java +++ b/network/tor/tor/src/main/java/bisq/tor/controller/TorControlProtocol.java @@ -4,6 +4,7 @@ import bisq.security.keys.TorKeyPair; import bisq.tor.controller.events.listener.BootstrapEventListener; import bisq.tor.controller.events.listener.HsDescEventListener; +import bisq.tor.controller.exceptions.CannotSendCommandToTorException; import net.freehaven.tor.control.PasswordDigest; import java.io.IOException; @@ -39,7 +40,7 @@ public void initialize() { whonixTorControlReader.start(); } - public void authenticate(PasswordDigest passwordDigest) throws IOException { + public void authenticate(PasswordDigest passwordDigest) { byte[] secret = passwordDigest.getSecret(); String secretHex = Hex.encode(secret); String command = "AUTHENTICATE " + secretHex + "\r\n"; @@ -56,7 +57,7 @@ public void authenticate(PasswordDigest passwordDigest) throws IOException { } } - public void addOnion(TorKeyPair torKeyPair, int onionPort, int localPort) throws IOException { + public void addOnion(TorKeyPair torKeyPair, int onionPort, int localPort) { String base64SecretScalar = torKeyPair.getBase64SecretScalar(); String command = "ADD_ONION " + "ED25519-V3:" + base64SecretScalar + " Port=" + onionPort + "," + localPort + "\r\n"; @@ -65,14 +66,14 @@ public void addOnion(TorKeyPair torKeyPair, int onionPort, int localPort) throws assertTwoLineOkReply(replyStream, "ADD_ONION"); } - public String getInfo(String keyword) throws IOException { + public String getInfo(String keyword) { String command = "GETINFO " + keyword + "\r\n"; sendCommand(command); Stream replyStream = receiveReply(); return assertTwoLineOkReply(replyStream, "GETINFO"); } - public void hsFetch(String hsAddress) throws IOException { + public void hsFetch(String hsAddress) { String command = "HSFETCH " + hsAddress + "\r\n"; sendCommand(command); String reply = receiveReply().findFirst().orElseThrow(); @@ -81,7 +82,7 @@ public void hsFetch(String hsAddress) throws IOException { } } - public void resetConf(String configName) throws IOException { + public void resetConf(String configName) { String command = "RESETCONF " + configName + "\r\n"; sendCommand(command); String reply = receiveReply().findFirst().orElseThrow(); @@ -90,7 +91,7 @@ public void resetConf(String configName) throws IOException { } } - public void setConfig(String configName, String configValue) throws IOException { + public void setConfig(String configName, String configValue) { String command = "SETCONF " + configName + "=" + configValue + "\r\n"; sendCommand(command); String reply = receiveReply().findFirst().orElseThrow(); @@ -99,7 +100,7 @@ public void setConfig(String configName, String configValue) throws IOException } } - public void setEvents(List events) throws IOException { + public void setEvents(List events) { var stringBuilder = new StringBuffer("SETEVENTS"); events.forEach(event -> stringBuilder.append(" ").append(event)); stringBuilder.append("\r\n"); @@ -112,7 +113,7 @@ public void setEvents(List events) throws IOException { } } - public void takeOwnership() throws IOException { + public void takeOwnership() { String command = "TAKEOWNERSHIP\r\n"; sendCommand(command); String reply = receiveReply().findFirst().orElseThrow(); @@ -137,10 +138,14 @@ public void removeHsDescEventListener(HsDescEventListener listener) { whonixTorControlReader.removeHsDescEventListener(listener); } - private void sendCommand(String command) throws IOException { - byte[] commandBytes = command.getBytes(StandardCharsets.US_ASCII); - outputStream.write(commandBytes); - outputStream.flush(); + private void sendCommand(String command) { + try { + byte[] commandBytes = command.getBytes(StandardCharsets.US_ASCII); + outputStream.write(commandBytes); + outputStream.flush(); + } catch (IOException e) { + throw new CannotSendCommandToTorException(e); + } } private Stream receiveReply() { diff --git a/network/tor/tor/src/main/java/bisq/tor/controller/TorController.java b/network/tor/tor/src/main/java/bisq/tor/controller/TorController.java index 9c6612fd10..d9c8752bd6 100644 --- a/network/tor/tor/src/main/java/bisq/tor/controller/TorController.java +++ b/network/tor/tor/src/main/java/bisq/tor/controller/TorController.java @@ -22,7 +22,10 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.concurrent.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; @Slf4j public class TorController implements BootstrapEventListener, HsDescEventListener { @@ -61,14 +64,14 @@ public void shutdown() { }); } - public void bootstrapTor() throws IOException { + public void bootstrapTor() { bindToBisq(); subscribeToBootstrapEvents(); enableNetworking(); waitUntilBootstrapped(); } - public CompletableFuture isOnionServiceOnline(String onionAddress) throws IOException, ExecutionException, InterruptedException, TimeoutException { + public CompletableFuture isOnionServiceOnline(String onionAddress) { var onionServiceLookupCompletableFuture = new CompletableFuture(); pendingIsOnionServiceOnlineLookupFutureMap.put(onionAddress, onionServiceLookupCompletableFuture); subscribeToHsDescEvents(); @@ -79,17 +82,13 @@ public CompletableFuture isOnionServiceOnline(String onionAddress) thro onionServiceLookupCompletableFuture.thenRun(() -> { torControlProtocol.removeHsDescEventListener(this); - try { - torControlProtocol.setEvents(Collections.emptyList()); - } catch (IOException e) { - throw new RuntimeException(e); - } + torControlProtocol.setEvents(Collections.emptyList()); }); return onionServiceLookupCompletableFuture; } - public void publish(TorKeyPair torKeyPair, int onionServicePort, int localPort) throws IOException, InterruptedException { + public void publish(TorKeyPair torKeyPair, int onionServicePort, int localPort) throws InterruptedException { String onionAddress = torKeyPair.getOnionAddress(); var onionServicePublishedLatch = new CountDownLatch(1); pendingOnionServicePublishLatchMap.put(onionAddress, onionServicePublishedLatch); @@ -107,28 +106,22 @@ public void publish(TorKeyPair torKeyPair, int onionServicePort, int localPort) torControlProtocol.setEvents(Collections.emptyList()); } - public Optional getSocksPort() { - try { - TorControlProtocol torControlProtocol = getTorControlProtocol(); - String socksListenersString = torControlProtocol.getInfo("net/listeners/socks"); - - String socksListener; - if (socksListenersString.contains(" ")) { - String[] socksPorts = socksListenersString.split(" "); - socksListener = socksPorts[0]; - } else { - socksListener = socksListenersString; - } - - // "127.0.0.1:12345" - socksListener = socksListener.replace("\"", ""); - String portString = socksListener.split(":")[1]; - - int port = Integer.parseInt(portString); - return Optional.of(port); - } catch (IOException e) { - return Optional.empty(); + public int getSocksPort() { + TorControlProtocol torControlProtocol = getTorControlProtocol(); + String socksListenersString = torControlProtocol.getInfo("net/listeners/socks"); + + String socksListener; + if (socksListenersString.contains(" ")) { + String[] socksPorts = socksListenersString.split(" "); + socksListener = socksPorts[0]; + } else { + socksListener = socksListenersString; } + + // "127.0.0.1:12345" + socksListener = socksListener.replace("\"", ""); + String portString = socksListener.split(":")[1]; + return Integer.parseInt(portString); } @Override @@ -179,30 +172,28 @@ private void initialize(int controlPort, Optional hashedControlP this.torControlProtocol = Optional.of(torControlProtocol); torControlProtocol.initialize(); - if (hashedControlPassword.isPresent()) { - torControlProtocol.authenticate(hashedControlPassword.get()); - } + hashedControlPassword.ifPresent(torControlProtocol::authenticate); } - private void bindToBisq() throws IOException { + private void bindToBisq() { TorControlProtocol torControlProtocol = getTorControlProtocol(); torControlProtocol.takeOwnership(); torControlProtocol.resetConf(NativeTorProcess.ARG_OWNER_PID); } - private void subscribeToBootstrapEvents() throws IOException { + private void subscribeToBootstrapEvents() { TorControlProtocol torControlProtocol = getTorControlProtocol(); torControlProtocol.addBootstrapEventListener(this); torControlProtocol.setEvents(List.of("STATUS_CLIENT")); } - private void subscribeToHsDescEvents() throws IOException { + private void subscribeToHsDescEvents() { TorControlProtocol torControlProtocol = getTorControlProtocol(); torControlProtocol.addHsDescEventListener(this); torControlProtocol.setEvents(List.of("HS_DESC")); } - private void enableNetworking() throws IOException { + private void enableNetworking() { TorControlProtocol torControlProtocol = getTorControlProtocol(); torControlProtocol.setConfig(TorrcClientConfigFactory.DISABLE_NETWORK_CONFIG_KEY, "0"); } @@ -227,8 +218,6 @@ private void waitUntilBootstrapped() { } } catch (InterruptedException e) { throw new TorBootstrapFailedException(e); - } catch (IOException e) { - throw new RuntimeException(e); } } diff --git a/network/tor/tor/src/main/java/bisq/tor/controller/exceptions/CannotSendCommandToTorException.java b/network/tor/tor/src/main/java/bisq/tor/controller/exceptions/CannotSendCommandToTorException.java new file mode 100644 index 0000000000..42b26f7d92 --- /dev/null +++ b/network/tor/tor/src/main/java/bisq/tor/controller/exceptions/CannotSendCommandToTorException.java @@ -0,0 +1,7 @@ +package bisq.tor.controller.exceptions; + +public class CannotSendCommandToTorException extends RuntimeException { + public CannotSendCommandToTorException(Throwable cause) { + super(cause); + } +}