mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
switch from httpurlconnection to jetty http client to avoid spurious dns query
This commit is contained in:
parent
d84ade5b7d
commit
c81c42a87c
16 changed files with 229 additions and 260 deletions
|
@ -121,7 +121,7 @@ dependencies {
|
|||
implementation('org.slf4j:jul-to-slf4j:1.7.30') {
|
||||
exclude group: 'org.slf4j'
|
||||
}
|
||||
implementation('com.sparrowwallet.nightjar:nightjar:0.2.37')
|
||||
implementation('com.sparrowwallet.nightjar:nightjar:0.2.38')
|
||||
implementation('io.reactivex.rxjava2:rxjava:2.2.15')
|
||||
implementation('io.reactivex.rxjava2:rxjavafx:2.2.2')
|
||||
implementation('org.apache.commons:commons-lang3:3.7')
|
||||
|
@ -508,7 +508,7 @@ extraJavaModuleInfo {
|
|||
exports('co.nstant.in.cbor.model')
|
||||
exports('co.nstant.in.cbor.builder')
|
||||
}
|
||||
module('nightjar-0.2.37.jar', 'com.sparrowwallet.nightjar', '0.2.37') {
|
||||
module('nightjar-0.2.38.jar', 'com.sparrowwallet.nightjar', '0.2.38') {
|
||||
requires('com.google.common')
|
||||
requires('net.sourceforge.streamsupport')
|
||||
requires('org.slf4j')
|
||||
|
|
|
@ -24,7 +24,6 @@ import com.sparrowwallet.sparrow.control.TrayManager;
|
|||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.io.*;
|
||||
import com.sparrowwallet.sparrow.net.*;
|
||||
import com.sparrowwallet.sparrow.paynym.PayNymService;
|
||||
import com.sparrowwallet.sparrow.soroban.SorobanServices;
|
||||
import com.sparrowwallet.sparrow.whirlpool.WhirlpoolServices;
|
||||
import javafx.application.Application;
|
||||
|
@ -61,7 +60,6 @@ import java.awt.event.KeyEvent;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
|
@ -96,7 +94,7 @@ public class AppServices {
|
|||
|
||||
private InteractionServices interactionServices;
|
||||
|
||||
private static PayNymService payNymService;
|
||||
private static HttpClientService httpClientService;
|
||||
|
||||
private final Application application;
|
||||
|
||||
|
@ -247,8 +245,8 @@ public class AppServices {
|
|||
versionCheckService.cancel();
|
||||
}
|
||||
|
||||
if(payNymService != null) {
|
||||
PayNymService.ShutdownService shutdownService = new PayNymService.ShutdownService(payNymService);
|
||||
if(httpClientService != null) {
|
||||
HttpClientService.ShutdownService shutdownService = new HttpClientService.ShutdownService(httpClientService);
|
||||
shutdownService.start();
|
||||
}
|
||||
|
||||
|
@ -513,18 +511,18 @@ public class AppServices {
|
|||
return get().interactionServices;
|
||||
}
|
||||
|
||||
public static PayNymService getPayNymService() {
|
||||
if(payNymService == null) {
|
||||
public static HttpClientService getHttpClientService() {
|
||||
if(httpClientService == null) {
|
||||
HostAndPort torProxy = getTorProxy();
|
||||
payNymService = new PayNymService(torProxy);
|
||||
httpClientService = new HttpClientService(torProxy);
|
||||
} else {
|
||||
HostAndPort torProxy = getTorProxy();
|
||||
if(!Objects.equals(payNymService.getTorProxy(), torProxy)) {
|
||||
payNymService.setTorProxy(getTorProxy());
|
||||
if(!Objects.equals(httpClientService.getTorProxy(), torProxy)) {
|
||||
httpClientService.setTorProxy(getTorProxy());
|
||||
}
|
||||
}
|
||||
|
||||
return payNymService;
|
||||
return httpClientService;
|
||||
}
|
||||
|
||||
public static HostAndPort getTorProxy() {
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.sparrowwallet.drongo.Network;
|
||||
import com.sparrowwallet.drongo.Utils;
|
||||
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||
import com.sparrowwallet.nightjar.http.JavaHttpException;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -30,7 +28,7 @@ public enum BroadcastSource {
|
|||
return List.of(Network.MAINNET, Network.TESTNET);
|
||||
}
|
||||
|
||||
protected URL getURL(Proxy proxy) throws MalformedURLException {
|
||||
protected URL getURL(HostAndPort proxy) throws MalformedURLException {
|
||||
if(Network.get() == Network.MAINNET) {
|
||||
return new URL(getBaseUrl(proxy) + "/api/tx");
|
||||
} else if(Network.get() == Network.TESTNET) {
|
||||
|
@ -51,7 +49,7 @@ public enum BroadcastSource {
|
|||
return List.of(Network.MAINNET, Network.TESTNET, Network.SIGNET);
|
||||
}
|
||||
|
||||
protected URL getURL(Proxy proxy) throws MalformedURLException {
|
||||
protected URL getURL(HostAndPort proxy) throws MalformedURLException {
|
||||
if(Network.get() == Network.MAINNET) {
|
||||
return new URL(getBaseUrl(proxy) + "/api/tx");
|
||||
} else if(Network.get() == Network.TESTNET) {
|
||||
|
@ -74,7 +72,7 @@ public enum BroadcastSource {
|
|||
return List.of(Network.MAINNET);
|
||||
}
|
||||
|
||||
protected URL getURL(Proxy proxy) throws MalformedURLException {
|
||||
protected URL getURL(HostAndPort proxy) throws MalformedURLException {
|
||||
if(Network.get() == Network.MAINNET) {
|
||||
return new URL(getBaseUrl(proxy) + "/api/tx");
|
||||
} else if(Network.get() == Network.TESTNET) {
|
||||
|
@ -95,7 +93,7 @@ public enum BroadcastSource {
|
|||
return List.of(Network.MAINNET);
|
||||
}
|
||||
|
||||
protected URL getURL(Proxy proxy) throws MalformedURLException {
|
||||
protected URL getURL(HostAndPort proxy) throws MalformedURLException {
|
||||
if(Network.get() == Network.MAINNET) {
|
||||
return new URL(getBaseUrl(proxy) + "/api/tx");
|
||||
} else if(Network.get() == Network.TESTNET) {
|
||||
|
@ -131,7 +129,7 @@ public enum BroadcastSource {
|
|||
return onionUrl;
|
||||
}
|
||||
|
||||
public String getBaseUrl(Proxy proxy) {
|
||||
public String getBaseUrl(HostAndPort proxy) {
|
||||
return (proxy == null ? getTlsUrl() : getOnionUrl());
|
||||
}
|
||||
|
||||
|
@ -139,48 +137,30 @@ public enum BroadcastSource {
|
|||
|
||||
public abstract List<Network> getSupportedNetworks();
|
||||
|
||||
protected abstract URL getURL(Proxy proxy) throws MalformedURLException;
|
||||
protected abstract URL getURL(HostAndPort proxy) throws MalformedURLException;
|
||||
|
||||
public Sha256Hash postTransactionData(String data) throws BroadcastException {
|
||||
//If a Tor proxy is configured, ensure we use a new circuit by configuring a random proxy password
|
||||
Proxy proxy = AppServices.getProxy(Integer.toString(secureRandom.nextInt()));
|
||||
HttpClientService httpClientService = AppServices.getHttpClientService();
|
||||
httpClientService.changeIdentity();
|
||||
|
||||
try {
|
||||
URL url = getURL(proxy);
|
||||
URL url = getURL(httpClientService.getTorProxy());
|
||||
|
||||
if(log.isInfoEnabled()) {
|
||||
log.info("Broadcasting transaction to " + url);
|
||||
}
|
||||
|
||||
HttpURLConnection connection = proxy == null ? (HttpURLConnection)url.openConnection() : (HttpURLConnection)url.openConnection(proxy);
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "text/plain");
|
||||
connection.setDoOutput(true);
|
||||
|
||||
try(OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream())) {
|
||||
writer.write(data);
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
StringBuilder response = new StringBuilder();
|
||||
try(BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
String responseLine;
|
||||
while((responseLine = br.readLine()) != null) {
|
||||
response.append(responseLine.trim());
|
||||
}
|
||||
}
|
||||
|
||||
int statusCode = connection.getResponseCode();
|
||||
if(statusCode < 200 || statusCode >= 300) {
|
||||
throw new BroadcastException("Could not broadcast transaction, server returned " + statusCode + ": " + response);
|
||||
}
|
||||
String response = httpClientService.postString(url.toString(), null, "text/plain", data);
|
||||
|
||||
try {
|
||||
return Sha256Hash.wrap(response.toString().trim());
|
||||
return Sha256Hash.wrap(response.trim());
|
||||
} catch(Exception e) {
|
||||
throw new BroadcastException("Could not retrieve txid from broadcast, server returned " + statusCode + ": " + response);
|
||||
throw new BroadcastException("Could not retrieve txid from broadcast, server returned: " + response);
|
||||
}
|
||||
} catch(IOException e) {
|
||||
} catch(JavaHttpException e) {
|
||||
throw new BroadcastException("Could not broadcast transaction, server returned " + e.getStatusCode() + ": " + e.getResponseBody());
|
||||
} catch(Exception e) {
|
||||
log.error("Could not post transaction via " + getName(), e);
|
||||
throw new BroadcastException("Could not broadcast transaction via " + getName(), e);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import com.sparrowwallet.sparrow.io.Server;
|
|||
import com.sparrowwallet.sparrow.net.cormorant.Cormorant;
|
||||
import com.sparrowwallet.sparrow.net.cormorant.bitcoind.CormorantBitcoindException;
|
||||
import com.sparrowwallet.sparrow.paynym.PayNym;
|
||||
import com.sparrowwallet.sparrow.paynym.PayNymService;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
|
@ -1882,7 +1883,7 @@ public class ElectrumServer {
|
|||
|
||||
private PayNym getPayNym(PaymentCode paymentCode) {
|
||||
try {
|
||||
return AppServices.getPayNymService().getPayNym(paymentCode.toString()).blockingFirst();
|
||||
return PayNymService.getPayNym(paymentCode.toString()).blockingFirst();
|
||||
} catch(Exception e) {
|
||||
//ignore
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.event.ExchangeRatesUpdatedEvent;
|
||||
import javafx.concurrent.ScheduledService;
|
||||
|
@ -9,12 +8,6 @@ import javafx.concurrent.Task;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -50,15 +43,14 @@ public enum ExchangeSource {
|
|||
|
||||
private CoinbaseRates getRates() {
|
||||
String url = "https://api.coinbase.com/v2/exchange-rates?currency=BTC";
|
||||
Proxy proxy = AppServices.getProxy();
|
||||
|
||||
if(log.isInfoEnabled()) {
|
||||
log.info("Requesting exchange rates from " + url);
|
||||
}
|
||||
|
||||
try(InputStream is = (proxy == null ? new URL(url).openStream() : new URL(url).openConnection(proxy).getInputStream()); Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
|
||||
Gson gson = new Gson();
|
||||
return gson.fromJson(reader, CoinbaseRates.class);
|
||||
HttpClientService httpClientService = AppServices.getHttpClientService();
|
||||
try {
|
||||
return httpClientService.requestJson(url, CoinbaseRates.class, null);
|
||||
} catch (Exception e) {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.warn("Error retrieving currency rates", e);
|
||||
|
@ -89,15 +81,14 @@ public enum ExchangeSource {
|
|||
|
||||
private CoinGeckoRates getRates() {
|
||||
String url = "https://api.coingecko.com/api/v3/exchange_rates";
|
||||
Proxy proxy = AppServices.getProxy();
|
||||
|
||||
if(log.isInfoEnabled()) {
|
||||
log.info("Requesting exchange rates from " + url);
|
||||
}
|
||||
|
||||
try(InputStream is = (proxy == null ? new URL(url).openStream() : new URL(url).openConnection(proxy).getInputStream()); Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
|
||||
Gson gson = new Gson();
|
||||
return gson.fromJson(reader, CoinGeckoRates.class);
|
||||
HttpClientService httpClientService = AppServices.getHttpClientService();
|
||||
try {
|
||||
return httpClientService.requestJson(url, CoinGeckoRates.class, null);
|
||||
} catch(Exception e) {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.warn("Error retrieving currency rates", e);
|
||||
|
@ -176,22 +167,22 @@ public enum ExchangeSource {
|
|||
}
|
||||
|
||||
private static class CoinbaseRates {
|
||||
CoinbaseData data;
|
||||
public CoinbaseData data = new CoinbaseData();
|
||||
}
|
||||
|
||||
private static class CoinbaseData {
|
||||
String currency;
|
||||
Map<String, Double> rates;
|
||||
public String currency;
|
||||
public Map<String, Double> rates = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
private static class CoinGeckoRates {
|
||||
Map<String, CoinGeckoRate> rates = new LinkedHashMap<>();
|
||||
public Map<String, CoinGeckoRate> rates = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
private static class CoinGeckoRate {
|
||||
String name;
|
||||
String unit;
|
||||
Double value;
|
||||
String type;
|
||||
public String name;
|
||||
public String unit;
|
||||
public Double value;
|
||||
public String type;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
@ -66,16 +59,14 @@ public enum FeeRatesSource {
|
|||
}
|
||||
|
||||
private static Map<Integer, Double> getThreeTierFeeRates(Map<Integer, Double> defaultblockTargetFeeRates, String url) {
|
||||
Proxy proxy = AppServices.getProxy();
|
||||
|
||||
if(log.isInfoEnabled()) {
|
||||
log.info("Requesting fee rates from " + url);
|
||||
}
|
||||
|
||||
Map<Integer, Double> blockTargetFeeRates = new LinkedHashMap<>();
|
||||
try(InputStream is = (proxy == null ? new URL(url).openStream() : new URL(url).openConnection(proxy).getInputStream()); Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
|
||||
Gson gson = new Gson();
|
||||
ThreeTierRates threeTierRates = gson.fromJson(reader, ThreeTierRates.class);
|
||||
HttpClientService httpClientService = AppServices.getHttpClientService();
|
||||
try {
|
||||
ThreeTierRates threeTierRates = httpClientService.requestJson(url, ThreeTierRates.class, null);
|
||||
Double lastRate = null;
|
||||
for(Integer blockTarget : defaultblockTargetFeeRates.keySet()) {
|
||||
if(blockTarget < BLOCKS_IN_HALF_HOUR) {
|
||||
|
@ -116,9 +107,9 @@ public enum FeeRatesSource {
|
|||
}
|
||||
|
||||
private static class ThreeTierRates {
|
||||
Double fastestFee;
|
||||
Double halfHourFee;
|
||||
Double hourFee;
|
||||
Double minimumFee;
|
||||
public Double fastestFee;
|
||||
public Double halfHourFee;
|
||||
public Double hourFee;
|
||||
public Double minimumFee;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.samourai.http.client.HttpUsage;
|
||||
import com.samourai.http.client.IHttpClient;
|
||||
import com.sparrowwallet.nightjar.http.JavaHttpClientService;
|
||||
import io.reactivex.Observable;
|
||||
import java8.util.Optional;
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpClientService {
|
||||
private final JavaHttpClientService httpClientService;
|
||||
|
||||
public HttpClientService(HostAndPort torProxy) {
|
||||
this.httpClientService = new JavaHttpClientService(torProxy, 120000);
|
||||
}
|
||||
|
||||
public <T> T requestJson(String url, Class<T> responseType, Map<String, String> headers) throws Exception {
|
||||
IHttpClient httpClient = httpClientService.getHttpClient(HttpUsage.COORDINATOR_REST);
|
||||
return httpClient.getJson(url, responseType, headers);
|
||||
}
|
||||
|
||||
public <T> Observable<Optional<T>> postJson(String url, Class<T> responseType, Map<String, String> headers, Object body) {
|
||||
IHttpClient httpClient = httpClientService.getHttpClient(HttpUsage.COORDINATOR_REST);
|
||||
return httpClient.postJson(url, responseType, headers, body);
|
||||
}
|
||||
|
||||
public String postString(String url, Map<String, String> headers, String contentType, String content) throws Exception {
|
||||
IHttpClient httpClient = httpClientService.getHttpClient(HttpUsage.COORDINATOR_REST);
|
||||
return httpClient.postString(url, headers, contentType, content);
|
||||
}
|
||||
|
||||
public void changeIdentity() {
|
||||
HostAndPort torProxy = getTorProxy();
|
||||
if(torProxy != null) {
|
||||
TorUtils.changeIdentity(torProxy);
|
||||
}
|
||||
}
|
||||
|
||||
public HostAndPort getTorProxy() {
|
||||
return httpClientService.getTorProxy();
|
||||
}
|
||||
|
||||
public void setTorProxy(HostAndPort torProxy) {
|
||||
//Ensure all http clients are shutdown first
|
||||
httpClientService.shutdown();
|
||||
httpClientService.setTorProxy(torProxy);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
httpClientService.shutdown();
|
||||
}
|
||||
|
||||
public static class ShutdownService extends Service<Boolean> {
|
||||
private final HttpClientService httpClientService;
|
||||
|
||||
public ShutdownService(HttpClientService httpClientService) {
|
||||
this.httpClientService = httpClientService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Task<Boolean> createTask() {
|
||||
return new Task<>() {
|
||||
protected Boolean call() throws Exception {
|
||||
httpClientService.shutdown();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
37
src/main/java/com/sparrowwallet/sparrow/net/TorUtils.java
Normal file
37
src/main/java/com/sparrowwallet/sparrow/net/TorUtils.java
Normal file
|
@ -0,0 +1,37 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import io.matthewnelson.kmp.tor.controller.common.control.usecase.TorControlSignal;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
|
||||
public class TorUtils {
|
||||
private static final Logger log = LoggerFactory.getLogger(TorUtils.class);
|
||||
|
||||
public static void changeIdentity(HostAndPort proxy) {
|
||||
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())) {
|
||||
writeNewNym(socket);
|
||||
} catch(Exception e) {
|
||||
log.warn("Error connecting to " + control + ", no Tor ControlPort configured?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeNewNym(Socket socket) throws IOException {
|
||||
log.debug("Sending NEWNYM to " + socket);
|
||||
socket.getOutputStream().write("AUTHENTICATE \"\"\r\n".getBytes());
|
||||
socket.getOutputStream().write("SIGNAL NEWNYM\r\n".getBytes());
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.sparrowwallet.drongo.address.Address;
|
||||
import com.sparrowwallet.drongo.address.InvalidAddressException;
|
||||
import com.sparrowwallet.drongo.crypto.ECKey;
|
||||
|
@ -13,12 +12,7 @@ import javafx.concurrent.Task;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.SignatureException;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -45,18 +39,15 @@ public class VersionCheckService extends ScheduledService<VersionUpdatedEvent> {
|
|||
}
|
||||
|
||||
private VersionCheck getVersionCheck() throws IOException {
|
||||
URL url = new URL(VERSION_CHECK_URL);
|
||||
Proxy proxy = AppServices.getProxy();
|
||||
|
||||
if(log.isInfoEnabled()) {
|
||||
log.info("Requesting application version check from " + url);
|
||||
log.info("Requesting application version check from " + VERSION_CHECK_URL);
|
||||
}
|
||||
|
||||
HttpsURLConnection conn = (HttpsURLConnection)(proxy == null ? url.openConnection() : url.openConnection(proxy));
|
||||
|
||||
try(InputStreamReader reader = new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8)) {
|
||||
Gson gson = new Gson();
|
||||
return gson.fromJson(reader, VersionCheck.class);
|
||||
HttpClientService httpClientService = AppServices.getHttpClientService();
|
||||
try {
|
||||
return httpClientService.requestJson(VERSION_CHECK_URL, VersionCheck.class, null);
|
||||
} catch(Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,9 @@ import com.sparrowwallet.drongo.psbt.PSBTParseException;
|
|||
import com.sparrowwallet.drongo.uri.BitcoinURI;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.drongo.wallet.WalletNode;
|
||||
import com.sparrowwallet.nightjar.http.JavaHttpException;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.net.HttpClientService;
|
||||
import com.sparrowwallet.sparrow.net.Protocol;
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
|
@ -22,11 +24,8 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.Proxy;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class Payjoin {
|
||||
|
@ -78,42 +77,21 @@ public class Payjoin {
|
|||
URI finalUri = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), uri.getQuery() == null ? appendQuery : uri.getQuery() + "&" + appendQuery, uri.getFragment());
|
||||
log.info("Sending PSBT to " + finalUri.toURL());
|
||||
|
||||
Proxy proxy = AppServices.getProxy();
|
||||
|
||||
if(proxy == null && Protocol.isOnionHost(finalUri.getHost())) {
|
||||
HttpClientService httpClientService = AppServices.getHttpClientService();
|
||||
if(httpClientService.getTorProxy() == null && Protocol.isOnionHost(finalUri.getHost())) {
|
||||
throw new PayjoinReceiverException("Configure a Tor proxy to get a payjoin transaction from " + finalUri.getHost() + ".");
|
||||
}
|
||||
|
||||
HttpURLConnection connection = proxy == null ? (HttpURLConnection)finalUri.toURL().openConnection() : (HttpURLConnection)finalUri.toURL().openConnection(proxy);
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "text/plain");
|
||||
connection.setDoOutput(true);
|
||||
|
||||
try(OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream())) {
|
||||
writer.write(base64Psbt);
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
StringBuilder response = new StringBuilder();
|
||||
try(BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
String responseLine;
|
||||
while((responseLine = br.readLine()) != null) {
|
||||
response.append(responseLine.trim());
|
||||
}
|
||||
}
|
||||
int statusCode = connection.getResponseCode();
|
||||
|
||||
if(statusCode != 200) {
|
||||
Gson gson = new Gson();
|
||||
PayjoinReceiverError payjoinReceiverError = gson.fromJson(response.toString(), PayjoinReceiverError.class);
|
||||
log.warn("Payjoin receiver returned an error of " + payjoinReceiverError.getErrorCode() + " (" + payjoinReceiverError.getMessage() + ")");
|
||||
throw new PayjoinReceiverException(payjoinReceiverError.getSafeMessage());
|
||||
}
|
||||
|
||||
PSBT proposalPsbt = PSBT.fromString(response.toString().trim());
|
||||
String response = httpClientService.postString(finalUri.toString(), null, "text/plain", base64Psbt);
|
||||
PSBT proposalPsbt = PSBT.fromString(response.trim());
|
||||
checkProposal(psbt, proposalPsbt, changeOutputIndex, maxAdditionalFeeContribution, allowOutputSubstitution);
|
||||
|
||||
return proposalPsbt;
|
||||
} catch(JavaHttpException e) {
|
||||
Gson gson = new Gson();
|
||||
PayjoinReceiverError payjoinReceiverError = gson.fromJson(e.getResponseBody(), PayjoinReceiverError.class);
|
||||
log.warn("Payjoin receiver returned an error of " + payjoinReceiverError.getErrorCode() + " (" + payjoinReceiverError.getMessage() + ")");
|
||||
throw new PayjoinReceiverException(payjoinReceiverError.getSafeMessage());
|
||||
} catch(URISyntaxException e) {
|
||||
log.error("Invalid payjoin receiver URI", e);
|
||||
throw new PayjoinReceiverException("Invalid payjoin receiver URI", e);
|
||||
|
@ -126,6 +104,9 @@ public class Payjoin {
|
|||
} catch(PSBTParseException e) {
|
||||
log.error("Error parsing received PSBT", e);
|
||||
throw new PayjoinReceiverException("Payjoin receiver returned invalid PSBT", e);
|
||||
} catch(Exception e) {
|
||||
log.error("Payjoin error", e);
|
||||
throw new PayjoinReceiverException("Payjoin error", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ public class PayNymController {
|
|||
}
|
||||
retrievePayNymProgress.setVisible(true);
|
||||
|
||||
AppServices.getPayNymService().getPayNym(getMasterWallet().getPaymentCode().toString()).subscribe(payNym -> {
|
||||
PayNymService.getPayNym(getMasterWallet().getPaymentCode().toString()).subscribe(payNym -> {
|
||||
retrievePayNymProgress.setVisible(false);
|
||||
walletPayNym = payNym;
|
||||
searchPayNyms.setDisable(false);
|
||||
|
@ -229,7 +229,7 @@ public class PayNymController {
|
|||
followingList.setItems(FXCollections.observableList(new ArrayList<>()));
|
||||
findPayNym.setVisible(true);
|
||||
|
||||
AppServices.getPayNymService().getPayNym(nymIdentifier, true).subscribe(searchedPayNym -> {
|
||||
PayNymService.getPayNym(nymIdentifier, true).subscribe(searchedPayNym -> {
|
||||
findPayNym.setVisible(false);
|
||||
List<PayNym> searchList = new ArrayList<>();
|
||||
searchList.add(searchedPayNym);
|
||||
|
@ -262,15 +262,14 @@ public class PayNymController {
|
|||
}
|
||||
|
||||
public void retrievePayNym(ActionEvent event) {
|
||||
PayNymService payNymService = AppServices.getPayNymService();
|
||||
Wallet masterWallet = getMasterWallet();
|
||||
setUsePayNym(masterWallet, true);
|
||||
payNymService.createPayNym(masterWallet).subscribe(createMap -> {
|
||||
PayNymService.createPayNym(masterWallet).subscribe(createMap -> {
|
||||
payNymName.setText((String)createMap.get("nymName"));
|
||||
payNymAvatar.setPaymentCode(masterWallet.getPaymentCode());
|
||||
payNymName.setVisible(true);
|
||||
|
||||
payNymService.claimPayNym(masterWallet, createMap, getMasterWallet().getScriptType() != ScriptType.P2PKH);
|
||||
PayNymService.claimPayNym(masterWallet, createMap, getMasterWallet().getScriptType() != ScriptType.P2PKH);
|
||||
refresh();
|
||||
}, error -> {
|
||||
log.error("Error retrieving PayNym", error);
|
||||
|
@ -282,12 +281,11 @@ public class PayNymController {
|
|||
}
|
||||
|
||||
public void followPayNym(PaymentCode contact) {
|
||||
PayNymService payNymService = AppServices.getPayNymService();
|
||||
Wallet masterWallet = getMasterWallet();
|
||||
retrievePayNymProgress.setVisible(true);
|
||||
payNymService.getAuthToken(masterWallet, new HashMap<>()).subscribe(authToken -> {
|
||||
String signature = payNymService.getSignature(masterWallet, authToken);
|
||||
payNymService.followPaymentCode(contact, authToken, signature).subscribe(followMap -> {
|
||||
PayNymService.getAuthToken(masterWallet, new HashMap<>()).subscribe(authToken -> {
|
||||
String signature = PayNymService.getSignature(masterWallet, authToken);
|
||||
PayNymService.followPaymentCode(contact, authToken, signature).subscribe(followMap -> {
|
||||
refresh();
|
||||
}, error -> {
|
||||
retrievePayNymProgress.setVisible(false);
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
package com.sparrowwallet.sparrow.paynym;
|
||||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.samourai.http.client.HttpUsage;
|
||||
import com.samourai.http.client.IHttpClient;
|
||||
import com.sparrowwallet.drongo.bip47.InvalidPaymentCodeException;
|
||||
import com.sparrowwallet.drongo.bip47.PaymentCode;
|
||||
import com.sparrowwallet.drongo.crypto.ChildNumber;
|
||||
|
@ -10,13 +7,11 @@ import com.sparrowwallet.drongo.crypto.ECKey;
|
|||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.nightjar.http.JavaHttpClientService;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.rxjavafx.schedulers.JavaFxScheduler;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java8.util.Optional;
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -30,17 +25,15 @@ import java.util.stream.Collectors;
|
|||
public class PayNymService {
|
||||
private static final Logger log = LoggerFactory.getLogger(PayNymService.class);
|
||||
|
||||
private final JavaHttpClientService httpClientService;
|
||||
|
||||
public PayNymService(HostAndPort torProxy) {
|
||||
this.httpClientService = new JavaHttpClientService(torProxy, 120000);
|
||||
private PayNymService() {
|
||||
//private constructor
|
||||
}
|
||||
|
||||
public Observable<Map<String, Object>> createPayNym(Wallet wallet) {
|
||||
public static Observable<Map<String, Object>> createPayNym(Wallet wallet) {
|
||||
return createPayNym(getPaymentCode(wallet));
|
||||
}
|
||||
|
||||
public Observable<Map<String, Object>> createPayNym(PaymentCode paymentCode) {
|
||||
public static Observable<Map<String, Object>> createPayNym(PaymentCode paymentCode) {
|
||||
if(paymentCode == null) {
|
||||
throw new IllegalStateException("Payment code is null");
|
||||
}
|
||||
|
@ -56,14 +49,13 @@ public class PayNymService {
|
|||
log.info("Creating PayNym using " + url);
|
||||
}
|
||||
|
||||
IHttpClient httpClient = httpClientService.getHttpClient(HttpUsage.COORDINATOR_REST);
|
||||
return httpClient.postJson(url, Map.class, headers, body)
|
||||
return AppServices.getHttpClientService().postJson(url, Map.class, headers, body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(JavaFxScheduler.platform())
|
||||
.map(Optional::get);
|
||||
}
|
||||
|
||||
public Observable<Map<String, Object>> updateToken(PaymentCode paymentCode) {
|
||||
public static Observable<Map<String, Object>> updateToken(PaymentCode paymentCode) {
|
||||
if(paymentCode == null) {
|
||||
throw new IllegalStateException("Payment code is null");
|
||||
}
|
||||
|
@ -79,14 +71,13 @@ public class PayNymService {
|
|||
log.info("Updating PayNym token using " + url);
|
||||
}
|
||||
|
||||
IHttpClient httpClient = httpClientService.getHttpClient(HttpUsage.COORDINATOR_REST);
|
||||
return httpClient.postJson(url, Map.class, headers, body)
|
||||
return AppServices.getHttpClientService().postJson(url, Map.class, headers, body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(JavaFxScheduler.platform())
|
||||
.map(Optional::get);
|
||||
}
|
||||
|
||||
public void claimPayNym(Wallet wallet, Map<String, Object> createMap, boolean segwit) {
|
||||
public static void claimPayNym(Wallet wallet, Map<String, Object> createMap, boolean segwit) {
|
||||
if(createMap.get("claimed") == Boolean.FALSE) {
|
||||
getAuthToken(wallet, createMap).subscribe(authToken -> {
|
||||
String signature = getSignature(wallet, authToken);
|
||||
|
@ -116,7 +107,7 @@ public class PayNymService {
|
|||
}
|
||||
}
|
||||
|
||||
private Observable<Map<String, Object>> claimPayNym(String authToken, String signature) {
|
||||
private static Observable<Map<String, Object>> claimPayNym(String authToken, String signature) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("content-type", "application/json");
|
||||
headers.put("auth-token", authToken);
|
||||
|
@ -129,14 +120,13 @@ public class PayNymService {
|
|||
log.info("Claiming PayNym using " + url);
|
||||
}
|
||||
|
||||
IHttpClient httpClient = httpClientService.getHttpClient(HttpUsage.COORDINATOR_REST);
|
||||
return httpClient.postJson(url, Map.class, headers, body)
|
||||
return AppServices.getHttpClientService().postJson(url, Map.class, headers, body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(JavaFxScheduler.platform())
|
||||
.map(Optional::get);
|
||||
}
|
||||
|
||||
public Observable<Map<String, Object>> addPaymentCode(PaymentCode paymentCode, String authToken, String signature, boolean segwit) {
|
||||
public static Observable<Map<String, Object>> addPaymentCode(PaymentCode paymentCode, String authToken, String signature, boolean segwit) {
|
||||
String strPaymentCode;
|
||||
try {
|
||||
strPaymentCode = segwit ? paymentCode.makeSamouraiPaymentCode() : paymentCode.toString();
|
||||
|
@ -159,18 +149,17 @@ public class PayNymService {
|
|||
log.info("Adding payment code to PayNym using " + url);
|
||||
}
|
||||
|
||||
IHttpClient httpClient = httpClientService.getHttpClient(HttpUsage.COORDINATOR_REST);
|
||||
return httpClient.postJson(url, Map.class, headers, body)
|
||||
return AppServices.getHttpClientService().postJson(url, Map.class, headers, body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(JavaFxScheduler.platform())
|
||||
.map(Optional::get);
|
||||
}
|
||||
|
||||
public Observable<Map<String, Object>> followPaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode paymentCode, String authToken, String signature) {
|
||||
public static Observable<Map<String, Object>> followPaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode paymentCode, String authToken, String signature) {
|
||||
return followPaymentCode(PaymentCode.fromString(paymentCode.toString()), authToken, signature);
|
||||
}
|
||||
|
||||
public Observable<Map<String, Object>> followPaymentCode(PaymentCode paymentCode, String authToken, String signature) {
|
||||
public static Observable<Map<String, Object>> followPaymentCode(PaymentCode paymentCode, String authToken, String signature) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("content-type", "application/json");
|
||||
headers.put("auth-token", authToken);
|
||||
|
@ -184,14 +173,13 @@ public class PayNymService {
|
|||
log.info("Following payment code using " + url);
|
||||
}
|
||||
|
||||
IHttpClient httpClient = httpClientService.getHttpClient(HttpUsage.COORDINATOR_REST);
|
||||
return httpClient.postJson(url, Map.class, headers, body)
|
||||
return AppServices.getHttpClientService().postJson(url, Map.class, headers, body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(JavaFxScheduler.platform())
|
||||
.map(Optional::get);
|
||||
}
|
||||
|
||||
public Observable<Map<String, Object>> fetchPayNym(String nymIdentifier, boolean compact) {
|
||||
public static Observable<Map<String, Object>> fetchPayNym(String nymIdentifier, boolean compact) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("content-type", "application/json");
|
||||
|
||||
|
@ -203,18 +191,17 @@ public class PayNymService {
|
|||
log.info("Fetching PayNym using " + url);
|
||||
}
|
||||
|
||||
IHttpClient httpClient = httpClientService.getHttpClient(HttpUsage.COORDINATOR_REST);
|
||||
return httpClient.postJson(url, Map.class, headers, body)
|
||||
return AppServices.getHttpClientService().postJson(url, Map.class, headers, body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(JavaFxScheduler.platform())
|
||||
.map(Optional::get);
|
||||
}
|
||||
|
||||
public Observable<PayNym> getPayNym(String nymIdentifier) {
|
||||
public static Observable<PayNym> getPayNym(String nymIdentifier) {
|
||||
return getPayNym(nymIdentifier, false);
|
||||
}
|
||||
|
||||
public Observable<PayNym> getPayNym(String nymIdentifier, boolean compact) {
|
||||
public static Observable<PayNym> getPayNym(String nymIdentifier, boolean compact) {
|
||||
return fetchPayNym(nymIdentifier, compact).map(nymMap -> {
|
||||
List<Map<String, Object>> codes = (List<Map<String, Object>>)nymMap.get("codes");
|
||||
PaymentCode code = new PaymentCode((String)codes.stream().filter(codeMap -> codeMap.get("segwit") == Boolean.FALSE).map(codeMap -> codeMap.get("code")).findFirst().orElse(codes.get(0).get("code")));
|
||||
|
@ -237,7 +224,7 @@ public class PayNymService {
|
|||
});
|
||||
}
|
||||
|
||||
public Observable<String> getAuthToken(Wallet wallet, Map<String, Object> map) {
|
||||
public static Observable<String> getAuthToken(Wallet wallet, Map<String, Object> map) {
|
||||
if(map.containsKey("token")) {
|
||||
return Observable.just((String)map.get("token"));
|
||||
}
|
||||
|
@ -245,11 +232,11 @@ public class PayNymService {
|
|||
return updateToken(wallet).map(tokenMap -> (String)tokenMap.get("token"));
|
||||
}
|
||||
|
||||
public Observable<Map<String, Object>> updateToken(Wallet wallet) {
|
||||
public static Observable<Map<String, Object>> updateToken(Wallet wallet) {
|
||||
return updateToken(getPaymentCode(wallet));
|
||||
}
|
||||
|
||||
public String getSignature(Wallet wallet, String authToken) {
|
||||
public static String getSignature(Wallet wallet, String authToken) {
|
||||
Wallet masterWallet = wallet.isMasterWallet() ? wallet : wallet.getMasterWallet();
|
||||
Keystore keystore = masterWallet.getKeystores().get(0);
|
||||
List<ChildNumber> derivation = keystore.getKeyDerivation().getDerivation();
|
||||
|
@ -258,48 +245,16 @@ public class PayNymService {
|
|||
return notificationPrivKey.signMessage(authToken, ScriptType.P2PKH);
|
||||
}
|
||||
|
||||
private PaymentCode getPaymentCode(Wallet wallet) {
|
||||
private static PaymentCode getPaymentCode(Wallet wallet) {
|
||||
Wallet masterWallet = wallet.isMasterWallet() ? wallet : wallet.getMasterWallet();
|
||||
return masterWallet.getPaymentCode();
|
||||
}
|
||||
|
||||
public HostAndPort getTorProxy() {
|
||||
return httpClientService.getTorProxy();
|
||||
}
|
||||
|
||||
public void setTorProxy(HostAndPort torProxy) {
|
||||
//Ensure all http clients are shutdown first
|
||||
httpClientService.shutdown();
|
||||
httpClientService.setTorProxy(torProxy);
|
||||
}
|
||||
|
||||
private String getHostUrl() {
|
||||
return getHostUrl(getTorProxy() != null);
|
||||
private static String getHostUrl() {
|
||||
return getHostUrl(AppServices.getHttpClientService().getTorProxy() != null);
|
||||
}
|
||||
|
||||
public static String getHostUrl(boolean tor) {
|
||||
return tor ? "http://paynym7bwekdtb2hzgkpl6y2waqcrs2dii7lwincvxme7mdpcpxzfsad.onion" : "https://paynym.is";
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
httpClientService.shutdown();
|
||||
}
|
||||
|
||||
public static class ShutdownService extends Service<Boolean> {
|
||||
private final PayNymService payNymService;
|
||||
|
||||
public ShutdownService(PayNymService payNymService) {
|
||||
this.payNymService = payNymService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Task<Boolean> createTask() {
|
||||
return new Task<>() {
|
||||
protected Boolean call() throws Exception {
|
||||
payNymService.shutdown();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -268,7 +268,7 @@ public class CounterpartyController extends SorobanController {
|
|||
mixingPartner.setText(code.substring(0, 12) + "..." + code.substring(code.length() - 5));
|
||||
if(isUsePayNym(wallet)) {
|
||||
mixPartnerAvatar.setPaymentCode(paymentCodeInitiator);
|
||||
AppServices.getPayNymService().getPayNym(paymentCodeInitiator.toString()).subscribe(payNym -> {
|
||||
PayNymService.getPayNym(paymentCodeInitiator.toString()).subscribe(payNym -> {
|
||||
mixingPartner.setText(payNym.nymName());
|
||||
}, error -> {
|
||||
//ignore, may not be a PayNym
|
||||
|
@ -346,10 +346,9 @@ public class CounterpartyController extends SorobanController {
|
|||
|
||||
private void followPaymentCode(PaymentCode paymentCodeInitiator) {
|
||||
if(isUsePayNym(wallet)) {
|
||||
PayNymService payNymService = AppServices.getPayNymService();
|
||||
payNymService.getAuthToken(wallet, new HashMap<>()).subscribe(authToken -> {
|
||||
String signature = payNymService.getSignature(wallet, authToken);
|
||||
payNymService.followPaymentCode(paymentCodeInitiator, authToken, signature).subscribe(followMap -> {
|
||||
PayNymService.getAuthToken(wallet, new HashMap<>()).subscribe(authToken -> {
|
||||
String signature = PayNymService.getSignature(wallet, authToken);
|
||||
PayNymService.followPaymentCode(paymentCodeInitiator, authToken, signature).subscribe(followMap -> {
|
||||
log.debug("Followed payment code " + followMap.get("following"));
|
||||
}, error -> {
|
||||
log.warn("Could not follow payment code", error);
|
||||
|
@ -389,13 +388,12 @@ public class CounterpartyController extends SorobanController {
|
|||
public void retrievePayNym(ActionEvent event) {
|
||||
setUsePayNym(wallet, true);
|
||||
|
||||
PayNymService payNymService = AppServices.getPayNymService();
|
||||
payNymService.createPayNym(wallet).subscribe(createMap -> {
|
||||
PayNymService.createPayNym(wallet).subscribe(createMap -> {
|
||||
payNym.setText((String)createMap.get("nymName"));
|
||||
payNymAvatar.setPaymentCode(wallet.isMasterWallet() ? wallet.getPaymentCode() : wallet.getMasterWallet().getPaymentCode());
|
||||
payNym.setVisible(true);
|
||||
|
||||
payNymService.claimPayNym(wallet, createMap, true);
|
||||
PayNymService.claimPayNym(wallet, createMap, true);
|
||||
}, error -> {
|
||||
log.error("Error retrieving PayNym", error);
|
||||
Optional<ButtonType> optResponse = showErrorDialog("Error retrieving PayNym", "Could not retrieve PayNym. Try again?", ButtonType.CANCEL, ButtonType.OK);
|
||||
|
|
|
@ -31,6 +31,7 @@ import com.sparrowwallet.sparrow.net.ElectrumServer;
|
|||
import com.sparrowwallet.sparrow.paynym.PayNym;
|
||||
import com.sparrowwallet.sparrow.paynym.PayNymAddress;
|
||||
import com.sparrowwallet.sparrow.paynym.PayNymDialog;
|
||||
import com.sparrowwallet.sparrow.paynym.PayNymService;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.rxjavafx.schedulers.JavaFxScheduler;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
@ -325,7 +326,7 @@ public class InitiatorController extends SorobanController {
|
|||
|
||||
private void searchPayNyms(String identifier) {
|
||||
payNymLoading.setVisible(true);
|
||||
AppServices.getPayNymService().getPayNym(identifier).subscribe(payNym -> {
|
||||
PayNymService.getPayNym(identifier).subscribe(payNym -> {
|
||||
payNymLoading.setVisible(false);
|
||||
counterpartyPayNymName.set(payNym.nymName());
|
||||
counterpartyPaymentCode.set(new PaymentCode(payNym.paymentCode().toString()));
|
||||
|
@ -344,7 +345,7 @@ public class InitiatorController extends SorobanController {
|
|||
|
||||
private void setPayNymFollowers() {
|
||||
Wallet masterWallet = wallet.isMasterWallet() ? wallet : wallet.getMasterWallet();
|
||||
AppServices.getPayNymService().getPayNym(masterWallet.getPaymentCode().toString()).map(PayNym::following).subscribe(followerPayNyms -> {
|
||||
PayNymService.getPayNym(masterWallet.getPaymentCode().toString()).map(PayNym::following).subscribe(followerPayNyms -> {
|
||||
findPayNym.setVisible(true);
|
||||
payNymFollowers.setItems(FXCollections.observableList(followerPayNyms));
|
||||
}, error -> {
|
||||
|
@ -624,7 +625,7 @@ public class InitiatorController extends SorobanController {
|
|||
if(counterpartyPaymentCode.get() != null) {
|
||||
return Observable.just(counterpartyPaymentCode.get());
|
||||
} else {
|
||||
return AppServices.getPayNymService().getPayNym(counterparty.getText()).map(payNym -> new PaymentCode(payNym.paymentCode().toString()));
|
||||
return PayNymService.getPayNym(counterparty.getText()).map(payNym -> new PaymentCode(payNym.paymentCode().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import com.sparrowwallet.sparrow.io.Config;
|
|||
import com.sparrowwallet.sparrow.io.Storage;
|
||||
import com.sparrowwallet.sparrow.net.*;
|
||||
import com.sparrowwallet.sparrow.paynym.PayNym;
|
||||
import com.sparrowwallet.sparrow.paynym.PayNymService;
|
||||
import com.sparrowwallet.sparrow.soroban.InitiatorDialog;
|
||||
import com.sparrowwallet.sparrow.paynym.PayNymAddress;
|
||||
import com.sparrowwallet.sparrow.soroban.SorobanServices;
|
||||
|
@ -1282,7 +1283,7 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
clear(null);
|
||||
if(Config.get().isUsePayNym()) {
|
||||
proxyWorker.setMessage("Finding PayNym...");
|
||||
AppServices.getPayNymService().getPayNym(externalPaymentCode.toString()).subscribe(payNym -> {
|
||||
PayNymService.getPayNym(externalPaymentCode.toString()).subscribe(payNym -> {
|
||||
proxyWorker.end();
|
||||
addChildWallets(walletTransaction.getWallet(), externalPaymentCode, transaction, payNym);
|
||||
}, error -> {
|
||||
|
|
|
@ -2,19 +2,10 @@ package com.sparrowwallet.sparrow.whirlpool.tor;
|
|||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.samourai.tor.client.TorClientService;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.net.Tor;
|
||||
import com.sparrowwallet.sparrow.net.TorUtils;
|
||||
import com.sparrowwallet.sparrow.whirlpool.Whirlpool;
|
||||
import io.matthewnelson.kmp.tor.controller.common.control.usecase.TorControlSignal;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
|
||||
public class SparrowTorClientService extends TorClientService {
|
||||
private static final Logger log = LoggerFactory.getLogger(SparrowTorClientService.class);
|
||||
|
||||
private final Whirlpool whirlpool;
|
||||
|
||||
public SparrowTorClientService(Whirlpool whirlpool) {
|
||||
|
@ -25,26 +16,7 @@ public class SparrowTorClientService extends TorClientService {
|
|||
public void changeIdentity() {
|
||||
HostAndPort proxy = whirlpool.getTorProxy();
|
||||
if(proxy != null) {
|
||||
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())) {
|
||||
writeNewNym(socket);
|
||||
} catch(Exception e) {
|
||||
log.warn("Error connecting to " + control + ", no Tor ControlPort configured?");
|
||||
}
|
||||
}
|
||||
TorUtils.changeIdentity(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeNewNym(Socket socket) throws IOException {
|
||||
log.debug("Sending NEWNYM to " + socket);
|
||||
socket.getOutputStream().write("AUTHENTICATE \"\"\r\n".getBytes());
|
||||
socket.getOutputStream().write("SIGNAL NEWNYM\r\n".getBytes());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue