Skip to content

Commit

Permalink
TorControlProtocol: Wrap IOException into CannotSendCommandToTorExcep…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
alvasw committed Jun 11, 2024
1 parent 46759a2 commit 05dad13
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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";
Expand All @@ -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";

Expand All @@ -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<String> 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();
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -99,7 +100,7 @@ public void setConfig(String configName, String configValue) throws IOException
}
}

public void setEvents(List<String> events) throws IOException {
public void setEvents(List<String> events) {
var stringBuilder = new StringBuffer("SETEVENTS");
events.forEach(event -> stringBuilder.append(" ").append(event));
stringBuilder.append("\r\n");
Expand All @@ -112,7 +113,7 @@ public void setEvents(List<String> events) throws IOException {
}
}

public void takeOwnership() throws IOException {
public void takeOwnership() {
String command = "TAKEOWNERSHIP\r\n";
sendCommand(command);
String reply = receiveReply().findFirst().orElseThrow();
Expand All @@ -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<String> receiveReply() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -61,14 +64,14 @@ public void shutdown() {
});
}

public void bootstrapTor() throws IOException {
public void bootstrapTor() {
bindToBisq();
subscribeToBootstrapEvents();
enableNetworking();
waitUntilBootstrapped();
}

public CompletableFuture<Boolean> isOnionServiceOnline(String onionAddress) throws IOException, ExecutionException, InterruptedException, TimeoutException {
public CompletableFuture<Boolean> isOnionServiceOnline(String onionAddress) {
var onionServiceLookupCompletableFuture = new CompletableFuture<Boolean>();
pendingIsOnionServiceOnlineLookupFutureMap.put(onionAddress, onionServiceLookupCompletableFuture);
subscribeToHsDescEvents();
Expand All @@ -79,17 +82,13 @@ public CompletableFuture<Boolean> 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);
Expand All @@ -107,28 +106,22 @@ public void publish(TorKeyPair torKeyPair, int onionServicePort, int localPort)
torControlProtocol.setEvents(Collections.emptyList());
}

public Optional<Integer> 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
Expand Down Expand Up @@ -179,30 +172,28 @@ private void initialize(int controlPort, Optional<PasswordDigest> 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");
}
Expand All @@ -227,8 +218,6 @@ private void waitUntilBootstrapped() {
}
} catch (InterruptedException e) {
throw new TorBootstrapFailedException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package bisq.tor.controller.exceptions;

public class CannotSendCommandToTorException extends RuntimeException {
public CannotSendCommandToTorException(Throwable cause) {
super(cause);
}
}

0 comments on commit 05dad13

Please sign in to comment.