mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-26 05:26:45 +00:00
support cookie authentication for tor control port
This commit is contained in:
parent
2e8112cba0
commit
08ec158d19
1 changed files with 52 additions and 3 deletions
|
@ -1,16 +1,22 @@
|
||||||
package com.sparrowwallet.sparrow.net;
|
package com.sparrowwallet.sparrow.net;
|
||||||
|
|
||||||
import com.google.common.net.HostAndPort;
|
import com.google.common.net.HostAndPort;
|
||||||
|
import com.sparrowwallet.drongo.Utils;
|
||||||
import com.sparrowwallet.sparrow.AppServices;
|
import com.sparrowwallet.sparrow.AppServices;
|
||||||
import io.matthewnelson.kmp.tor.controller.common.control.usecase.TorControlSignal;
|
import io.matthewnelson.kmp.tor.controller.common.control.usecase.TorControlSignal;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.*;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class TorUtils {
|
public class TorUtils {
|
||||||
private static final Logger log = LoggerFactory.getLogger(TorUtils.class);
|
private static final Logger log = LoggerFactory.getLogger(TorUtils.class);
|
||||||
|
private static final Pattern TOR_OK = Pattern.compile("^2\\d{2}[ -]OK$");
|
||||||
|
private static final Pattern TOR_AUTH_METHODS = Pattern.compile("^2\\d{2}[ -]AUTH METHODS=(\\S+)\\s?(COOKIEFILE=\"?(.+?)\"?)?$");
|
||||||
|
|
||||||
public static void changeIdentity(HostAndPort proxy) {
|
public static void changeIdentity(HostAndPort proxy) {
|
||||||
if(AppServices.isTorRunning()) {
|
if(AppServices.isTorRunning()) {
|
||||||
|
@ -22,16 +28,59 @@ public class TorUtils {
|
||||||
} else {
|
} else {
|
||||||
HostAndPort control = HostAndPort.fromParts(proxy.getHost(), proxy.getPort() + 1);
|
HostAndPort control = HostAndPort.fromParts(proxy.getHost(), proxy.getPort() + 1);
|
||||||
try(Socket socket = new Socket(control.getHost(), control.getPort())) {
|
try(Socket socket = new Socket(control.getHost(), control.getPort())) {
|
||||||
writeNewNym(socket);
|
if(authenticate(socket)) {
|
||||||
|
writeNewNym(socket);
|
||||||
|
}
|
||||||
|
} catch(TorAuthenticationException e) {
|
||||||
|
log.warn("Error authenticating to Tor at " + control + ", server returned " + e.getMessage());
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
log.warn("Error connecting to " + control + ", no Tor ControlPort configured?");
|
log.warn("Error connecting to " + control + ", no Tor ControlPort configured?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean authenticate(Socket socket) throws IOException, TorAuthenticationException {
|
||||||
|
socket.getOutputStream().write("PROTOCOLINFO\r\n".getBytes());
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
String line;
|
||||||
|
File cookieFile = null;
|
||||||
|
while((line = reader.readLine()) != null) {
|
||||||
|
Matcher authMatcher = TOR_AUTH_METHODS.matcher(line);
|
||||||
|
if(authMatcher.matches()) {
|
||||||
|
String methods = authMatcher.group(1);
|
||||||
|
if(methods.contains("COOKIE") && !authMatcher.group(3).isEmpty()) {
|
||||||
|
cookieFile = new File(authMatcher.group(3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(TOR_OK.matcher(line).matches()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cookieFile != null && cookieFile.exists()) {
|
||||||
|
byte[] cookieBytes = Files.readAllBytes(cookieFile.toPath());
|
||||||
|
String authentication = "AUTHENTICATE " + Utils.bytesToHex(cookieBytes) + "\r\n";
|
||||||
|
socket.getOutputStream().write(authentication.getBytes());
|
||||||
|
} else {
|
||||||
|
socket.getOutputStream().write("AUTHENTICATE \"\"\r\n".getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
line = reader.readLine();
|
||||||
|
if(TOR_OK.matcher(line).matches()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new TorAuthenticationException(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void writeNewNym(Socket socket) throws IOException {
|
private static void writeNewNym(Socket socket) throws IOException {
|
||||||
log.debug("Sending NEWNYM to " + socket);
|
log.debug("Sending NEWNYM to " + socket);
|
||||||
socket.getOutputStream().write("AUTHENTICATE \"\"\r\n".getBytes());
|
|
||||||
socket.getOutputStream().write("SIGNAL NEWNYM\r\n".getBytes());
|
socket.getOutputStream().write("SIGNAL NEWNYM\r\n".getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TorAuthenticationException extends Exception {
|
||||||
|
public TorAuthenticationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue