mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-11-02 20:36:44 +00:00
update tor to 0.4.7.13 using kmp-tor library
This commit is contained in:
parent
acab50cdcd
commit
faa5a11c94
24 changed files with 435 additions and 213 deletions
178
build.gradle
178
build.gradle
|
@ -23,6 +23,19 @@ if(System.getProperty("os.arch") == "aarch64") {
|
|||
}
|
||||
def headless = "true".equals(System.getProperty("java.awt.headless"))
|
||||
|
||||
def vTor = '4.7.13-4'
|
||||
def vKmpTor = '1.4.2'
|
||||
def kmpOs = osName
|
||||
if(os.macOsX) {
|
||||
kmpOs = "macos"
|
||||
} else if(os.windows) {
|
||||
kmpOs = "mingw"
|
||||
}
|
||||
def kmpArch = "x64"
|
||||
if(System.getProperty("os.arch") == "aarch64") {
|
||||
kmpArch = "arm64"
|
||||
}
|
||||
|
||||
group "com.sparrowwallet"
|
||||
version "${sparrowVersion}"
|
||||
|
||||
|
@ -84,10 +97,15 @@ dependencies {
|
|||
implementation("com.github.sarxos:webcam-capture${targetName}:0.3.13-SNAPSHOT") {
|
||||
exclude group: 'com.nativelibs4java', module: 'bridj'
|
||||
}
|
||||
implementation("com.sparrowwallet:netlayer-jpms-${osName}${targetName}:0.6.8") {
|
||||
exclude group: 'org.jetbrains.kotlin'
|
||||
implementation "io.matthewnelson.kotlin-components:kmp-tor:${vTor}-${vKmpTor}"
|
||||
if(kmpOs == "linux" && kmpArch == "arm64") {
|
||||
implementation("com.sparrowwallet.kmp-tor-binary:kmp-tor-binary-${kmpOs}${kmpArch}-jvm:${vTor}")
|
||||
} else {
|
||||
implementation("io.matthewnelson.kotlin-components:kmp-tor-binary-${kmpOs}${kmpArch}:${vTor}")
|
||||
}
|
||||
implementation('org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.20')
|
||||
implementation("io.matthewnelson.kotlin-components:kmp-tor-binary-extract:${vTor}")
|
||||
implementation("io.matthewnelson.kotlin-components:kmp-tor-ext-callback-manager:${vKmpTor}")
|
||||
implementation('org.jetbrains.kotlinx:kotlinx-coroutines-javafx:1.6.4')
|
||||
implementation('de.codecentric.centerdevice:centerdevice-nsmenufx:2.1.7')
|
||||
implementation('org.controlsfx:controlsfx:11.1.0' ) {
|
||||
exclude group: 'org.openjfx', module: 'javafx-base'
|
||||
|
@ -163,7 +181,8 @@ run {
|
|||
"--add-opens=javafx.graphics/javafx.scene.input=com.sparrowwallet.sparrow",
|
||||
"--add-opens=java.base/java.net=com.sparrowwallet.sparrow",
|
||||
"--add-opens=java.base/java.io=com.google.gson",
|
||||
"--add-opens=java.smartcardio/sun.security.smartcardio=com.sparrowwallet.sparrow"]
|
||||
"--add-opens=java.smartcardio/sun.security.smartcardio=com.sparrowwallet.sparrow",
|
||||
"--add-reads=kotlin.stdlib=kotlinx.coroutines.core.jvm"]
|
||||
|
||||
if(os.macOsX) {
|
||||
applicationDefaultJvmArgs += ["-Dprism.lcdtext=false", "-Xdock:name=Sparrow", "-Xdock:icon=/Users/scy/git/sparrow/src/main/resources/sparrow-large.png",
|
||||
|
@ -221,7 +240,8 @@ jlink {
|
|||
"--add-reads=com.sparrowwallet.merged.module=com.fasterxml.jackson.databind",
|
||||
"--add-reads=com.sparrowwallet.merged.module=com.fasterxml.jackson.annotation",
|
||||
"--add-reads=com.sparrowwallet.merged.module=com.fasterxml.jackson.core",
|
||||
"--add-reads=com.sparrowwallet.merged.module=co.nstant.in.cbor"]
|
||||
"--add-reads=com.sparrowwallet.merged.module=co.nstant.in.cbor",
|
||||
"--add-reads=kotlin.stdlib=kotlinx.coroutines.core.jvm"]
|
||||
|
||||
if(os.windows) {
|
||||
jvmArgs += ["-Djavax.accessibility.assistive_technologies", "-Djavax.accessibility.screen_magnifier_present=false"]
|
||||
|
@ -403,11 +423,6 @@ extraJavaModuleInfo {
|
|||
requires('java.xml')
|
||||
requires('java.logging')
|
||||
}
|
||||
module('kotlin-logging-1.5.4.jar', 'io.github.microutils.kotlin.logging', '1.5.4') {
|
||||
exports('mu')
|
||||
requires('kotlin.stdlib')
|
||||
requires('org.slf4j')
|
||||
}
|
||||
module('failureaccess-1.0.1.jar', 'failureaccess', '1.0.1') {
|
||||
exports('com.google.common.util.concurrent.internal')
|
||||
}
|
||||
|
@ -483,13 +498,6 @@ extraJavaModuleInfo {
|
|||
requires('javafx.graphics')
|
||||
}
|
||||
module('jai-imageio-core-1.4.0.jar', 'com.github.jai.imageio.jai.imageio.core', '1.4.0')
|
||||
module('kotlin-stdlib-jdk8-1.5.20.jar', 'org.jetbrains.kotlin.kotlin.stdlib.jdk8', '1.5.20')
|
||||
module('kotlin-stdlib-jdk7-1.5.20.jar', 'org.jetbrains.kotlin.kotlin.stdlib.jdk7', '1.5.20')
|
||||
module('kotlin-stdlib-1.5.20.jar', 'kotlin.stdlib', '1.5.20') {
|
||||
exports('kotlin')
|
||||
exports('kotlin.jvm')
|
||||
exports('kotlin.collections')
|
||||
}
|
||||
module('hummingbird-1.6.3.jar', 'com.sparrowwallet.hummingbird', '1.6.3') {
|
||||
exports('com.sparrowwallet.hummingbird')
|
||||
exports('com.sparrowwallet.hummingbird.registry')
|
||||
|
@ -597,29 +605,131 @@ extraJavaModuleInfo {
|
|||
requires('javafx.graphics')
|
||||
requires('java.xml')
|
||||
}
|
||||
module("netlayer-jpms-${osName}${targetName}-0.6.8.jar", 'netlayer.jpms', '0.6.8') {
|
||||
exports('org.berndpruenster.netlayer.tor')
|
||||
requires('com.github.ravn.jsocks')
|
||||
requires('com.github.JesusMcCloud.jtorctl')
|
||||
module('kotlinx-coroutines-core-jvm-1.6.4.jar', 'kotlinx.coroutines.core.jvm', '1.6.4') {
|
||||
exports('kotlinx.coroutines')
|
||||
requires('kotlin.stdlib')
|
||||
requires('commons.compress')
|
||||
requires('org.tukaani.xz')
|
||||
requires('java.instrument')
|
||||
uses('kotlinx.coroutines.CoroutineExceptionHandler')
|
||||
uses('kotlinx.coroutines.internal.MainDispatcherFactory')
|
||||
}
|
||||
module('kotlinx-coroutines-javafx-1.6.4.jar', 'kotlinx.coroutines.javafx', '1.6.4') {
|
||||
exports('kotlinx.coroutines.javafx')
|
||||
requires('kotlinx.coroutines.core.jvm')
|
||||
requires('kotlin.stdlib')
|
||||
requires('javafx.graphics')
|
||||
}
|
||||
module("kmp-tor-jvm-${vKmpTor}.jar", 'kmp.tor.jvm', "${vTor}-${vKmpTor}") {
|
||||
exports('io.matthewnelson.kmp.tor')
|
||||
requires('kmp.tor.binary.extract.jvm')
|
||||
requires('kmp.tor.manager.jvm')
|
||||
requires('kmp.tor.manager.common.jvm')
|
||||
requires('kmp.tor.controller.common.jvm')
|
||||
requires('kotlin.stdlib')
|
||||
requires('kotlinx.coroutines.core.jvm')
|
||||
requires('java.management')
|
||||
requires('io.github.microutils.kotlin.logging')
|
||||
}
|
||||
module('jtorctl-1.5.jar', 'com.github.JesusMcCloud.jtorctl', '1.5') {
|
||||
exports('net.freehaven.tor.control')
|
||||
if(kmpOs == "linux" && kmpArch == "arm64") {
|
||||
module("kmp-tor-binary-${kmpOs}${kmpArch}-jvm-${vTor}.jar", "kmp.tor.binary.${kmpOs}${kmpArch}", "${vTor}") {
|
||||
exports("io.matthewnelson.kmp.tor.resource.${kmpOs}.${kmpArch}")
|
||||
exports("kmptor.${kmpOs}.${kmpArch}")
|
||||
}
|
||||
} else {
|
||||
module("kmp-tor-binary-${kmpOs}${kmpArch}-jvm-${vTor}.jar", "kmp.tor.binary.${kmpOs}${kmpArch}", "${vTor}") {
|
||||
exports("io.matthewnelson.kmp.tor.binary.${kmpOs}.${kmpArch}")
|
||||
exports("kmptor.${kmpOs}.${kmpArch}")
|
||||
}
|
||||
}
|
||||
module('commons-compress-1.18.jar', 'commons.compress', '1.18') {
|
||||
exports('org.apache.commons.compress')
|
||||
requires('org.tukaani.xz')
|
||||
module("kmp-tor-binary-extract-jvm-${vTor}.jar", 'kmp.tor.binary.extract.jvm', "${vTor}") {
|
||||
exports('io.matthewnelson.kmp.tor.binary.extract')
|
||||
exports('io.matthewnelson.kmp.tor.binary.extract.internal')
|
||||
requires('kotlin.stdlib')
|
||||
requires("kmp.tor.binary.${kmpOs}${kmpArch}")
|
||||
requires('kmp.tor.binary.geoip.jvm')
|
||||
}
|
||||
module('xz-1.6.jar', 'org.tukaani.xz', '1.6') {
|
||||
exports('org.tukaani.xz')
|
||||
module("kmp-tor-manager-jvm-${vKmpTor}.jar", 'kmp.tor.manager.jvm', "${vKmpTor}") {
|
||||
exports('io.matthewnelson.kmp.tor.manager')
|
||||
exports('io.matthewnelson.kmp.tor.manager.util')
|
||||
requires('kmp.tor.controller.common.jvm')
|
||||
requires('kmp.tor.manager.common.jvm')
|
||||
requires('kotlin.stdlib')
|
||||
requires('kotlinx.coroutines.core.jvm')
|
||||
requires('kotlinx.atomicfu')
|
||||
requires('kmp.tor.controller.jvm')
|
||||
requires('kmp.tor.common.jvm')
|
||||
}
|
||||
module('jsocks-1.0.jar', 'com.github.ravn.jsocks', '1.0') {
|
||||
exports('com.runjva.sourceforge.jsocks.protocol')
|
||||
requires('org.slf4j')
|
||||
module("kmp-tor-manager-common-jvm-${vKmpTor}.jar", 'kmp.tor.manager.common.jvm', "${vKmpTor}") {
|
||||
exports('io.matthewnelson.kmp.tor.manager.common')
|
||||
exports('io.matthewnelson.kmp.tor.manager.common.event')
|
||||
exports('io.matthewnelson.kmp.tor.manager.common.state')
|
||||
requires('kmp.tor.controller.common.jvm')
|
||||
requires('kmp.tor.common.jvm')
|
||||
requires('kotlin.stdlib')
|
||||
}
|
||||
module("kmp-tor-controller-common-jvm-${vKmpTor}.jar", 'kmp.tor.controller.common.jvm', "${vKmpTor}") {
|
||||
exports('io.matthewnelson.kmp.tor.controller.common.config')
|
||||
exports('io.matthewnelson.kmp.tor.controller.common.file')
|
||||
exports('io.matthewnelson.kmp.tor.controller.common.control')
|
||||
exports('io.matthewnelson.kmp.tor.controller.common.control.usecase')
|
||||
exports('io.matthewnelson.kmp.tor.controller.common.events')
|
||||
exports('io.matthewnelson.kmp.tor.controller.common.exceptions')
|
||||
requires('kmp.tor.common.jvm')
|
||||
requires('kotlin.stdlib')
|
||||
requires('kotlinx.atomicfu')
|
||||
}
|
||||
module("kmp-tor-common-jvm-${vKmpTor}.jar", 'kmp.tor.common.jvm', "${vKmpTor}") {
|
||||
exports('io.matthewnelson.kmp.tor.common.address')
|
||||
requires('parcelize.jvm')
|
||||
requires('kotlin.stdlib')
|
||||
}
|
||||
module("kmp-tor-controller-jvm-${vKmpTor}.jar", 'kmp.tor.controller.jvm', "${vKmpTor}") {
|
||||
exports('io.matthewnelson.kmp.tor.controller.internal.controller')
|
||||
requires('kmp.tor.common.jvm')
|
||||
requires('kmp.tor.controller.common.jvm')
|
||||
requires('kotlinx.coroutines.core.jvm')
|
||||
requires('kotlin.stdlib')
|
||||
requires('kotlinx.atomicfu')
|
||||
requires('encoding.core.jvm')
|
||||
requires('encoding.base16.jvm')
|
||||
}
|
||||
module("kmp-tor-ext-callback-common-jvm-${vKmpTor}.jar", 'kmp.tor.ext.callback.common.jvm', "${vKmpTor}") {
|
||||
exports('io.matthewnelson.kmp.tor.ext.callback.common')
|
||||
}
|
||||
module("kmp-tor-ext-callback-manager-jvm-${vKmpTor}.jar", 'kmp.tor.ext.callback.manager.jvm', "${vKmpTor}") {
|
||||
exports('io.matthewnelson.kmp.tor.ext.callback.manager')
|
||||
requires('kmp.tor.manager.jvm')
|
||||
requires('kmp.tor.ext.callback.common.jvm')
|
||||
requires('kmp.tor.ext.callback.manager.common.jvm')
|
||||
requires('kmp.tor.ext.callback.controller.common.jvm')
|
||||
requires('kmp.tor.manager.common.jvm')
|
||||
requires('kmp.tor.controller.common.jvm')
|
||||
requires('kotlin.stdlib')
|
||||
requires('kotlinx.coroutines.core.jvm')
|
||||
}
|
||||
module("kmp-tor-ext-callback-manager-common-jvm-${vKmpTor}.jar", 'kmp.tor.ext.callback.manager.common.jvm', "${vKmpTor}") {
|
||||
exports('io.matthewnelson.kmp.tor.ext.callback.manager.common')
|
||||
requires('kmp.tor.ext.callback.controller.common.jvm')
|
||||
}
|
||||
module("kmp-tor-ext-callback-controller-common-jvm-${vKmpTor}.jar", 'kmp.tor.ext.callback.controller.common.jvm', "${vKmpTor}") {
|
||||
exports('io.matthewnelson.kmp.tor.ext.callback.controller.common.control')
|
||||
exports('io.matthewnelson.kmp.tor.ext.callback.controller.common.control.usecase')
|
||||
}
|
||||
module("kmp-tor-binary-geoip-jvm-${vTor}.jar", 'kmp.tor.binary.geoip.jvm', "${vTor}") {
|
||||
exports('io.matthewnelson.kmp.tor.binary.geoip')
|
||||
exports('kmptor')
|
||||
}
|
||||
module("encoding-base16-jvm-1.2.1.jar", 'encoding.base16.jvm', "1.2.1") {
|
||||
exports('io.matthewnelson.encoding.base16')
|
||||
requires('encoding.core.jvm')
|
||||
requires('kotlin.stdlib')
|
||||
}
|
||||
module("encoding-base32-jvm-1.2.1.jar", 'encoding.base32.jvm', "1.2.1")
|
||||
module("encoding-base64-jvm-1.2.1.jar", 'encoding.base64.jvm', "1.2.1")
|
||||
module("encoding-core-jvm-1.2.1.jar", 'encoding.core.jvm', "1.2.1") {
|
||||
exports('io.matthewnelson.encoding.core')
|
||||
requires('kotlin.stdlib')
|
||||
}
|
||||
module("parcelize-jvm-0.1.2.jar", 'parcelize.jvm', "0.1.2") {
|
||||
exports('io.matthewnelson.component.parcelize')
|
||||
}
|
||||
module('jnacl-1.0.0.jar', 'eu.neilalexander.jnacl', '1.0.0')
|
||||
module('logback-core-1.2.8.jar', 'logback.core', '1.2.8') {
|
||||
|
|
|
@ -50,7 +50,6 @@ import javafx.stage.Screen;
|
|||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import javafx.util.Duration;
|
||||
import org.berndpruenster.netlayer.tor.Tor;
|
||||
import org.controlsfx.glyphfont.Glyph;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -252,7 +251,7 @@ public class AppServices {
|
|||
}
|
||||
|
||||
if(Tor.getDefault() != null) {
|
||||
Tor.getDefault().shutdown();
|
||||
Tor.getDefault().getTorManager().destroy(true, success -> {});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -414,23 +413,6 @@ 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()));
|
||||
});
|
||||
|
||||
|
@ -490,8 +472,7 @@ public class AppServices {
|
|||
InetSocketAddress proxyAddress = new InetSocketAddress(proxyHostAndPort.getHost(), proxyHostAndPort.getPortOrDefault(ProxyTcpOverTlsTransport.DEFAULT_PROXY_PORT));
|
||||
proxy = new Proxy(Proxy.Type.SOCKS, proxyAddress);
|
||||
} else if(AppServices.isTorRunning()) {
|
||||
InetSocketAddress proxyAddress = new InetSocketAddress("localhost", TorService.PROXY_PORT);
|
||||
proxy = new Proxy(Proxy.Type.SOCKS, proxyAddress);
|
||||
proxy = Tor.getDefault().getProxy();
|
||||
}
|
||||
|
||||
//Setting new proxy authentication credentials will force a new Tor circuit to be created
|
||||
|
@ -546,7 +527,7 @@ public class AppServices {
|
|||
|
||||
public static HostAndPort getTorProxy() {
|
||||
return AppServices.isTorRunning() ?
|
||||
HostAndPort.fromParts("localhost", TorService.PROXY_PORT) :
|
||||
Tor.getDefault().getProxyHostAndPort() :
|
||||
(Config.get().getProxyServer() == null || Config.get().getProxyServer().isEmpty() || !Config.get().isUseProxy() ? null : HostAndPort.fromString(Config.get().getProxyServer()));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
package com.sparrowwallet.sparrow;
|
||||
|
||||
import com.sparrowwallet.drongo.LogHandler;
|
||||
import com.sparrowwallet.sparrow.event.TorStatusEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.event.Level;
|
||||
|
||||
public class TorLogHandler implements LogHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(TorLogHandler.class);
|
||||
|
||||
@Override
|
||||
public void handleLog(String threadName, Level level, String message, String loggerName, long timestamp, StackTraceElement[] callerData) {
|
||||
log.debug(message);
|
||||
EventManager.get().post(new TorStatusEvent(message));
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
|||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import javafx.concurrent.ScheduledService;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.concurrent.Worker;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.Node;
|
||||
|
@ -33,15 +34,15 @@ public class TorStatusLabel extends Label {
|
|||
}
|
||||
|
||||
public void update() {
|
||||
boolean proxyInUse = AppServices.isUsingProxy();
|
||||
boolean internal = AppServices.isTorRunning();
|
||||
|
||||
if(!proxyInUse || internal) {
|
||||
if(!Config.get().isUseProxy()) {
|
||||
torConnectionTest.cancel();
|
||||
if(internal) {
|
||||
if(AppServices.isTorRunning()) {
|
||||
setTooltip(new Tooltip("Internal Tor proxy enabled"));
|
||||
}
|
||||
} else if(!torConnectionTest.isRunning()) {
|
||||
if(torConnectionTest.getState() == Worker.State.CANCELLED || torConnectionTest.getState() == Worker.State.FAILED) {
|
||||
torConnectionTest.reset();
|
||||
}
|
||||
torConnectionTest.setPeriod(Duration.seconds(20.0));
|
||||
torConnectionTest.setBackoffStrategy(null);
|
||||
torConnectionTest.setOnSucceeded(workerStateEvent -> {
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
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 instanceof TorServerAlreadyBoundException ? exception.getCause().getMessage() + " Is a Tor proxy already running?" :
|
||||
(exception.getCause() != null ? exception.getCause().getMessage() : exception.getMessage())));
|
||||
super("Tor failed to start: " + (exception.getCause() != null ? exception.getCause().getMessage() : exception.getMessage()));
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ public class Auth47 {
|
|||
}
|
||||
|
||||
Proxy proxy = AppServices.getProxy();
|
||||
if(proxy == null && callback.getHost().toLowerCase(Locale.ROOT).endsWith(TorService.TOR_ADDRESS_SUFFIX)) {
|
||||
if(proxy == null && callback.getHost().toLowerCase(Locale.ROOT).endsWith(Tor.TOR_ADDRESS_SUFFIX)) {
|
||||
throw new Auth47Exception("A Tor proxy must be configured to authenticate this resource.");
|
||||
}
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ public class Bwt {
|
|||
|
||||
private HostAndPort getTorProxy() {
|
||||
return AppServices.isTorRunning() ?
|
||||
HostAndPort.fromParts("127.0.0.1", TorService.PROXY_PORT) :
|
||||
Tor.getDefault().getProxyHostAndPort() :
|
||||
(Config.get().getProxyServer() == null || Config.get().getProxyServer().isEmpty() || !Config.get().isUseProxy() ? null : HostAndPort.fromString(Config.get().getProxyServer().replace("localhost", "127.0.0.1")));
|
||||
}
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ public class LnurlAuth {
|
|||
}
|
||||
|
||||
Proxy proxy = AppServices.getProxy();
|
||||
if(proxy == null && callback.getHost().toLowerCase(Locale.ROOT).endsWith(TorService.TOR_ADDRESS_SUFFIX)) {
|
||||
if(proxy == null && callback.getHost().toLowerCase(Locale.ROOT).endsWith(Tor.TOR_ADDRESS_SUFFIX)) {
|
||||
throw new LnurlAuthException("A Tor proxy must be configured to authenticate this resource.");
|
||||
}
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ public enum Protocol {
|
|||
}
|
||||
|
||||
public static boolean isOnionHost(String host) {
|
||||
return host != null && host.toLowerCase(Locale.ROOT).endsWith(TorService.TOR_ADDRESS_SUFFIX);
|
||||
return host != null && host.toLowerCase(Locale.ROOT).endsWith(Tor.TOR_ADDRESS_SUFFIX);
|
||||
}
|
||||
|
||||
public static boolean isOnionAddress(Server server) {
|
||||
|
|
|
@ -32,7 +32,7 @@ public class ProxyTcpOverTlsTransport extends TcpOverTlsTransport {
|
|||
protected void createSocket() throws IOException {
|
||||
InetSocketAddress proxyAddr = new InetSocketAddress(proxy.getHost(), proxy.getPortOrDefault(DEFAULT_PROXY_PORT));
|
||||
socket = new Socket(new Proxy(Proxy.Type.SOCKS, proxyAddr));
|
||||
socket.connect(new InetSocketAddress(server.getHost(), server.getPortOrDefault(Protocol.SSL.getDefaultPort())));
|
||||
socket.connect(new InetSocketAddress(server.getHost(), server.getPortOrDefault(getDefaultPort())));
|
||||
socket = sslSocketFactory.createSocket(socket, proxy.getHost(), proxy.getPortOrDefault(DEFAULT_PROXY_PORT), true);
|
||||
startHandshake((SSLSocket)socket);
|
||||
}
|
||||
|
|
|
@ -125,4 +125,9 @@ public class TcpOverTlsTransport extends TcpTransport {
|
|||
|
||||
return Storage.getCertificateFile(server.getHost()) == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultPort() {
|
||||
return Protocol.SSL.getDefaultPort();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -254,7 +254,11 @@ public class TcpTransport implements CloseableTransport, TimeoutCounter {
|
|||
|
||||
protected void createSocket() throws IOException {
|
||||
socket = socketFactory.createSocket();
|
||||
socket.connect(new InetSocketAddress(server.getHost(), server.getPortOrDefault(Protocol.TCP.getDefaultPort())));
|
||||
socket.connect(new InetSocketAddress(server.getHost(), server.getPortOrDefault(getDefaultPort())));
|
||||
}
|
||||
|
||||
protected int getDefaultPort() {
|
||||
return Protocol.TCP.getDefaultPort();
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
|
|
158
src/main/java/com/sparrowwallet/sparrow/net/Tor.java
Normal file
158
src/main/java/com/sparrowwallet/sparrow/net/Tor.java
Normal file
|
@ -0,0 +1,158 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.event.TorStatusEvent;
|
||||
import com.sparrowwallet.sparrow.io.Storage;
|
||||
import io.matthewnelson.kmp.tor.KmpTorLoaderJvm;
|
||||
import io.matthewnelson.kmp.tor.PlatformInstaller;
|
||||
import io.matthewnelson.kmp.tor.TorConfigProviderJvm;
|
||||
import io.matthewnelson.kmp.tor.binary.extract.TorBinaryResource;
|
||||
import io.matthewnelson.kmp.tor.common.address.Port;
|
||||
import io.matthewnelson.kmp.tor.common.address.ProxyAddress;
|
||||
import io.matthewnelson.kmp.tor.controller.common.config.TorConfig;
|
||||
import io.matthewnelson.kmp.tor.controller.common.file.Path;
|
||||
import io.matthewnelson.kmp.tor.ext.callback.manager.CallbackTorManager;
|
||||
import io.matthewnelson.kmp.tor.manager.TorManager;
|
||||
import io.matthewnelson.kmp.tor.manager.common.event.TorManagerEvent;
|
||||
import io.matthewnelson.kmp.tor.manager.util.PortUtil;
|
||||
import org.controlsfx.tools.Platform;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.util.List;
|
||||
|
||||
public class Tor {
|
||||
private static final Logger log = LoggerFactory.getLogger(Tor.class);
|
||||
|
||||
public static final String TOR_DIR = "tor";
|
||||
public static final String TOR_ADDRESS_SUFFIX = ".onion";
|
||||
|
||||
private static Tor tor;
|
||||
|
||||
private final Path path = Path.invoke(Storage.getSparrowHome().getAbsolutePath()).builder().addSegment(TOR_DIR).build();
|
||||
private final CallbackTorManager instance;
|
||||
private ProxyAddress socksAddress;
|
||||
|
||||
public Tor() {
|
||||
Platform platform = Platform.getCurrent();
|
||||
String arch = System.getProperty("os.arch");
|
||||
PlatformInstaller installer;
|
||||
PlatformInstaller.InstallOption installOption = PlatformInstaller.InstallOption.CleanInstallIfMissing;
|
||||
|
||||
if(platform == Platform.OSX) {
|
||||
if(arch.equals("aarch64")) {
|
||||
installer = PlatformInstaller.macosArm64(installOption);
|
||||
} else {
|
||||
installer = PlatformInstaller.macosX64(installOption);
|
||||
}
|
||||
} else if(platform == Platform.WINDOWS) {
|
||||
installer = PlatformInstaller.mingwX64(installOption);
|
||||
} else if(platform == Platform.UNIX) {
|
||||
if(arch.equals("aarch64")) {
|
||||
TorBinaryResource linuxArm64 = TorBinaryResource.from(TorBinaryResource.OS.Linux, "arm64",
|
||||
"588496f3164d52b91f17e4db3372d8dfefa6366a8df265eebd4a28d4128992aa",
|
||||
List.of("libevent-2.1.so.7.gz", "libstdc++.so.6.gz", "libcrypto.so.1.1.gz", "tor.gz", "libssl.so.1.1.gz"));
|
||||
installer = PlatformInstaller.custom(installOption, linuxArm64);
|
||||
} else {
|
||||
installer = PlatformInstaller.linuxX64(installOption);
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Sparrow's bundled Tor is not supported on " + platform + " " + arch);
|
||||
}
|
||||
|
||||
TorConfigProviderJvm torConfigProviderJvm = new TorConfigProviderJvm() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Path getWorkDir() {
|
||||
return path.builder().addSegment("work").build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Path getCacheDir() {
|
||||
return path.builder().addSegment("cache").build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected TorConfig provide() {
|
||||
TorConfig.Builder builder = new TorConfig.Builder();
|
||||
|
||||
TorConfig.Setting.DormantCanceledByStartup dormantCanceledByStartup = new TorConfig.Setting.DormantCanceledByStartup();
|
||||
dormantCanceledByStartup.set(TorConfig.Option.AorTorF.getTrue());
|
||||
builder.put(dormantCanceledByStartup);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
};
|
||||
|
||||
KmpTorLoaderJvm jvmLoader = new KmpTorLoaderJvm(installer, torConfigProviderJvm);
|
||||
TorManager torManager = TorManager.newInstance(jvmLoader);
|
||||
|
||||
torManager.debug(true);
|
||||
torManager.addListener(new TorManagerEvent.Listener() {
|
||||
@Override
|
||||
public void managerEventWarn(@NotNull String message) {
|
||||
log.warn(message);
|
||||
EventManager.get().post(new TorStatusEvent(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void managerEventInfo(@NotNull String message) {
|
||||
log.info(message);
|
||||
EventManager.get().post(new TorStatusEvent(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void managerEventDebug(@NotNull String message) {
|
||||
log.debug(message);
|
||||
EventManager.get().post(new TorStatusEvent(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void managerEventAddressInfo(@NotNull TorManagerEvent.AddressInfo info) {
|
||||
if(info.isNull) {
|
||||
socksAddress = null;
|
||||
} else {
|
||||
socksAddress = info.socksInfoToProxyAddress().iterator().next();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.instance = new CallbackTorManager(torManager, uncaughtException -> {
|
||||
log.error("Uncaught exception from CallbackTorManager", uncaughtException);
|
||||
});
|
||||
}
|
||||
|
||||
public static Tor getDefault() {
|
||||
return Tor.tor;
|
||||
}
|
||||
|
||||
public static void setDefault(Tor tor) {
|
||||
Tor.tor = tor;
|
||||
}
|
||||
|
||||
public CallbackTorManager getTorManager() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Proxy getProxy() {
|
||||
if(socksAddress == null) {
|
||||
throw new IllegalStateException("Tor socks proxy is not yet instantiated");
|
||||
}
|
||||
|
||||
return new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(socksAddress.address.getValue(), socksAddress.port.getValue()));
|
||||
}
|
||||
|
||||
public HostAndPort getProxyHostAndPort() {
|
||||
return HostAndPort.fromParts(socksAddress.address.getValue(), socksAddress.port.getValue());
|
||||
}
|
||||
|
||||
public static boolean isRunningExternally() {
|
||||
return !PortUtil.isTcpPortAvailable(Port.invoke(9050));
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,10 @@ public class TorServerException extends ServerException {
|
|||
super(cause);
|
||||
}
|
||||
|
||||
public TorServerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public TorServerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
|
|
@ -1,86 +1,85 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import io.matthewnelson.kmp.tor.ext.callback.manager.CallbackTorManager;
|
||||
import io.matthewnelson.kmp.tor.manager.common.event.TorManagerEvent;
|
||||
import javafx.concurrent.ScheduledService;
|
||||
import javafx.concurrent.Task;
|
||||
import net.freehaven.tor.control.TorControlError;
|
||||
import org.berndpruenster.netlayer.tor.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.Socket;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Service to start internal Tor (including a Tor proxy running on localhost:9050)
|
||||
* Service to start internal Tor (including a Tor proxy running on localhost:9050, or another port if unavailable)
|
||||
*
|
||||
* This is a ScheduledService to take advantage of the retry on failure behaviour
|
||||
*/
|
||||
public class TorService extends ScheduledService<NativeTor> {
|
||||
public class TorService extends ScheduledService<Tor> {
|
||||
private static final Logger log = LoggerFactory.getLogger(TorService.class);
|
||||
|
||||
public static final int PROXY_PORT = 9050;
|
||||
public static final String TOR_DIR_PREFIX = "tor";
|
||||
public static final String TOR_ADDRESS_SUFFIX = ".onion";
|
||||
private final ReentrantLock startupLock = new ReentrantLock();
|
||||
private final Condition startupCondition = startupLock.newCondition();
|
||||
|
||||
@Override
|
||||
protected Task<NativeTor> createTask() {
|
||||
protected Task<Tor> createTask() {
|
||||
return new Task<>() {
|
||||
protected NativeTor call() throws IOException, TorServerException {
|
||||
if(Tor.getDefault() == null) {
|
||||
Path path = Files.createTempDirectory(TOR_DIR_PREFIX);
|
||||
File torInstallDir = path.toFile();
|
||||
torInstallDir.deleteOnExit();
|
||||
try {
|
||||
LinkedHashMap<String, String> torrcOptionsMap = new LinkedHashMap<>();
|
||||
torrcOptionsMap.put("SocksPort", Integer.toString(PROXY_PORT));
|
||||
torrcOptionsMap.put("HashedControlPassword", "16:D780432418F09B06609940000924317D3B9DF522A3191F8F4E597E9329");
|
||||
torrcOptionsMap.put("DisableNetwork", "0");
|
||||
Torrc override = new Torrc(torrcOptionsMap);
|
||||
private Exception startupException;
|
||||
|
||||
return new NativeTor(torInstallDir, Collections.emptyList(), override);
|
||||
} catch(TorCtlException e) {
|
||||
if(e.getCause() instanceof TorControlError) {
|
||||
if(e.getCause().getMessage().contains("Failed to bind")) {
|
||||
throw new TorServerAlreadyBoundException("Tor server already bound", e.getCause());
|
||||
@Override
|
||||
protected Tor call() throws Exception {
|
||||
Tor tor = Tor.getDefault();
|
||||
if(tor == null) {
|
||||
tor = new Tor();
|
||||
CallbackTorManager callbackTorManager = tor.getTorManager();
|
||||
callbackTorManager.addListener(new TorManagerEvent.Listener() {
|
||||
@Override
|
||||
public void managerEventAddressInfo(@NotNull TorManagerEvent.AddressInfo info) {
|
||||
if(!info.isNull) {
|
||||
try {
|
||||
startupLock.lock();
|
||||
startupCondition.signalAll();
|
||||
} finally {
|
||||
startupLock.unlock();
|
||||
}
|
||||
}
|
||||
log.error("Failed to start Tor", e);
|
||||
throw new TorServerException("Failed to start Tor", e.getCause());
|
||||
} else {
|
||||
log.error("Failed to start Tor", e);
|
||||
throw new TorServerException("Failed to start Tor", e);
|
||||
}
|
||||
});
|
||||
callbackTorManager.start(throwable -> {
|
||||
if(throwable instanceof Exception exception) {
|
||||
startupException = exception;
|
||||
} else {
|
||||
startupException = new Exception(throwable);
|
||||
}
|
||||
log.error("Error", throwable);
|
||||
try {
|
||||
startupLock.lock();
|
||||
startupCondition.signalAll();
|
||||
} finally {
|
||||
startupLock.unlock();
|
||||
}
|
||||
}, success -> {
|
||||
log.info("Tor daemon started successfully");
|
||||
});
|
||||
|
||||
try {
|
||||
startupLock.lock();
|
||||
if(!startupCondition.await(5, TimeUnit.MINUTES)) {
|
||||
throw new TorStartupException("Tor failed to start after 5 minutes, giving up");
|
||||
}
|
||||
|
||||
if(startupException != null) {
|
||||
throw startupException;
|
||||
}
|
||||
} finally {
|
||||
startupLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return tor;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Socket getControlSocket() {
|
||||
Tor tor = Tor.getDefault();
|
||||
if(tor != null) {
|
||||
try {
|
||||
Class<?> torClass = Class.forName("org.berndpruenster.netlayer.tor.Tor");
|
||||
Field torControllerField = torClass.getDeclaredField("torController");
|
||||
torControllerField.setAccessible(true);
|
||||
TorController torController = (TorController)torControllerField.get(tor);
|
||||
|
||||
Class<?> torControllerClass = Class.forName("org.berndpruenster.netlayer.tor.TorController");
|
||||
Field socketField = torControllerClass.getDeclaredField("socket");
|
||||
socketField.setAccessible(true);
|
||||
return (Socket)socketField.get(torController);
|
||||
} catch(Exception e) {
|
||||
log.error("Error retrieving Tor control socket", e);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
public class TorStartupException extends TorServerException {
|
||||
public TorStartupException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public TorStartupException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public TorStartupException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -27,21 +27,15 @@ public class TorTcpOverTlsTransport extends TcpOverTlsTransport {
|
|||
|
||||
@Override
|
||||
protected void createSocket() throws IOException {
|
||||
TorTcpTransport torTcpTransport = new TorTcpTransport(server);
|
||||
TorTcpTransport torTcpTransport = new TorTcpTransport(server) {
|
||||
@Override
|
||||
protected int getDefaultPort() {
|
||||
return Protocol.SSL.getDefaultPort();
|
||||
}
|
||||
};
|
||||
torTcpTransport.createSocket();
|
||||
socket = torTcpTransport.socket;
|
||||
|
||||
try {
|
||||
Field socketField = socket.getClass().getDeclaredField("socket");
|
||||
socketField.setAccessible(true);
|
||||
Socket innerSocket = (Socket)socketField.get(socket);
|
||||
Field connectedField = innerSocket.getClass().getSuperclass().getDeclaredField("connected");
|
||||
connectedField.setAccessible(true);
|
||||
connectedField.set(innerSocket, true);
|
||||
} catch(Exception e) {
|
||||
log.error("Could not set socket connected status", e);
|
||||
}
|
||||
|
||||
socket = sslSocketFactory.createSocket(socket, server.getHost(), server.getPortOrDefault(Protocol.SSL.getDefaultPort()), true);
|
||||
startHandshake((SSLSocket)socket);
|
||||
}
|
||||
|
|
|
@ -2,14 +2,12 @@ package com.sparrowwallet.sparrow.net;
|
|||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import org.berndpruenster.netlayer.tor.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
public class TorTcpTransport extends TcpTransport {
|
||||
public static final String TOR_DIR_PREFIX = "tor";
|
||||
|
||||
public TorTcpTransport(HostAndPort server) {
|
||||
super(server);
|
||||
}
|
||||
|
@ -24,6 +22,7 @@ public class TorTcpTransport extends TcpTransport {
|
|||
throw new IllegalStateException("Can't create Tor socket, Tor is not running");
|
||||
}
|
||||
|
||||
socket = new TorSocket(server.getHost(), server.getPortOrDefault(Protocol.TCP.getDefaultPort()), "sparrow");
|
||||
socket = new Socket(Tor.getDefault().getProxy());
|
||||
socket.connect(new InetSocketAddress(server.getHost(), server.getPortOrDefault(getDefaultPort())));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,6 @@ import javafx.stage.DirectoryChooser;
|
|||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.util.Duration;
|
||||
import javafx.util.StringConverter;
|
||||
import org.berndpruenster.netlayer.tor.Tor;
|
||||
import org.controlsfx.control.SegmentedButton;
|
||||
import org.controlsfx.glyphfont.Glyph;
|
||||
import org.controlsfx.validation.ValidationResult;
|
||||
|
@ -494,20 +492,6 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
torService.cancel();
|
||||
testResults.appendText("\nTor failed to start");
|
||||
showConnectionFailure(workerStateEvent.getSource().getException());
|
||||
|
||||
Throwable exception = workerStateEvent.getSource().getException();
|
||||
if(Config.get().getServerType() == ServerType.ELECTRUM_SERVER &&
|
||||
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");
|
||||
useProxyOriginal = false;
|
||||
testResults.appendText("\n\nAssuming Tor proxy is running on port 9050 and trying again...");
|
||||
startElectrumConnection();
|
||||
}
|
||||
});
|
||||
|
||||
torService.start();
|
||||
|
@ -658,8 +642,6 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
reason = tlsServerException.getMessage() + "\n\n" + reason;
|
||||
} 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 + "?";
|
||||
} else if(reason != null && (reason.contains("Check if Bitcoin Core is running") || reason.contains("Could not connect to Bitcoin Core RPC"))) {
|
||||
reason += "\n\nSee https://sparrowwallet.com/docs/connect-node.html";
|
||||
} else if(reason != null && (reason.startsWith("Cannot connect to hidden service"))) {
|
||||
|
|
|
@ -15,7 +15,6 @@ import com.sparrowwallet.sparrow.terminal.SparrowTerminal;
|
|||
import javafx.application.Platform;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.util.Duration;
|
||||
import org.berndpruenster.netlayer.tor.Tor;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DateFormat;
|
||||
|
@ -203,8 +202,6 @@ public class ServerTestDialog extends DialogWindow {
|
|||
reason = tlsServerException.getMessage() + "\n\n" + reason;
|
||||
} 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 + "?";
|
||||
} else if(reason != null && reason.contains("Check if Bitcoin Core is running")) {
|
||||
reason += "\n\nSee https://sparrowwallet.com/docs/connect-node.html";
|
||||
}
|
||||
|
|
|
@ -2,8 +2,10 @@ package com.sparrowwallet.sparrow.whirlpool.tor;
|
|||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.samourai.tor.client.TorClientService;
|
||||
import com.sparrowwallet.sparrow.net.TorService;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.net.Tor;
|
||||
import com.sparrowwallet.sparrow.whirlpool.Whirlpool;
|
||||
import io.matthewnelson.kmp.tor.controller.common.control.usecase.TorControlSignal;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -23,13 +25,12 @@ public class SparrowTorClientService extends TorClientService {
|
|||
public void changeIdentity() {
|
||||
HostAndPort proxy = whirlpool.getTorProxy();
|
||||
if(proxy != null) {
|
||||
Socket controlSocket = TorService.getControlSocket();
|
||||
if(controlSocket != null) {
|
||||
try {
|
||||
writeNewNym(controlSocket);
|
||||
} catch(Exception e) {
|
||||
log.warn("Error sending NEWNYM to " + controlSocket, e);
|
||||
}
|
||||
if(AppServices.isTorRunning()) {
|
||||
Tor.getDefault().getTorManager().signal(TorControlSignal.Signal.NewNym, throwable -> {
|
||||
log.warn("Failed to signal newnym");
|
||||
}, successEvent -> {
|
||||
log.info("Signalled newnym for new Tor circuit");
|
||||
});
|
||||
} else {
|
||||
HostAndPort control = HostAndPort.fromParts(proxy.getHost(), proxy.getPort() + 1);
|
||||
try(Socket socket = new Socket(control.getHost(), control.getPort())) {
|
||||
|
|
|
@ -19,7 +19,19 @@ open module com.sparrowwallet.sparrow {
|
|||
requires org.jetbrains.annotations;
|
||||
requires com.fasterxml.jackson.databind;
|
||||
requires com.fasterxml.jackson.annotation;
|
||||
requires netlayer.jpms;
|
||||
requires kotlin.stdlib;
|
||||
requires kmp.tor.jvm;
|
||||
requires kmp.tor.binary.extract.jvm;
|
||||
requires kmp.tor.common.jvm;
|
||||
requires kmp.tor.controller.common.jvm;
|
||||
requires kmp.tor.manager.jvm;
|
||||
requires kmp.tor.manager.common.jvm;
|
||||
requires kmp.tor.ext.callback.manager.jvm;
|
||||
requires kmp.tor.ext.callback.common.jvm;
|
||||
requires kmp.tor.ext.callback.manager.common.jvm;
|
||||
requires kmp.tor.ext.callback.controller.common.jvm;
|
||||
requires parcelize.jvm;
|
||||
requires kotlinx.coroutines.javafx;
|
||||
requires org.slf4j;
|
||||
requires com.google.gson;
|
||||
requires org.jdbi.v3.core;
|
||||
|
@ -31,7 +43,6 @@ open module com.sparrowwallet.sparrow {
|
|||
requires org.fxmisc.flowless;
|
||||
requires com.github.sarxos.webcam.capture;
|
||||
requires centerdevice.nsmenufx;
|
||||
requires com.github.JesusMcCloud.jtorctl;
|
||||
requires com.beust.jcommander;
|
||||
requires org.slf4j.jul.to.slf4j;
|
||||
requires net.sourceforge.javacsv;
|
||||
|
|
|
@ -60,14 +60,6 @@
|
|||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="APPLICATION_TOR" class="com.sparrowwallet.drongo.ApplicationAppender">
|
||||
<callback>com.sparrowwallet.sparrow.TorLogHandler</callback>
|
||||
</appender>
|
||||
|
||||
<logger name="org.berndpruenster.netlayer.tor" level="debug" additivity="false">
|
||||
<appender-ref ref="APPLICATION_TOR" />
|
||||
</logger>
|
||||
|
||||
<root level="warn">
|
||||
<appender-ref ref="FILE" />
|
||||
<appender-ref ref="STDOUT" />
|
||||
|
|
Loading…
Reference in a new issue