mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 05:06:45 +00:00
automatically switch between internal and external tor proxy as required when connecting to server
This commit is contained in:
parent
c3ae98f3d1
commit
579b9a685b
11 changed files with 100 additions and 14 deletions
|
@ -1633,6 +1633,12 @@ public class AppController implements Initializable {
|
||||||
statusUpdated(new StatusEvent(event.getStatus()));
|
statusUpdated(new StatusEvent(event.getStatus()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void torExternalStatus(TorExternalStatusEvent event) {
|
||||||
|
serverToggle.setDisable(false);
|
||||||
|
statusUpdated(new StatusEvent(event.getStatus()));
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void newBlock(NewBlockEvent event) {
|
public void newBlock(NewBlockEvent event) {
|
||||||
setServerToggleTooltip(event.getHeight());
|
setServerToggleTooltip(event.getHeight());
|
||||||
|
|
|
@ -94,7 +94,7 @@ public class AppServices {
|
||||||
@Override
|
@Override
|
||||||
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean online) {
|
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean online) {
|
||||||
if(online) {
|
if(online) {
|
||||||
if(Config.get().requiresTor() && !isTorRunning()) {
|
if(Config.get().requiresInternalTor() && !isTorRunning()) {
|
||||||
torService.start();
|
torService.start();
|
||||||
} else {
|
} else {
|
||||||
restartServices();
|
restartServices();
|
||||||
|
@ -122,7 +122,7 @@ public class AppServices {
|
||||||
onlineProperty.addListener(onlineServicesListener);
|
onlineProperty.addListener(onlineServicesListener);
|
||||||
|
|
||||||
if(config.getMode() == Mode.ONLINE) {
|
if(config.getMode() == Mode.ONLINE) {
|
||||||
if(config.requiresTor()) {
|
if(config.requiresInternalTor()) {
|
||||||
torService.start();
|
torService.start();
|
||||||
} else {
|
} else {
|
||||||
restartServices();
|
restartServices();
|
||||||
|
@ -233,6 +233,12 @@ public class AppServices {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(failEvent.getSource().getException() instanceof ProxyServerException && Config.get().isUseProxy() && Config.get().requiresTor()) {
|
||||||
|
Config.get().setUseProxy(false);
|
||||||
|
Platform.runLater(() -> restartService(torService));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
onlineProperty.removeListener(onlineServicesListener);
|
onlineProperty.removeListener(onlineServicesListener);
|
||||||
onlineProperty.setValue(false);
|
onlineProperty.setValue(false);
|
||||||
onlineProperty.addListener(onlineServicesListener);
|
onlineProperty.addListener(onlineServicesListener);
|
||||||
|
@ -314,6 +320,23 @@ public class AppServices {
|
||||||
EventManager.get().post(new TorReadyStatusEvent());
|
EventManager.get().post(new TorReadyStatusEvent());
|
||||||
});
|
});
|
||||||
torService.setOnFailed(workerStateEvent -> {
|
torService.setOnFailed(workerStateEvent -> {
|
||||||
|
Throwable exception = workerStateEvent.getSource().getException();
|
||||||
|
if(exception instanceof TorServerAlreadyBoundException) {
|
||||||
|
String proxyServer = Config.get().getProxyServer();
|
||||||
|
if(proxyServer == null || proxyServer.equals("")) {
|
||||||
|
proxyServer = "localhost:9050";
|
||||||
|
Config.get().setProxyServer(proxyServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(proxyServer.equals("localhost:9050") || proxyServer.equals("127.0.0.1:9050")) {
|
||||||
|
Config.get().setUseProxy(true);
|
||||||
|
torService.cancel();
|
||||||
|
restartServices();
|
||||||
|
EventManager.get().post(new TorExternalStatusEvent());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EventManager.get().post(new TorFailedStatusEvent(workerStateEvent.getSource().getException()));
|
EventManager.get().post(new TorFailedStatusEvent(workerStateEvent.getSource().getException()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.sparrowwallet.sparrow.event;
|
||||||
|
|
||||||
|
public class TorExternalStatusEvent extends TorStatusEvent {
|
||||||
|
public TorExternalStatusEvent() {
|
||||||
|
super("Tor is already running, using external instance...");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
package com.sparrowwallet.sparrow.event;
|
package com.sparrowwallet.sparrow.event;
|
||||||
|
|
||||||
|
import com.sparrowwallet.sparrow.net.TorServerAlreadyBoundException;
|
||||||
|
|
||||||
public class TorFailedStatusEvent extends TorStatusEvent {
|
public class TorFailedStatusEvent extends TorStatusEvent {
|
||||||
private final Throwable exception;
|
private final Throwable exception;
|
||||||
|
|
||||||
public TorFailedStatusEvent(Throwable exception) {
|
public TorFailedStatusEvent(Throwable exception) {
|
||||||
super("Tor failed to start: " + (exception.getCause() != null ?
|
super("Tor failed to start: " + (exception instanceof TorServerAlreadyBoundException ? exception.getCause().getMessage() + " Is a Tor proxy already running?" :
|
||||||
(exception.getCause().getMessage().contains("Failed to bind") ? exception.getCause().getMessage() + " Is a Tor proxy already running?" : exception.getCause().getMessage() ) :
|
(exception.getCause() != null ? exception.getCause().getMessage() : exception.getMessage())));
|
||||||
exception.getMessage()));
|
|
||||||
this.exception = exception;
|
this.exception = exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -303,8 +303,16 @@ public class Config {
|
||||||
return getServerType() == ServerType.BITCOIN_CORE ? getCoreServer() : (getServerType() == ServerType.PUBLIC_ELECTRUM_SERVER ? getPublicElectrumServer() : getElectrumServer());
|
return getServerType() == ServerType.BITCOIN_CORE ? getCoreServer() : (getServerType() == ServerType.PUBLIC_ELECTRUM_SERVER ? getPublicElectrumServer() : getElectrumServer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean requiresInternalTor() {
|
||||||
|
if(isUseProxy()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return requiresTor();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean requiresTor() {
|
public boolean requiresTor() {
|
||||||
if(isUseProxy() || !hasServerAddress()) {
|
if(!hasServerAddress()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.sparrowwallet.sparrow.net;
|
||||||
|
|
||||||
|
public class ProxyServerException extends ServerException {
|
||||||
|
public ProxyServerException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -196,6 +196,10 @@ public class TcpTransport implements Transport, Closeable {
|
||||||
} catch(SSLHandshakeException e) {
|
} catch(SSLHandshakeException e) {
|
||||||
throw new TlsServerException(server, e);
|
throw new TlsServerException(server, e);
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
|
if(e.getStackTrace().length > 0 && e.getStackTrace()[0].getClassName().contains("SocksSocketImpl")) {
|
||||||
|
throw new ProxyServerException(e);
|
||||||
|
}
|
||||||
|
|
||||||
throw new ServerException(e);
|
throw new ServerException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.sparrowwallet.sparrow.net;
|
||||||
|
|
||||||
|
public class TorServerAlreadyBoundException extends TorServerException {
|
||||||
|
public TorServerAlreadyBoundException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TorServerAlreadyBoundException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.sparrowwallet.sparrow.net;
|
||||||
|
|
||||||
|
public class TorServerException extends ServerException {
|
||||||
|
public TorServerException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TorServerException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ public class TorService extends ScheduledService<NativeTor> {
|
||||||
@Override
|
@Override
|
||||||
protected Task<NativeTor> createTask() {
|
protected Task<NativeTor> createTask() {
|
||||||
return new Task<>() {
|
return new Task<>() {
|
||||||
protected NativeTor call() throws IOException {
|
protected NativeTor call() throws IOException, TorServerException {
|
||||||
if(Tor.getDefault() == null) {
|
if(Tor.getDefault() == null) {
|
||||||
Path path = Files.createTempDirectory(TOR_DIR_PREFIX);
|
Path path = Files.createTempDirectory(TOR_DIR_PREFIX);
|
||||||
File torInstallDir = path.toFile();
|
File torInstallDir = path.toFile();
|
||||||
|
@ -45,11 +45,15 @@ public class TorService extends ScheduledService<NativeTor> {
|
||||||
|
|
||||||
return new NativeTor(torInstallDir, Collections.emptyList(), override);
|
return new NativeTor(torInstallDir, Collections.emptyList(), override);
|
||||||
} catch(TorCtlException e) {
|
} catch(TorCtlException e) {
|
||||||
log.error("Failed to start Tor", e);
|
|
||||||
if(e.getCause() instanceof TorControlError) {
|
if(e.getCause() instanceof TorControlError) {
|
||||||
throw new IOException("Failed to start Tor", e.getCause());
|
if(e.getCause().getMessage().contains("Failed to bind")) {
|
||||||
|
throw new TorServerAlreadyBoundException("Tor server already bound", e.getCause());
|
||||||
|
}
|
||||||
|
log.error("Failed to start Tor", e);
|
||||||
|
throw new TorServerException("Failed to start Tor", e.getCause());
|
||||||
} else {
|
} else {
|
||||||
throw new IOException("Failed to start Tor", e);
|
log.error("Failed to start Tor", e);
|
||||||
|
throw new TorServerException("Failed to start Tor", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,7 +306,7 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
||||||
testConnection.setGraphic(getGlyph(FontAwesome5.Glyph.ELLIPSIS_H, null));
|
testConnection.setGraphic(getGlyph(FontAwesome5.Glyph.ELLIPSIS_H, null));
|
||||||
testResults.setText("Connecting to " + config.getServerAddress() + "...");
|
testResults.setText("Connecting to " + config.getServerAddress() + "...");
|
||||||
|
|
||||||
if(Config.get().requiresTor() && Tor.getDefault() == null) {
|
if(Config.get().requiresInternalTor() && Tor.getDefault() == null) {
|
||||||
startTor();
|
startTor();
|
||||||
} else {
|
} else {
|
||||||
startElectrumConnection();
|
startElectrumConnection();
|
||||||
|
@ -430,8 +430,10 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
||||||
|
|
||||||
Throwable exception = workerStateEvent.getSource().getException();
|
Throwable exception = workerStateEvent.getSource().getException();
|
||||||
if(Config.get().getServerType() == ServerType.ELECTRUM_SERVER &&
|
if(Config.get().getServerType() == ServerType.ELECTRUM_SERVER &&
|
||||||
exception.getCause() != null && exception.getCause() instanceof TorControlError && exception.getCause().getMessage().contains("Failed to bind") &&
|
exception instanceof TorServerAlreadyBoundException &&
|
||||||
useProxyOriginal == null && !useProxy.isSelected() && proxyHost.getText().isEmpty() && proxyPort.getText().isEmpty()) {
|
useProxyOriginal == null && !useProxy.isSelected() &&
|
||||||
|
(proxyHost.getText().isEmpty() || proxyHost.getText().equals("localhost") || proxyHost.getText().equals("127.0.0.1")) &&
|
||||||
|
(proxyPort.getText().isEmpty() || proxyPort.getText().equals("9050"))) {
|
||||||
useProxy.setSelected(true);
|
useProxy.setSelected(true);
|
||||||
proxyHost.setText("localhost");
|
proxyHost.setText("localhost");
|
||||||
proxyPort.setText("9050");
|
proxyPort.setText("9050");
|
||||||
|
@ -566,7 +568,9 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
||||||
}
|
}
|
||||||
|
|
||||||
reason = tlsServerException.getMessage() + "\n\n" + reason;
|
reason = tlsServerException.getMessage() + "\n\n" + reason;
|
||||||
} else if(exception.getCause() != null && exception.getCause() instanceof TorControlError && exception.getCause().getMessage().contains("Failed to bind")) {
|
} else if(exception instanceof ProxyServerException) {
|
||||||
|
reason += ". Check if the proxy server is running.";
|
||||||
|
} else if(exception instanceof TorServerAlreadyBoundException) {
|
||||||
reason += "\nIs a Tor proxy already running on port " + TorService.PROXY_PORT + "?";
|
reason += "\nIs a Tor proxy already running on port " + TorService.PROXY_PORT + "?";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue