mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-23 20:36:44 +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()));
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void torExternalStatus(TorExternalStatusEvent event) {
|
||||
serverToggle.setDisable(false);
|
||||
statusUpdated(new StatusEvent(event.getStatus()));
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void newBlock(NewBlockEvent event) {
|
||||
setServerToggleTooltip(event.getHeight());
|
||||
|
|
|
@ -94,7 +94,7 @@ public class AppServices {
|
|||
@Override
|
||||
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean online) {
|
||||
if(online) {
|
||||
if(Config.get().requiresTor() && !isTorRunning()) {
|
||||
if(Config.get().requiresInternalTor() && !isTorRunning()) {
|
||||
torService.start();
|
||||
} else {
|
||||
restartServices();
|
||||
|
@ -122,7 +122,7 @@ public class AppServices {
|
|||
onlineProperty.addListener(onlineServicesListener);
|
||||
|
||||
if(config.getMode() == Mode.ONLINE) {
|
||||
if(config.requiresTor()) {
|
||||
if(config.requiresInternalTor()) {
|
||||
torService.start();
|
||||
} else {
|
||||
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.setValue(false);
|
||||
onlineProperty.addListener(onlineServicesListener);
|
||||
|
@ -314,6 +320,23 @@ public class AppServices {
|
|||
EventManager.get().post(new TorReadyStatusEvent());
|
||||
});
|
||||
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()));
|
||||
});
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
import com.sparrowwallet.sparrow.net.TorServerAlreadyBoundException;
|
||||
|
||||
public class TorFailedStatusEvent extends TorStatusEvent {
|
||||
private final Throwable exception;
|
||||
|
||||
public TorFailedStatusEvent(Throwable exception) {
|
||||
super("Tor failed to start: " + (exception.getCause() != null ?
|
||||
(exception.getCause().getMessage().contains("Failed to bind") ? exception.getCause().getMessage() + " Is a Tor proxy already running?" : exception.getCause().getMessage() ) :
|
||||
exception.getMessage()));
|
||||
super("Tor failed to start: " + (exception instanceof TorServerAlreadyBoundException ? exception.getCause().getMessage() + " Is a Tor proxy already running?" :
|
||||
(exception.getCause() != null ? exception.getCause().getMessage() : exception.getMessage())));
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
|
|
|
@ -303,8 +303,16 @@ public class Config {
|
|||
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() {
|
||||
if(isUseProxy() || !hasServerAddress()) {
|
||||
if(!hasServerAddress()) {
|
||||
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) {
|
||||
throw new TlsServerException(server, e);
|
||||
} catch(IOException e) {
|
||||
if(e.getStackTrace().length > 0 && e.getStackTrace()[0].getClassName().contains("SocksSocketImpl")) {
|
||||
throw new ProxyServerException(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
|
||||
protected Task<NativeTor> createTask() {
|
||||
return new Task<>() {
|
||||
protected NativeTor call() throws IOException {
|
||||
protected NativeTor call() throws IOException, TorServerException {
|
||||
if(Tor.getDefault() == null) {
|
||||
Path path = Files.createTempDirectory(TOR_DIR_PREFIX);
|
||||
File torInstallDir = path.toFile();
|
||||
|
@ -45,11 +45,15 @@ public class TorService extends ScheduledService<NativeTor> {
|
|||
|
||||
return new NativeTor(torInstallDir, Collections.emptyList(), override);
|
||||
} catch(TorCtlException e) {
|
||||
log.error("Failed to start Tor", e);
|
||||
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 {
|
||||
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));
|
||||
testResults.setText("Connecting to " + config.getServerAddress() + "...");
|
||||
|
||||
if(Config.get().requiresTor() && Tor.getDefault() == null) {
|
||||
if(Config.get().requiresInternalTor() && Tor.getDefault() == null) {
|
||||
startTor();
|
||||
} else {
|
||||
startElectrumConnection();
|
||||
|
@ -430,8 +430,10 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
|
||||
Throwable exception = workerStateEvent.getSource().getException();
|
||||
if(Config.get().getServerType() == ServerType.ELECTRUM_SERVER &&
|
||||
exception.getCause() != null && exception.getCause() instanceof TorControlError && exception.getCause().getMessage().contains("Failed to bind") &&
|
||||
useProxyOriginal == null && !useProxy.isSelected() && proxyHost.getText().isEmpty() && proxyPort.getText().isEmpty()) {
|
||||
exception instanceof TorServerAlreadyBoundException &&
|
||||
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);
|
||||
proxyHost.setText("localhost");
|
||||
proxyPort.setText("9050");
|
||||
|
@ -566,7 +568,9 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
}
|
||||
|
||||
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 + "?";
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue