mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Compare commits
8 Commits
control-po
...
misc-code-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
189ec874cc | ||
|
|
8c25732d13 | ||
|
|
c59ef29cdb | ||
|
|
56ac755e96 | ||
|
|
98633f5e7c | ||
|
|
86130e845a | ||
|
|
8ecec8bcf5 | ||
|
|
ad9191b076 |
@@ -11,8 +11,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 26
|
targetSdkVersion 26
|
||||||
versionCode 10106
|
versionCode 10105
|
||||||
versionName "1.1.6"
|
versionName "1.1.5"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
@@ -30,8 +30,8 @@ configurations {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bramble-core', configuration: 'default')
|
implementation project(path: ':bramble-core', configuration: 'default')
|
||||||
tor 'org.briarproject:tor-android:0.3.5.8@zip'
|
tor 'org.briarproject:tor-android:0.3.4.8@zip'
|
||||||
tor 'org.briarproject:obfs4proxy-android:0.0.9@zip'
|
tor 'org.briarproject:obfs4proxy-android:0.0.7@zip'
|
||||||
|
|
||||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
|
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
|
||||||
|
|
||||||
|
|||||||
@@ -9,23 +9,22 @@ import org.briarproject.bramble.api.account.AccountManager;
|
|||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.util.IoUtils.deleteFileOrDir;
|
||||||
|
|
||||||
class AndroidAccountManager extends AccountManagerImpl
|
class AndroidAccountManager extends AccountManagerImpl
|
||||||
implements AccountManager {
|
implements AccountManager {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(AndroidAccountManager.class.getName());
|
getLogger(AndroidAccountManager.class.getName());
|
||||||
|
|
||||||
private static final String PREF_DB_KEY = "key";
|
private static final String PREF_DB_KEY = "key";
|
||||||
|
|
||||||
@@ -41,7 +40,7 @@ class AndroidAccountManager extends AccountManagerImpl
|
|||||||
appContext = app.getApplicationContext();
|
appContext = app.getApplicationContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: stateChangeLock
|
@GuardedBy("stateChangeLock")
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
protected String loadEncryptedDatabaseKey() {
|
protected String loadEncryptedDatabaseKey() {
|
||||||
@@ -51,7 +50,7 @@ class AndroidAccountManager extends AccountManagerImpl
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: stateChangeLock
|
@GuardedBy("stateChangeLock")
|
||||||
@Nullable
|
@Nullable
|
||||||
private String getDatabaseKeyFromPreferences() {
|
private String getDatabaseKeyFromPreferences() {
|
||||||
String key = prefs.getString(PREF_DB_KEY, null);
|
String key = prefs.getString(PREF_DB_KEY, null);
|
||||||
@@ -60,7 +59,7 @@ class AndroidAccountManager extends AccountManagerImpl
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: stateChangeLock
|
@GuardedBy("stateChangeLock")
|
||||||
private void migrateDatabaseKeyToFile(String key) {
|
private void migrateDatabaseKeyToFile(String key) {
|
||||||
if (storeEncryptedDatabaseKey(key)) {
|
if (storeEncryptedDatabaseKey(key)) {
|
||||||
if (prefs.edit().remove(PREF_DB_KEY).commit())
|
if (prefs.edit().remove(PREF_DB_KEY).commit())
|
||||||
@@ -85,7 +84,7 @@ class AndroidAccountManager extends AccountManagerImpl
|
|||||||
return PreferenceManager.getDefaultSharedPreferences(appContext);
|
return PreferenceManager.getDefaultSharedPreferences(appContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: stateChangeLock
|
@GuardedBy("stateChangeLock")
|
||||||
private void deleteAppData(SharedPreferences... clear) {
|
private void deleteAppData(SharedPreferences... clear) {
|
||||||
// Clear and commit shared preferences
|
// Clear and commit shared preferences
|
||||||
for (SharedPreferences prefs : clear) {
|
for (SharedPreferences prefs : clear) {
|
||||||
@@ -93,42 +92,20 @@ class AndroidAccountManager extends AccountManagerImpl
|
|||||||
LOG.warning("Could not clear shared preferences");
|
LOG.warning("Could not clear shared preferences");
|
||||||
}
|
}
|
||||||
// Delete files, except lib and shared_prefs directories
|
// Delete files, except lib and shared_prefs directories
|
||||||
Set<File> files = new HashSet<>();
|
|
||||||
File dataDir = new File(appContext.getApplicationInfo().dataDir);
|
File dataDir = new File(appContext.getApplicationInfo().dataDir);
|
||||||
@Nullable
|
File[] children = dataDir.listFiles();
|
||||||
File[] fileArray = dataDir.listFiles();
|
if (children == null) {
|
||||||
if (fileArray == null) {
|
|
||||||
LOG.warning("Could not list files in app data dir");
|
LOG.warning("Could not list files in app data dir");
|
||||||
} else {
|
} else {
|
||||||
for (File file : fileArray) {
|
for (File child : children) {
|
||||||
String name = file.getName();
|
String name = child.getName();
|
||||||
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
||||||
files.add(file);
|
deleteFileOrDir(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
files.add(appContext.getFilesDir());
|
|
||||||
files.add(appContext.getCacheDir());
|
|
||||||
addIfNotNull(files, appContext.getExternalCacheDir());
|
|
||||||
if (SDK_INT >= 19) {
|
|
||||||
for (File file : appContext.getExternalCacheDirs()) {
|
|
||||||
addIfNotNull(files, file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (SDK_INT >= 21) {
|
|
||||||
for (File file : appContext.getExternalMediaDirs()) {
|
|
||||||
addIfNotNull(files, file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (File file : files) {
|
|
||||||
IoUtils.deleteFileOrDir(file);
|
|
||||||
}
|
|
||||||
// Recreate the cache dir as some OpenGL drivers expect it to exist
|
// Recreate the cache dir as some OpenGL drivers expect it to exist
|
||||||
if (!new File(dataDir, "cache").mkdirs())
|
if (!new File(dataDir, "cache").mkdir())
|
||||||
LOG.warning("Could not recreate cache dir");
|
LOG.warning("Could not recreate cache dir");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addIfNotNull(Set<File> files, @Nullable File file) {
|
|
||||||
if (file != null) files.add(file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ import org.briarproject.bramble.api.lifecycle.Service;
|
|||||||
import org.briarproject.bramble.api.network.NetworkManager;
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
import org.briarproject.bramble.api.network.NetworkStatus;
|
import org.briarproject.bramble.api.network.NetworkStatus;
|
||||||
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
|
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
|
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
@@ -34,16 +33,17 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
|||||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
|
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@NotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
|
||||||
class AndroidNetworkManager implements NetworkManager, Service {
|
class AndroidNetworkManager implements NetworkManager, Service {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(AndroidNetworkManager.class.getName());
|
getLogger(AndroidNetworkManager.class.getName());
|
||||||
|
|
||||||
// See android.net.wifi.WifiManager
|
// See android.net.wifi.WifiManager
|
||||||
private static final String WIFI_AP_STATE_CHANGED_ACTION =
|
private static final String WIFI_AP_STATE_CHANGED_ACTION =
|
||||||
@@ -56,6 +56,7 @@ class AndroidNetworkManager implements NetworkManager, Service {
|
|||||||
new AtomicReference<>();
|
new AtomicReference<>();
|
||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private volatile BroadcastReceiver networkStateReceiver = null;
|
private volatile BroadcastReceiver networkStateReceiver = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -89,9 +90,8 @@ class AndroidNetworkManager implements NetworkManager, Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NetworkStatus getNetworkStatus() {
|
public NetworkStatus getNetworkStatus() {
|
||||||
ConnectivityManager cm = (ConnectivityManager)
|
ConnectivityManager cm = (ConnectivityManager) requireNonNull(
|
||||||
appContext.getSystemService(CONNECTIVITY_SERVICE);
|
appContext.getSystemService(CONNECTIVITY_SERVICE));
|
||||||
if (cm == null) throw new AssertionError();
|
|
||||||
NetworkInfo net = cm.getActiveNetworkInfo();
|
NetworkInfo net = cm.getActiveNetworkInfo();
|
||||||
boolean connected = net != null && net.isConnected();
|
boolean connected = net != null && net.isConnected();
|
||||||
boolean wifi = connected && net.getType() == TYPE_WIFI;
|
boolean wifi = connected && net.getType() == TYPE_WIFI;
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import java.io.IOException;
|
|||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
@@ -48,9 +47,11 @@ import static android.bluetooth.BluetoothAdapter.STATE_OFF;
|
|||||||
import static android.bluetooth.BluetoothAdapter.STATE_ON;
|
import static android.bluetooth.BluetoothAdapter.STATE_ON;
|
||||||
import static android.bluetooth.BluetoothDevice.ACTION_FOUND;
|
import static android.bluetooth.BluetoothDevice.ACTION_FOUND;
|
||||||
import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
|
import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
|
||||||
|
import static java.util.Collections.shuffle;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@@ -58,7 +59,7 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
|||||||
class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(AndroidBluetoothPlugin.class.getName());
|
getLogger(AndroidBluetoothPlugin.class.getName());
|
||||||
|
|
||||||
private static final int MAX_DISCOVERY_MS = 10_000;
|
private static final int MAX_DISCOVERY_MS = 10_000;
|
||||||
|
|
||||||
@@ -259,7 +260,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
appContext.unregisterReceiver(receiver);
|
appContext.unregisterReceiver(receiver);
|
||||||
}
|
}
|
||||||
// Shuffle the addresses so we don't always try the same one first
|
// Shuffle the addresses so we don't always try the same one first
|
||||||
Collections.shuffle(addresses);
|
shuffle(addresses);
|
||||||
return addresses;
|
return addresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,17 +32,19 @@ import static android.net.ConnectivityManager.TYPE_WIFI;
|
|||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
|
class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
getLogger(AndroidLanTcpPlugin.class.getName());
|
||||||
|
|
||||||
private static final byte[] WIFI_AP_ADDRESS_BYTES =
|
private static final byte[] WIFI_AP_ADDRESS_BYTES =
|
||||||
{(byte) 192, (byte) 168, 43, 1};
|
{(byte) 192, (byte) 168, 43, 1};
|
||||||
private static final InetAddress WIFI_AP_ADDRESS;
|
private static final InetAddress WIFI_AP_ADDRESS;
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(AndroidLanTcpPlugin.class.getName());
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
WIFI_AP_ADDRESS = InetAddress.getByAddress(WIFI_AP_ADDRESS_BYTES);
|
WIFI_AP_ADDRESS = InetAddress.getByAddress(WIFI_AP_ADDRESS_BYTES);
|
||||||
@@ -66,10 +68,8 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
|
|||||||
// Don't execute more than one connection status check at a time
|
// Don't execute more than one connection status check at a time
|
||||||
connectionStatusExecutor =
|
connectionStatusExecutor =
|
||||||
new PoliteExecutor("AndroidLanTcpPlugin", ioExecutor, 1);
|
new PoliteExecutor("AndroidLanTcpPlugin", ioExecutor, 1);
|
||||||
ConnectivityManager connectivityManager = (ConnectivityManager)
|
connectivityManager = (ConnectivityManager) requireNonNull(
|
||||||
appContext.getSystemService(CONNECTIVITY_SERVICE);
|
appContext.getSystemService(CONNECTIVITY_SERVICE));
|
||||||
if (connectivityManager == null) throw new AssertionError();
|
|
||||||
this.connectivityManager = connectivityManager;
|
|
||||||
wifiManager = (WifiManager) appContext.getApplicationContext()
|
wifiManager = (WifiManager) appContext.getApplicationContext()
|
||||||
.getSystemService(WIFI_SERVICE);
|
.getSystemService(WIFI_SERVICE);
|
||||||
socketFactory = SocketFactory.getDefault();
|
socketFactory = SocketFactory.getDefault();
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ import android.os.PowerManager;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.battery.BatteryManager;
|
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||||
import org.briarproject.bramble.api.network.NetworkManager;
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.Backoff;
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
@@ -26,10 +25,10 @@ import javax.net.SocketFactory;
|
|||||||
import static android.content.Context.MODE_PRIVATE;
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
import static android.content.Context.POWER_SERVICE;
|
import static android.content.Context.POWER_SERVICE;
|
||||||
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
|
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@NotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
|
||||||
class AndroidTorPlugin extends TorPlugin {
|
class AndroidTorPlugin extends TorPlugin {
|
||||||
|
|
||||||
// This tag may prevent Huawei's power manager from killing us
|
// This tag may prevent Huawei's power manager from killing us
|
||||||
@@ -52,8 +51,7 @@ class AndroidTorPlugin extends TorPlugin {
|
|||||||
appContext.getDir("tor", MODE_PRIVATE));
|
appContext.getDir("tor", MODE_PRIVATE));
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
PowerManager pm = (PowerManager)
|
PowerManager pm = (PowerManager)
|
||||||
appContext.getSystemService(POWER_SERVICE);
|
requireNonNull(appContext.getSystemService(POWER_SERVICE));
|
||||||
if (pm == null) throw new AssertionError();
|
|
||||||
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
|
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
|
||||||
WAKE_LOCK_TAG, 1, MINUTES);
|
WAKE_LOCK_TAG, 1, MINUTES);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.bramble.plugin.tor;
|
package org.briarproject.bramble.plugin.tor;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.battery.BatteryManager;
|
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
@@ -26,12 +25,15 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(AndroidTorPluginFactory.class.getName());
|
getLogger(AndroidTorPluginFactory.class.getName());
|
||||||
|
|
||||||
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
||||||
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
|
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
|
||||||
@@ -102,7 +104,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// Use position-independent executable for SDK >= 16
|
// Use position-independent executable for SDK >= 16
|
||||||
if (Build.VERSION.SDK_INT >= 16) architecture += "_pie";
|
if (SDK_INT >= 16) architecture += "_pie";
|
||||||
|
|
||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
|
|||||||
@@ -15,12 +15,13 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.content.Context.TELEPHONY_SERVICE;
|
import static android.content.Context.TELEPHONY_SERVICE;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class AndroidLocationUtils implements LocationUtils {
|
class AndroidLocationUtils implements LocationUtils {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(AndroidLocationUtils.class.getName());
|
getLogger(AndroidLocationUtils.class.getName());
|
||||||
|
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
|
|
||||||
@@ -59,14 +60,14 @@ class AndroidLocationUtils implements LocationUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getCountryFromPhoneNetwork() {
|
private String getCountryFromPhoneNetwork() {
|
||||||
Object o = appContext.getSystemService(TELEPHONY_SERVICE);
|
TelephonyManager tm = (TelephonyManager)
|
||||||
TelephonyManager tm = (TelephonyManager) o;
|
appContext.getSystemService(TELEPHONY_SERVICE);
|
||||||
return tm.getNetworkCountryIso();
|
return tm == null ? "" : tm.getNetworkCountryIso();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCountryFromSimCard() {
|
private String getCountryFromSimCard() {
|
||||||
Object o = appContext.getSystemService(TELEPHONY_SERVICE);
|
TelephonyManager tm = (TelephonyManager)
|
||||||
TelephonyManager tm = (TelephonyManager) o;
|
appContext.getSystemService(TELEPHONY_SERVICE);
|
||||||
return tm.getSimCountryIso();
|
return tm == null ? "" : tm.getSimCountryIso();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import android.content.ContentResolver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.wifi.WifiConfiguration;
|
import android.net.wifi.WifiConfiguration;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -23,6 +22,9 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.content.Context.WIFI_SERVICE;
|
import static android.content.Context.WIFI_SERVICE;
|
||||||
|
import static android.os.Build.FINGERPRINT;
|
||||||
|
import static android.os.Build.SERIAL;
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.provider.Settings.Secure.ANDROID_ID;
|
import static android.provider.Settings.Secure.ANDROID_ID;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -45,8 +47,8 @@ class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
|
|||||||
out.writeInt(android.os.Process.myPid());
|
out.writeInt(android.os.Process.myPid());
|
||||||
out.writeInt(android.os.Process.myTid());
|
out.writeInt(android.os.Process.myTid());
|
||||||
out.writeInt(android.os.Process.myUid());
|
out.writeInt(android.os.Process.myUid());
|
||||||
if (Build.FINGERPRINT != null) out.writeUTF(Build.FINGERPRINT);
|
if (FINGERPRINT != null) out.writeUTF(FINGERPRINT);
|
||||||
if (Build.SERIAL != null) out.writeUTF(Build.SERIAL);
|
if (SERIAL != null) out.writeUTF(SERIAL);
|
||||||
ContentResolver contentResolver = appContext.getContentResolver();
|
ContentResolver contentResolver = appContext.getContentResolver();
|
||||||
String id = Settings.Secure.getString(contentResolver, ANDROID_ID);
|
String id = Settings.Secure.getString(contentResolver, ANDROID_ID);
|
||||||
if (id != null) out.writeUTF(id);
|
if (id != null) out.writeUTF(id);
|
||||||
@@ -74,15 +76,13 @@ class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
|
|||||||
// Silence strict mode
|
// Silence strict mode
|
||||||
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskWrites();
|
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskWrites();
|
||||||
super.writeSeed();
|
super.writeSeed();
|
||||||
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18)
|
if (SDK_INT >= 16 && SDK_INT <= 18) applyOpenSslFix();
|
||||||
applyOpenSslFix();
|
|
||||||
StrictMode.setThreadPolicy(tp);
|
StrictMode.setThreadPolicy(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
||||||
private void applyOpenSslFix() {
|
private void applyOpenSslFix() {
|
||||||
byte[] seed = new UnixSecureRandomSpi().engineGenerateSeed(
|
byte[] seed = new UnixSecureRandomSpi().engineGenerateSeed(SEED_LENGTH);
|
||||||
SEED_LENGTH);
|
|
||||||
try {
|
try {
|
||||||
// Seed the OpenSSL PRNG
|
// Seed the OpenSSL PRNG
|
||||||
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||||
|
|||||||
@@ -3,17 +3,20 @@ package org.briarproject.bramble.util;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static android.content.Context.MODE_PRIVATE;
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
|
import static android.os.Build.CPU_ABI;
|
||||||
|
import static android.os.Build.CPU_ABI2;
|
||||||
|
import static android.os.Build.SUPPORTED_ABIS;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||||
|
|
||||||
public class AndroidUtils {
|
public class AndroidUtils {
|
||||||
|
|
||||||
@@ -22,14 +25,13 @@ public class AndroidUtils {
|
|||||||
|
|
||||||
private static final String STORED_REPORTS = "dev-reports";
|
private static final String STORED_REPORTS = "dev-reports";
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public static Collection<String> getSupportedArchitectures() {
|
public static Collection<String> getSupportedArchitectures() {
|
||||||
List<String> abis = new ArrayList<>();
|
List<String> abis = new ArrayList<>();
|
||||||
if (SDK_INT >= 21) {
|
if (SDK_INT >= 21) {
|
||||||
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
|
abis.addAll(asList(SUPPORTED_ABIS));
|
||||||
} else {
|
} else {
|
||||||
abis.add(Build.CPU_ABI);
|
abis.add(CPU_ABI);
|
||||||
if (Build.CPU_ABI2 != null) abis.add(Build.CPU_ABI2);
|
if (CPU_ABI2 != null) abis.add(CPU_ABI2);
|
||||||
}
|
}
|
||||||
return abis;
|
return abis;
|
||||||
}
|
}
|
||||||
@@ -49,7 +51,7 @@ public class AndroidUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isValidBluetoothAddress(String address) {
|
private static boolean isValidBluetoothAddress(String address) {
|
||||||
return !StringUtils.isNullOrEmpty(address)
|
return !isNullOrEmpty(address)
|
||||||
&& BluetoothAdapter.checkBluetoothAddress(address)
|
&& BluetoothAdapter.checkBluetoothAddress(address)
|
||||||
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
|
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,17 +10,19 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class RenewableWakeLock {
|
public class RenewableWakeLock {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(RenewableWakeLock.class.getName());
|
getLogger(RenewableWakeLock.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Automatically release the lock this many milliseconds after it's due
|
* Automatically release the lock this many milliseconds after it's due
|
||||||
@@ -36,10 +38,12 @@ public class RenewableWakeLock {
|
|||||||
private final Runnable renewTask;
|
private final Runnable renewTask;
|
||||||
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
|
@GuardedBy("lock")
|
||||||
@Nullable
|
@Nullable
|
||||||
private PowerManager.WakeLock wakeLock; // Locking: lock
|
private PowerManager.WakeLock wakeLock;
|
||||||
|
@GuardedBy("lock")
|
||||||
@Nullable
|
@Nullable
|
||||||
private ScheduledFuture future; // Locking: lock
|
private ScheduledFuture future;
|
||||||
|
|
||||||
public RenewableWakeLock(PowerManager powerManager,
|
public RenewableWakeLock(PowerManager powerManager,
|
||||||
ScheduledExecutorService scheduler, int levelAndFlags, String tag,
|
ScheduledExecutorService scheduler, int levelAndFlags, String tag,
|
||||||
|
|||||||
@@ -112,8 +112,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
|||||||
// Other directories should be deleted
|
// Other directories should be deleted
|
||||||
File potatoDir = new File(testDir, ".potato");
|
File potatoDir = new File(testDir, ".potato");
|
||||||
File potatoFile = new File(potatoDir, "file");
|
File potatoFile = new File(potatoDir, "file");
|
||||||
File filesDir = new File(testDir, "filesDir");
|
|
||||||
File externalCacheDir = new File(testDir, "externalCacheDir");
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(prefs).edit();
|
oneOf(prefs).edit();
|
||||||
@@ -130,12 +128,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(app).getApplicationInfo();
|
oneOf(app).getApplicationInfo();
|
||||||
will(returnValue(applicationInfo));
|
will(returnValue(applicationInfo));
|
||||||
oneOf(app).getFilesDir();
|
|
||||||
will(returnValue(filesDir));
|
|
||||||
oneOf(app).getCacheDir();
|
|
||||||
will(returnValue(cacheDir));
|
|
||||||
oneOf(app).getExternalCacheDir();
|
|
||||||
will(returnValue(externalCacheDir));
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertTrue(dbDir.mkdirs());
|
assertTrue(dbDir.mkdirs());
|
||||||
@@ -148,8 +140,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
|||||||
assertTrue(cacheFile.createNewFile());
|
assertTrue(cacheFile.createNewFile());
|
||||||
assertTrue(potatoDir.mkdirs());
|
assertTrue(potatoDir.mkdirs());
|
||||||
assertTrue(potatoFile.createNewFile());
|
assertTrue(potatoFile.createNewFile());
|
||||||
assertTrue(filesDir.mkdirs());
|
|
||||||
assertTrue(externalCacheDir.mkdirs());
|
|
||||||
|
|
||||||
accountManager.deleteAccount();
|
accountManager.deleteAccount();
|
||||||
|
|
||||||
@@ -163,8 +153,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
|||||||
assertFalse(cacheFile.exists());
|
assertFalse(cacheFile.exists());
|
||||||
assertFalse(potatoDir.exists());
|
assertFalse(potatoDir.exists());
|
||||||
assertFalse(potatoFile.exists());
|
assertFalse(potatoFile.exists());
|
||||||
assertFalse(filesDir.exists());
|
|
||||||
assertFalse(externalCacheDir.exists());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|||||||
@@ -1,44 +1,46 @@
|
|||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
verify = [
|
verify = [
|
||||||
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
||||||
'com.android.tools.analytics-library:protos:26.3.2:protos-26.3.2.jar:50238fb4298b297217b184b9cd93c14f83536fcee829eb0ca850bdb5b53251f0',
|
'com.android.tools.analytics-library:protos:26.2.1:protos-26.2.1.jar:2f371f5b1f551e85ab08be4d6a2873471b3d44afd1ebf6aa3298f3b796bf691f',
|
||||||
'com.android.tools.analytics-library:shared:26.3.2:shared-26.3.2.jar:ddd80dcf21905018b7c0583ba72b7282f446084d4952422609a09fbf8237ef71',
|
'com.android.tools.analytics-library:shared:26.2.1:shared-26.2.1.jar:4c1e4e705fa4d45f23aaea230557f6508155012d9c296337787c1d7b26a97f5a',
|
||||||
'com.android.tools.analytics-library:tracker:26.3.2:tracker-26.3.2.jar:28c575d2d1af003e96d7b375a668ee10b2673a2dd0f6438750aa8c3b42e7d0ad',
|
'com.android.tools.analytics-library:tracker:26.2.1:tracker-26.2.1.jar:4a624ecc976539f755ddb0bb8dfc2dd3d08326cfec59a098dbd70f701ca7fb75',
|
||||||
'com.android.tools.build:apksig:3.3.2:apksig-3.3.2.jar:84c4aaa20127c6c1fe6bdd334b3f5df71f54ad080be9029c8a10f43b6a908acd',
|
'com.android.tools.build:aapt2:3.2.1-4818971:aapt2-3.2.1-4818971-linux.jar:f431b6f96c91a2c155144b091a9c97d9805c589fe8efc9c930b6cd346cb60a1e',
|
||||||
'com.android.tools.build:apkzlib:3.3.2:apkzlib-3.3.2.jar:d34e523278e5dff565eba3ef3c089d515b2b5cc7b47dc77e2f3465e5e47176ac',
|
'com.android.tools.build:apksig:3.2.1:apksig-3.2.1.jar:2b46f2feffea66037aab29e4261b2433c190194a6ef97b958511eb157f2ccba5',
|
||||||
'com.android.tools.build:builder-model:3.3.2:builder-model-3.3.2.jar:055e3db0ecee9e06b9f024034999a29cd92cb1885207b37542126bd8bcc57f46',
|
'com.android.tools.build:apkzlib:3.2.1:apkzlib-3.2.1.jar:c39ad0313905932431fe81c8899c2cf39a4d92ad6c4edcaa4b25432f461452aa',
|
||||||
'com.android.tools.build:builder-test-api:3.3.2:builder-test-api-3.3.2.jar:0b2e4cd7615bbcad14a3c91fe45ae26693508d06e40ba06c5968b8bc24416618',
|
'com.android.tools.build:builder-model:3.2.1:builder-model-3.2.1.jar:a9f68e6abcec122f9cb5ad352d3f05a3eb03acbcdca95e4d25c16310c2c965ff',
|
||||||
'com.android.tools.build:builder:3.3.2:builder-3.3.2.jar:65649704da7aef0487235fd326f0f2e99ed5cf958e80f204496e6e08a42bd9f5',
|
'com.android.tools.build:builder-test-api:3.2.1:builder-test-api-3.2.1.jar:533ac6c2b5884bb54967a33791f2628dfdfac7981af39417a333b43d4379b6be',
|
||||||
'com.android.tools.build:gradle-api:3.3.2:gradle-api-3.3.2.jar:3cbd47e41bb70330dd72ec2c9fe51e6173554b484a03829b5a2de9e00841e040',
|
'com.android.tools.build:builder:3.2.1:builder-3.2.1.jar:aedcbfd115dbe91d09b4113e66ef50589b558d0aa3b2f133b1d867c9b87fae83',
|
||||||
'com.android.tools.build:manifest-merger:26.3.2:manifest-merger-26.3.2.jar:05c4a6d8b02fb9f08744876477d0a68547c03a8a9069b1f086684fa04af97c33',
|
'com.android.tools.build:gradle-api:3.2.1:gradle-api-3.2.1.jar:57cf0ac5ac1dca8afdb3f62b94265e776e7dcfa641cc3844fb53a05193de208d',
|
||||||
'com.android.tools.ddms:ddmlib:26.3.2:ddmlib-26.3.2.jar:d248da8a563d6e46d2c7ebbf371a4877e00510f4ca763c0bb272d5a281bf8b85',
|
'com.android.tools.build:manifest-merger:26.2.1:manifest-merger-26.2.1.jar:8830573263361035d38cfdcb51e2db94029c93865b21334f5fbf8a27984281a6',
|
||||||
'com.android.tools.external.com-intellij:intellij-core:26.3.2:intellij-core-26.3.2.jar:6c5ecc968230e9f4dcd0fef28885379feace1f0cd8130de6f61d649c86139bf3',
|
'com.android.tools.ddms:ddmlib:26.2.1:ddmlib-26.2.1.jar:a4bf0a29a19980bf27269465cc782064656750b77c26728f82f9e148b705218b',
|
||||||
'com.android.tools.external.com-intellij:kotlin-compiler:26.3.2:kotlin-compiler-26.3.2.jar:1007d9b07ccb49cd8eaf30fda10ed4681d4714f2f9ab2ecda39b4e539cc51bbe',
|
'com.android.tools.external.com-intellij:intellij-core:26.2.1:intellij-core-26.2.1.jar:4925ad1892c2687cb1a63427d440ef519c8c59215fefe0dc5d541d5d411fcafe',
|
||||||
'com.android.tools.external.org-jetbrains:uast:26.3.2:uast-26.3.2.jar:5d1833e562ea4f38a89708dfde695f0a162cbd39d003d3dde818c3fdc2b05317',
|
'com.android.tools.external.com-intellij:kotlin-compiler:26.2.1:kotlin-compiler-26.2.1.jar:daa064fd708f340ee25fb9823c4c74104ac77f1370b76d907eb9ae6daec0a2ae',
|
||||||
'com.android.tools.layoutlib:layoutlib-api:26.3.2:layoutlib-api-26.3.2.jar:d7e61e874ab95f5c350dd38b6a95b5c9dbe0083a02001884264cdb390cb255b8',
|
'com.android.tools.external.org-jetbrains:uast:26.2.1:uast-26.2.1.jar:f10f7258d2ab9189562cc0f9ad838c0378fdba439229173390a99de02ebac75b',
|
||||||
'com.android.tools.lint:lint-api:26.3.2:lint-api-26.3.2.jar:5867dfd7fb4a4e161a816a5d29d045f9b542d34594c00a1efec46fb4cd0e1033',
|
'com.android.tools.layoutlib:layoutlib-api:26.2.1:layoutlib-api-26.2.1.jar:ddbf4fca123733fa011595b1cc1f4ac2937ed327b60990711fafc33c775c2ade',
|
||||||
'com.android.tools.lint:lint-checks:26.3.2:lint-checks-26.3.2.jar:4b163b9c93790d2771e92ba8de58a0d9e0671ffcf2ccef3cf496efd442e27517',
|
'com.android.tools.lint:lint-api:26.2.1:lint-api-26.2.1.jar:3b57e739de567b98bc9ab56c2c0ee66fc026b4adf5843e8f9804ca0666a6f66e',
|
||||||
'com.android.tools.lint:lint-gradle-api:26.3.2:lint-gradle-api-26.3.2.jar:54cb282e0c054f9bed3f51302ce08b003c8ab7961dfd5a4f6de26c23cc23062f',
|
'com.android.tools.lint:lint-checks:26.2.1:lint-checks-26.2.1.jar:c86f4cc9aaee722ee4ad70062f7b5af91e9b041914af27adc09f545ab0fb3bc6',
|
||||||
'com.android.tools.lint:lint-gradle:26.3.2:lint-gradle-26.3.2.jar:bb139615f4ce97d42cc394b9389b49b76a6eb85be6785a5d272991543b519013',
|
'com.android.tools.lint:lint-gradle-api:26.2.1:lint-gradle-api-26.2.1.jar:2283e7af32e301565f2a797e531f0fc8c648077d457afb3ffdddbee638976c2f',
|
||||||
'com.android.tools.lint:lint:26.3.2:lint-26.3.2.jar:ef7b369f8a56a92ccb0f4c1c357666b9339e4a711a9d84747d446441746cfe4e',
|
'com.android.tools.lint:lint-gradle:26.2.1:lint-gradle-26.2.1.jar:8fd90b2f3ec788cbb9801c07ab3e1ea2255aa31a6093157d7ea0ff13d0315ecb',
|
||||||
'com.android.tools:annotations:26.3.2:annotations-26.3.2.jar:5bcce8e98b6a2f5ccf13ebcefd8f734e0b35f8b19e456575665631442ce1f7a1',
|
'com.android.tools.lint:lint-kotlin:26.2.1:lint-kotlin-26.2.1.jar:7a6a5d2b18f69cf1b900d857c2632b4c683713c533295933b8b759f8cab4a877',
|
||||||
'com.android.tools:common:26.3.2:common-26.3.2.jar:d9f8e7f0669e9a701568e3db6a87c89cf12d8fa6811c9991e969f950215ecfac',
|
'com.android.tools.lint:lint:26.2.1:lint-26.2.1.jar:7848b82ae988b90dee259ae7c7e86e05cbf52db6cd21c8bbd38ce7df08f3f8c5',
|
||||||
'com.android.tools:dvlib:26.3.2:dvlib-26.3.2.jar:d84aad56161c7773579303d69714ded6897c64c6ddfd7d456e453231e4dfe811',
|
'com.android.tools:annotations:26.2.1:annotations-26.2.1.jar:7391c6a1e080174b96e64ceb078dadd31ce4d8a2d2fee0ec65be202126f90f24',
|
||||||
'com.android.tools:repository:26.3.2:repository-26.3.2.jar:da611eeb06e9ab8750d25b9e2901e10db8e5ec6304eb4c8b7103d39e0921ea40',
|
'com.android.tools:common:26.2.1:common-26.2.1.jar:a50aab2d6411ff68f4004a87c7e93d87d8e980a0ec3b352246549897ea2d78e5',
|
||||||
'com.android.tools:sdk-common:26.3.2:sdk-common-26.3.2.jar:82823a3bf25e64fac33a286490f0cf5ac50c2cdb3c540149b030896bb44bf96c',
|
'com.android.tools:dvlib:26.2.1:dvlib-26.2.1.jar:72a83bf2839b1df9b1fbf67ba45d1bfb9f966cd774da4320c762b2be8f1688aa',
|
||||||
'com.android.tools:sdklib:26.3.2:sdklib-26.3.2.jar:424d15492af67321900963238646d27495ab60de2a5b19e6a416963bc5d6932b',
|
'com.android.tools:repository:26.2.1:repository-26.2.1.jar:fa74dae09103faef703df38550ad8fa244c5b6d1bf90d6198be932292b3d9cc1',
|
||||||
|
'com.android.tools:sdk-common:26.2.1:sdk-common-26.2.1.jar:759d4b292ca69a35cf961fca377b54158fc6c88108978006999442e80a011cf4',
|
||||||
|
'com.android.tools:sdklib:26.2.1:sdklib-26.2.1.jar:248df7ad5eac4aeb6f96c394c76760de4b7b89ac056e54d0c21a739368b91b45',
|
||||||
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
|
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
|
||||||
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
|
||||||
'com.google.code.gson:gson:2.8.0:gson-2.8.0.jar:c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825',
|
'com.google.code.gson:gson:2.8.0:gson-2.8.0.jar:c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825',
|
||||||
'com.google.dagger:dagger-compiler:2.19:dagger-compiler-2.19.jar:27a4b202a2de908182edb261f8c0a264e08e5e4733d7514bc7fbf0d31da5c0fc',
|
'com.google.dagger:dagger-compiler:2.19:dagger-compiler-2.19.jar:27a4b202a2de908182edb261f8c0a264e08e5e4733d7514bc7fbf0d31da5c0fc',
|
||||||
'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768',
|
'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768',
|
||||||
'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1',
|
'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1',
|
||||||
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
|
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
|
||||||
|
'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b',
|
||||||
'com.google.errorprone:error_prone_annotations:2.1.3:error_prone_annotations-2.1.3.jar:03d0329547c13da9e17c634d1049ea2ead093925e290567e1a364fd6b1fc7ff8',
|
'com.google.errorprone:error_prone_annotations:2.1.3:error_prone_annotations-2.1.3.jar:03d0329547c13da9e17c634d1049ea2ead093925e290567e1a364fd6b1fc7ff8',
|
||||||
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
||||||
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
|
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
|
||||||
|
'com.google.guava:guava:23.0:guava-23.0.jar:7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596',
|
||||||
'com.google.guava:guava:25.0-jre:guava-25.0-jre.jar:3fd4341776428c7e0e5c18a7c10de129475b69ab9d30aeafbb5c277bb6074fa9',
|
'com.google.guava:guava:25.0-jre:guava-25.0-jre.jar:3fd4341776428c7e0e5c18a7c10de129475b69ab9d30aeafbb5c277bb6074fa9',
|
||||||
'com.google.guava:guava:26.0-jre:guava-26.0-jre.jar:a0e9cabad665bc20bcd2b01f108e5fc03f756e13aea80abaadb9f407033bea2c',
|
|
||||||
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
|
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
|
||||||
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
|
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
|
||||||
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
|
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
|
||||||
@@ -66,22 +68,21 @@ dependencyVerification {
|
|||||||
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||||
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
|
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
|
||||||
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
|
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
|
||||||
'org.briarproject:obfs4proxy-android:0.0.9:obfs4proxy-android-0.0.9.zip:9b7e9181535ea8d8bbe8ae6338e08cf4c5fc1e357a779393e0ce49586d459ae0',
|
'org.briarproject:obfs4proxy-android:0.0.7:obfs4proxy-android-0.0.7.zip:abdfb5d889d848de9bf214f9276abbf454808a505b870819eccc9a9e985bf617',
|
||||||
'org.briarproject:tor-android:0.3.5.8:tor-android-0.3.5.8.zip:42a13a6f185be1a62f42e3f30ce66a3c099ac5ec890a65e7593111b65b44a54a',
|
'org.briarproject:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926',
|
||||||
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
|
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
|
||||||
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
|
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
|
||||||
'org.codehaus.groovy:groovy-all:2.4.15:groovy-all-2.4.15.jar:51d6c4e71782e85674239189499854359d380fb75e1a703756e3aaa5b98a5af0',
|
|
||||||
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
|
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
|
||||||
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
|
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
|
||||||
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
|
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
|
||||||
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
|
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
|
||||||
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
||||||
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
||||||
'org.jetbrains.kotlin:kotlin-reflect:1.3.21:kotlin-reflect-1.3.21.jar:a3065c822633191e0a3e3ee12a29bec234fc4b2864a6bb87ef48cce3e9e0c26a',
|
'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.21:kotlin-stdlib-common-1.3.21.jar:cea61f7b611895e64f58569a9757fc0ab0d582f107211e1930e0ce2a0add52a7',
|
'org.jetbrains.kotlin:kotlin-stdlib-common:1.2.71:kotlin-stdlib-common-1.2.71.jar:63999687ff2fce8a592dd180ffbbf8f1d21c26b4044c55cdc74ff3cf3b3cf328',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21:kotlin-stdlib-jdk7-1.3.21.jar:a87875604fd42140da6938ae4d35ee61081f4482536efc6d2615b8b626a198af',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.71:kotlin-stdlib-jdk7-1.2.71.jar:b136bd61b240e07d4d92ce00d3bd1dbf584400a7bf5f220c2f3cd22446858082',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.21:kotlin-stdlib-jdk8-1.3.21.jar:5823ed66ac122a1c55442ebca5a209a843ccd87f562edc31a787f3d2e47f74d4',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.71:kotlin-stdlib-jdk8-1.2.71.jar:ac3c8abf47790b64b4f7e2509a53f0c145e061ac1612a597520535d199946ea9',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib:1.3.21:kotlin-stdlib-1.3.21.jar:38ba2370d9f06f50433e06b2ca775b94473c2e2785f410926079ab793c72b034',
|
'org.jetbrains.kotlin:kotlin-stdlib:1.2.71:kotlin-stdlib-1.2.71.jar:4c895c270b87f5fec2a2796e1d89c15407ee821de961527c28588bb46afbc68b',
|
||||||
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
|
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
|
||||||
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
|
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
|
||||||
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package org.briarproject.bramble.api;
|
package org.briarproject.bramble.api;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper around a byte array, to allow it to be stored in maps etc.
|
* A wrapper around a byte array, to allow it to be stored in maps etc.
|
||||||
*/
|
*/
|
||||||
@@ -56,8 +57,7 @@ public class Bytes implements Comparable<Bytes> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getClass().getSimpleName() +
|
return getClass().getSimpleName() + "(" + toHexString(getBytes()) + ")";
|
||||||
"(" + StringUtils.toHexString(getBytes()) + ")";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class BytesComparator implements Comparator<Bytes> {
|
public static class BytesComparator implements Comparator<Bytes> {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.bramble.api;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
@@ -10,6 +9,8 @@ import java.util.Set;
|
|||||||
|
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
|
import static java.util.Collections.unmodifiableSet;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class Multiset<T> {
|
public class Multiset<T> {
|
||||||
@@ -96,6 +97,6 @@ public class Multiset<T> {
|
|||||||
* is unmodifiable.
|
* is unmodifiable.
|
||||||
*/
|
*/
|
||||||
public Set<T> keySet() {
|
public Set<T> keySet() {
|
||||||
return Collections.unmodifiableSet(map.keySet());
|
return unmodifiableSet(map.keySet());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class BdfMessageContext {
|
public class BdfMessageContext {
|
||||||
@@ -23,7 +24,7 @@ public class BdfMessageContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public BdfMessageContext(BdfDictionary dictionary) {
|
public BdfMessageContext(BdfDictionary dictionary) {
|
||||||
this(dictionary, Collections.emptyList());
|
this(dictionary, emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public BdfDictionary getDictionary() {
|
public BdfDictionary getDictionary() {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -23,7 +24,7 @@ import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOC
|
|||||||
public abstract class BdfMessageValidator implements MessageValidator {
|
public abstract class BdfMessageValidator implements MessageValidator {
|
||||||
|
|
||||||
protected static final Logger LOG =
|
protected static final Logger LOG =
|
||||||
Logger.getLogger(BdfMessageValidator.class.getName());
|
getLogger(BdfMessageValidator.class.getName());
|
||||||
|
|
||||||
protected final ClientHelper clientHelper;
|
protected final ClientHelper clientHelper;
|
||||||
protected final MetadataEncoder metadataEncoder;
|
protected final MetadataEncoder metadataEncoder;
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.briarproject.bramble.api.contact;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public interface ContactExchangeListener {
|
||||||
|
|
||||||
|
void contactExchangeSucceeded(Author remoteAuthor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The exchange failed because the contact already exists.
|
||||||
|
*/
|
||||||
|
void duplicateContact(Author remoteAuthor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A general failure.
|
||||||
|
*/
|
||||||
|
void contactExchangeFailed();
|
||||||
|
}
|
||||||
@@ -41,7 +41,8 @@ public interface ContactExchangeTask {
|
|||||||
/**
|
/**
|
||||||
* Exchanges contact information with a remote peer.
|
* Exchanges contact information with a remote peer.
|
||||||
*/
|
*/
|
||||||
void startExchange(LocalAuthor localAuthor, SecretKey masterSecret,
|
void startExchange(ContactExchangeListener listener,
|
||||||
|
LocalAuthor localAuthor, SecretKey masterSecret,
|
||||||
DuplexTransportConnection conn, TransportId transportId,
|
DuplexTransportConnection conn, TransportId transportId,
|
||||||
boolean alice);
|
boolean alice);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.contact.event;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.Event;
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
public class ContactExchangeFailedEvent extends Event {
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private final Author duplicateRemoteAuthor;
|
|
||||||
|
|
||||||
public ContactExchangeFailedEvent(@Nullable Author duplicateRemoteAuthor) {
|
|
||||||
this.duplicateRemoteAuthor = duplicateRemoteAuthor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContactExchangeFailedEvent() {
|
|
||||||
this(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Author getDuplicateRemoteAuthor() {
|
|
||||||
return duplicateRemoteAuthor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean wasDuplicateContact() {
|
|
||||||
return duplicateRemoteAuthor != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.contact.event;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.Event;
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
public class ContactExchangeSucceededEvent extends Event {
|
|
||||||
|
|
||||||
private final Author remoteAuthor;
|
|
||||||
|
|
||||||
public ContactExchangeSucceededEvent(Author remoteAuthor) {
|
|
||||||
this.remoteAuthor = remoteAuthor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Author getRemoteAuthor() {
|
|
||||||
return remoteAuthor;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.Bytes;
|
|||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -24,9 +23,9 @@ public class BdfDictionary extends TreeMap<String, Object> {
|
|||||||
* );
|
* );
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public static BdfDictionary of(Entry<String, ?>... entries) {
|
public static BdfDictionary of(BdfEntry... entries) {
|
||||||
BdfDictionary d = new BdfDictionary();
|
BdfDictionary d = new BdfDictionary();
|
||||||
for (Entry<String, ?> e : entries) d.put(e.getKey(), e.getValue());
|
for (BdfEntry e : entries) d.put(e.getKey(), e.getValue());
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import org.briarproject.bramble.api.Bytes;
|
|||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@@ -22,7 +22,7 @@ public class BdfList extends ArrayList<Object> {
|
|||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public static BdfList of(Object... items) {
|
public static BdfList of(Object... items) {
|
||||||
return new BdfList(Arrays.asList(items));
|
return new BdfList(asList(items));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BdfList() {
|
public BdfList() {
|
||||||
@@ -33,6 +33,7 @@ public class BdfList extends ArrayList<Object> {
|
|||||||
super(items);
|
super(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||||
private boolean isInRange(int index) {
|
private boolean isInRange(int index) {
|
||||||
return index >= 0 && index < size();
|
return index >= 0 && index < size();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ package org.briarproject.bramble.api.db;
|
|||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper around a database transaction. Transactions are not thread-safe.
|
* A wrapper around a database transaction. Transactions are not thread-safe.
|
||||||
*/
|
*/
|
||||||
@@ -53,7 +54,7 @@ public class Transaction {
|
|||||||
* Returns any events attached to the transaction.
|
* Returns any events attached to the transaction.
|
||||||
*/
|
*/
|
||||||
public List<Event> getEvents() {
|
public List<Event> getEvents() {
|
||||||
if (events == null) return Collections.emptyList();
|
if (events == null) return emptyList();
|
||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ package org.briarproject.bramble.api.identity;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.Nameable;
|
import org.briarproject.bramble.api.Nameable;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pseudonym for a user.
|
* A pseudonym for a user.
|
||||||
@@ -28,7 +28,7 @@ public class Author implements Nameable {
|
|||||||
|
|
||||||
public Author(AuthorId id, int formatVersion, String name,
|
public Author(AuthorId id, int formatVersion, String name,
|
||||||
byte[] publicKey) {
|
byte[] publicKey) {
|
||||||
int nameLength = StringUtils.toUtf8(name).length;
|
int nameLength = toUtf8(name).length;
|
||||||
if (nameLength == 0 || nameLength > MAX_AUTHOR_NAME_LENGTH)
|
if (nameLength == 0 || nameLength > MAX_AUTHOR_NAME_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if (publicKey.length == 0 || publicKey.length > MAX_PUBLIC_KEY_LENGTH)
|
if (publicKey.length == 0 || publicKey.length > MAX_PUBLIC_KEY_LENGTH)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package org.briarproject.bramble.api.plugin;
|
package org.briarproject.bramble.api.plugin;
|
||||||
|
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type-safe wrapper for a namespaced string that uniquely identifies a
|
* Type-safe wrapper for a namespaced string that uniquely identifies a
|
||||||
@@ -11,12 +11,12 @@ public class TransportId {
|
|||||||
/**
|
/**
|
||||||
* The maximum length of a transport identifier in UTF-8 bytes.
|
* The maximum length of a transport identifier in UTF-8 bytes.
|
||||||
*/
|
*/
|
||||||
public static int MAX_TRANSPORT_ID_LENGTH = 100;
|
public static final int MAX_TRANSPORT_ID_LENGTH = 100;
|
||||||
|
|
||||||
private final String id;
|
private final String id;
|
||||||
|
|
||||||
public TransportId(String id) {
|
public TransportId(String id) {
|
||||||
int length = StringUtils.toUtf8(id).length;
|
int length = toUtf8(id).length;
|
||||||
if (length == 0 || length > MAX_TRANSPORT_ID_LENGTH)
|
if (length == 0 || length > MAX_TRANSPORT_ID_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package org.briarproject.bramble.api.sync;
|
package org.briarproject.bramble.api.sync;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type-safe wrapper for a namespaced string that uniquely identifies a sync
|
* Type-safe wrapper for a namespaced string that uniquely identifies a sync
|
||||||
* client.
|
* client.
|
||||||
@@ -16,12 +17,12 @@ public class ClientId implements Comparable<ClientId> {
|
|||||||
/**
|
/**
|
||||||
* The maximum length of a client identifier in UTF-8 bytes.
|
* The maximum length of a client identifier in UTF-8 bytes.
|
||||||
*/
|
*/
|
||||||
public static int MAX_CLIENT_ID_LENGTH = 100;
|
public static final int MAX_CLIENT_ID_LENGTH = 100;
|
||||||
|
|
||||||
private final String id;
|
private final String id;
|
||||||
|
|
||||||
public ClientId(String id) {
|
public ClientId(String id) {
|
||||||
int length = StringUtils.toUtf8(id).length;
|
int length = toUtf8(id).length;
|
||||||
if (length == 0 || length > MAX_CLIENT_ID_LENGTH)
|
if (length == 0 || length > MAX_CLIENT_ID_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import org.briarproject.bramble.api.db.Metadata;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class MessageContext {
|
public class MessageContext {
|
||||||
@@ -22,7 +23,7 @@ public class MessageContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MessageContext(Metadata metadata) {
|
public MessageContext(Metadata metadata) {
|
||||||
this(metadata, Collections.emptyList());
|
this(metadata, emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Metadata getMetadata() {
|
public Metadata getMetadata() {
|
||||||
|
|||||||
@@ -16,12 +16,13 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class IoUtils {
|
public class IoUtils {
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger(IoUtils.class.getName());
|
private static final Logger LOG = getLogger(IoUtils.class.getName());
|
||||||
|
|
||||||
public static void deleteFileOrDir(File f) {
|
public static void deleteFileOrDir(File f) {
|
||||||
if (f.isFile()) {
|
if (f.isFile()) {
|
||||||
|
|||||||
@@ -7,13 +7,15 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class ValidationUtils {
|
public class ValidationUtils {
|
||||||
|
|
||||||
public static void checkLength(@Nullable String s, int minLength,
|
public static void checkLength(@Nullable String s, int minLength,
|
||||||
int maxLength) throws FormatException {
|
int maxLength) throws FormatException {
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
int length = StringUtils.toUtf8(s).length;
|
int length = toUtf8(s).length;
|
||||||
if (length < minLength) throw new FormatException();
|
if (length < minLength) throw new FormatException();
|
||||||
if (length > maxLength) throw new FormatException();
|
if (length > maxLength) throw new FormatException();
|
||||||
}
|
}
|
||||||
@@ -21,7 +23,7 @@ public class ValidationUtils {
|
|||||||
|
|
||||||
public static void checkLength(@Nullable String s, int length)
|
public static void checkLength(@Nullable String s, int length)
|
||||||
throws FormatException {
|
throws FormatException {
|
||||||
if (s != null && StringUtils.toUtf8(s).length != length)
|
if (s != null && toUtf8(s).length != length)
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.util.Collections;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -19,15 +20,15 @@ public class BdfDictionaryTest extends BrambleTestCase {
|
|||||||
public void testConstructors() {
|
public void testConstructors() {
|
||||||
assertEquals(Collections.<String, Object>emptyMap(),
|
assertEquals(Collections.<String, Object>emptyMap(),
|
||||||
new BdfDictionary());
|
new BdfDictionary());
|
||||||
assertEquals(Collections.singletonMap("foo", NULL_VALUE),
|
assertEquals(singletonMap("foo", NULL_VALUE),
|
||||||
new BdfDictionary(Collections.singletonMap("foo", NULL_VALUE)));
|
new BdfDictionary(singletonMap("foo", NULL_VALUE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFactoryMethod() {
|
public void testFactoryMethod() {
|
||||||
assertEquals(Collections.<String, Object>emptyMap(),
|
assertEquals(Collections.<String, Object>emptyMap(),
|
||||||
BdfDictionary.of());
|
BdfDictionary.of());
|
||||||
assertEquals(Collections.singletonMap("foo", NULL_VALUE),
|
assertEquals(singletonMap("foo", NULL_VALUE),
|
||||||
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)));
|
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testKeySetIteratorIsOrderedByKeys() throws Exception {
|
public void testKeySetIteratorIsOrderedByKeys() {
|
||||||
BdfDictionary d = new BdfDictionary();
|
BdfDictionary d = new BdfDictionary();
|
||||||
d.put("a", 1);
|
d.put("a", 1);
|
||||||
d.put("d", 4);
|
d.put("d", 4);
|
||||||
@@ -86,7 +87,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValuesIteratorIsOrderedByKeys() throws Exception {
|
public void testValuesIteratorIsOrderedByKeys() {
|
||||||
BdfDictionary d = new BdfDictionary();
|
BdfDictionary d = new BdfDictionary();
|
||||||
d.put("a", 1);
|
d.put("a", 1);
|
||||||
d.put("d", 4);
|
d.put("d", 4);
|
||||||
@@ -105,7 +106,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEntrySetIteratorIsOrderedByKeys() throws Exception {
|
public void testEntrySetIteratorIsOrderedByKeys() {
|
||||||
BdfDictionary d = new BdfDictionary();
|
BdfDictionary d = new BdfDictionary();
|
||||||
d.put("a", 1);
|
d.put("a", 1);
|
||||||
d.put("d", 4);
|
d.put("d", 4);
|
||||||
|
|||||||
@@ -5,26 +5,31 @@ import org.briarproject.bramble.api.FormatException;
|
|||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Random;
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
public class BdfListTest extends BrambleTestCase {
|
public class BdfListTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
private final Random random = new Random();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConstructors() {
|
public void testConstructors() {
|
||||||
assertEquals(Collections.emptyList(), new BdfList());
|
assertEquals(emptyList(), new BdfList());
|
||||||
assertEquals(Arrays.asList(1, 2, NULL_VALUE),
|
assertEquals(asList(1, 2, NULL_VALUE),
|
||||||
new BdfList(Arrays.asList(1, 2, NULL_VALUE)));
|
new BdfList(asList(1, 2, NULL_VALUE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFactoryMethod() {
|
public void testFactoryMethod() {
|
||||||
assertEquals(Collections.emptyList(), BdfList.of());
|
assertEquals(emptyList(), BdfList.of());
|
||||||
assertEquals(Arrays.asList(1, 2, NULL_VALUE),
|
assertEquals(asList(1, 2, NULL_VALUE),
|
||||||
BdfList.of(1, 2, NULL_VALUE));
|
BdfList.of(1, 2, NULL_VALUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,22 +69,21 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("ConstantConditions")
|
public void testIndexOutOfBoundsReturnsDefaultValue() {
|
||||||
public void testIndexOutOfBoundsReturnsDefaultValue() throws Exception {
|
|
||||||
BdfList list = BdfList.of(1, 2, 3);
|
BdfList list = BdfList.of(1, 2, 3);
|
||||||
boolean defaultBoolean = true;
|
boolean defaultBoolean = random.nextBoolean();
|
||||||
assertEquals(defaultBoolean, list.getBoolean(-1, defaultBoolean));
|
assertEquals(defaultBoolean, list.getBoolean(-1, defaultBoolean));
|
||||||
assertEquals(defaultBoolean, list.getBoolean(3, defaultBoolean));
|
assertEquals(defaultBoolean, list.getBoolean(3, defaultBoolean));
|
||||||
Long defaultLong = 123L;
|
Long defaultLong = random.nextLong();
|
||||||
assertEquals(defaultLong, list.getLong(-1, defaultLong));
|
assertEquals(defaultLong, list.getLong(-1, defaultLong));
|
||||||
assertEquals(defaultLong, list.getLong(3, defaultLong));
|
assertEquals(defaultLong, list.getLong(3, defaultLong));
|
||||||
Double defaultDouble = 1.23;
|
Double defaultDouble = random.nextDouble();
|
||||||
assertEquals(defaultDouble, list.getDouble(-1, defaultDouble));
|
assertEquals(defaultDouble, list.getDouble(-1, defaultDouble));
|
||||||
assertEquals(defaultDouble, list.getDouble(3, defaultDouble));
|
assertEquals(defaultDouble, list.getDouble(3, defaultDouble));
|
||||||
String defaultString = "123";
|
String defaultString = getRandomString(123);
|
||||||
assertEquals(defaultString, list.getString(-1, defaultString));
|
assertEquals(defaultString, list.getString(-1, defaultString));
|
||||||
assertEquals(defaultString, list.getString(3, defaultString));
|
assertEquals(defaultString, list.getString(3, defaultString));
|
||||||
byte[] defaultBytes = new byte[] {1, 2, 3};
|
byte[] defaultBytes = getRandomBytes(123);
|
||||||
assertArrayEquals(defaultBytes, list.getRaw(-1, defaultBytes));
|
assertArrayEquals(defaultBytes, list.getRaw(-1, defaultBytes));
|
||||||
assertArrayEquals(defaultBytes, list.getRaw(3, defaultBytes));
|
assertArrayEquals(defaultBytes, list.getRaw(3, defaultBytes));
|
||||||
BdfList defaultList = BdfList.of(1, 2, 3);
|
BdfList defaultList = BdfList.of(1, 2, 3);
|
||||||
@@ -95,18 +99,17 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("ConstantConditions")
|
public void testWrongTypeReturnsDefaultValue() {
|
||||||
public void testWrongTypeReturnsDefaultValue() throws Exception {
|
|
||||||
BdfList list = BdfList.of(1, 2, 3, true);
|
BdfList list = BdfList.of(1, 2, 3, true);
|
||||||
boolean defaultBoolean = true;
|
boolean defaultBoolean = random.nextBoolean();
|
||||||
assertEquals(defaultBoolean, list.getBoolean(0, defaultBoolean));
|
assertEquals(defaultBoolean, list.getBoolean(0, defaultBoolean));
|
||||||
Long defaultLong = 123L;
|
Long defaultLong = random.nextLong();
|
||||||
assertEquals(defaultLong, list.getLong(3, defaultLong));
|
assertEquals(defaultLong, list.getLong(3, defaultLong));
|
||||||
Double defaultDouble = 1.23;
|
Double defaultDouble = random.nextDouble();
|
||||||
assertEquals(defaultDouble, list.getDouble(0, defaultDouble));
|
assertEquals(defaultDouble, list.getDouble(0, defaultDouble));
|
||||||
String defaultString = "123";
|
String defaultString = getRandomString(123);
|
||||||
assertEquals(defaultString, list.getString(0, defaultString));
|
assertEquals(defaultString, list.getString(0, defaultString));
|
||||||
byte[] defaultBytes = new byte[] {1, 2, 3};
|
byte[] defaultBytes = getRandomBytes(123);
|
||||||
assertArrayEquals(defaultBytes, list.getRaw(0, defaultBytes));
|
assertArrayEquals(defaultBytes, list.getRaw(0, defaultBytes));
|
||||||
BdfList defaultList = BdfList.of(1, 2, 3);
|
BdfList defaultList = BdfList.of(1, 2, 3);
|
||||||
assertEquals(defaultList, list.getList(0, defaultList));
|
assertEquals(defaultList, list.getList(0, defaultList));
|
||||||
|
|||||||
@@ -12,12 +12,10 @@ import org.briarproject.bramble.api.sync.Group;
|
|||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -25,6 +23,7 @@ import java.util.Random;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.sort;
|
||||||
import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION;
|
import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
@@ -33,6 +32,7 @@ import static org.briarproject.bramble.api.properties.TransportPropertyConstants
|
|||||||
import static org.briarproject.bramble.api.sync.ClientId.MAX_CLIENT_ID_LENGTH;
|
import static org.briarproject.bramble.api.sync.ClientId.MAX_CLIENT_ID_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||||
|
import static org.briarproject.bramble.util.IoUtils.deleteFileOrDir;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
|
|
||||||
public class TestUtils {
|
public class TestUtils {
|
||||||
@@ -48,8 +48,10 @@ public class TestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteTestDirectory(File testDir) {
|
public static void deleteTestDirectory(File testDir) {
|
||||||
IoUtils.deleteFileOrDir(testDir);
|
deleteFileOrDir(testDir);
|
||||||
testDir.getParentFile().delete(); // Delete if empty
|
// Delete parent directory only if it's empty
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
|
testDir.getParentFile().delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] getRandomBytes(int length) {
|
public static byte[] getRandomBytes(int length) {
|
||||||
@@ -145,7 +147,7 @@ public class TestUtils {
|
|||||||
if (size == 0) throw new IllegalArgumentException();
|
if (size == 0) throw new IllegalArgumentException();
|
||||||
List<Double> sorted = new ArrayList<>(size);
|
List<Double> sorted = new ArrayList<>(size);
|
||||||
for (Number n : samples) sorted.add(n.doubleValue());
|
for (Number n : samples) sorted.add(n.doubleValue());
|
||||||
Collections.sort(sorted);
|
sort(sorted);
|
||||||
if (size % 2 == 1) return sorted.get(size / 2);
|
if (size % 2 == 1) return sorted.get(size / 2);
|
||||||
double low = sorted.get(size / 2 - 1), high = sorted.get(size / 2);
|
double low = sorted.get(size / 2 - 1), high = sorted.get(size / 2);
|
||||||
return (low + high) / 2;
|
return (low + high) / 2;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ dependencies {
|
|||||||
implementation 'org.bitlet:weupnp:0.1.4'
|
implementation 'org.bitlet:weupnp:0.1.4'
|
||||||
implementation 'net.i2p.crypto:eddsa:0.2.0'
|
implementation 'net.i2p.crypto:eddsa:0.2.0'
|
||||||
implementation 'org.whispersystems:curve25519-java:0.5.0'
|
implementation 'org.whispersystems:curve25519-java:0.5.0'
|
||||||
|
implementation 'org.briarproject:jtorctl:0.3'
|
||||||
|
|
||||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
|
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
*.class
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
// Copyright 2005 Nick Mathewson, Roger Dingledine
|
|
||||||
// See LICENSE file for copying information
|
|
||||||
package net.freehaven.tor.control;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static class to do bytewise structure manipulation in Java.
|
|
||||||
*/
|
|
||||||
/* XXXX There must be a better way to do most of this.
|
|
||||||
* XXXX The string logic here uses default encoding, which is stupid.
|
|
||||||
*/
|
|
||||||
final class Bytes {
|
|
||||||
|
|
||||||
/** Write the two-byte value in 's' into the byte array 'ba', starting at
|
|
||||||
* the index 'pos'. */
|
|
||||||
public static void setU16(byte[] ba, int pos, short s) {
|
|
||||||
ba[pos] = (byte)((s >> 8) & 0xff);
|
|
||||||
ba[pos+1] = (byte)((s ) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Write the four-byte value in 'i' into the byte array 'ba', starting at
|
|
||||||
* the index 'pos'. */
|
|
||||||
public static void setU32(byte[] ba, int pos, int i) {
|
|
||||||
ba[pos] = (byte)((i >> 24) & 0xff);
|
|
||||||
ba[pos+1] = (byte)((i >> 16) & 0xff);
|
|
||||||
ba[pos+2] = (byte)((i >> 8) & 0xff);
|
|
||||||
ba[pos+3] = (byte)((i ) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return the four-byte value starting at index 'pos' within 'ba' */
|
|
||||||
public static int getU32(byte[] ba, int pos) {
|
|
||||||
return
|
|
||||||
((ba[pos ]&0xff)<<24) |
|
|
||||||
((ba[pos+1]&0xff)<<16) |
|
|
||||||
((ba[pos+2]&0xff)<< 8) |
|
|
||||||
((ba[pos+3]&0xff));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getU32S(byte[] ba, int pos) {
|
|
||||||
return String.valueOf( (getU32(ba,pos))&0xffffffffL );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return the two-byte value starting at index 'pos' within 'ba' */
|
|
||||||
public static int getU16(byte[] ba, int pos) {
|
|
||||||
return
|
|
||||||
((ba[pos ]&0xff)<<8) |
|
|
||||||
((ba[pos+1]&0xff));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return the string starting at position 'pos' of ba and extending
|
|
||||||
* until a zero byte or the end of the string. */
|
|
||||||
public static String getNulTerminatedStr(byte[] ba, int pos) {
|
|
||||||
int len, maxlen = ba.length-pos;
|
|
||||||
for (len=0; len<maxlen; ++len) {
|
|
||||||
if (ba[pos+len] == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return new String(ba, pos, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read bytes from 'ba' starting at 'pos', dividing them into strings
|
|
||||||
* along the character in 'split' and writing them into 'lst'
|
|
||||||
*/
|
|
||||||
public static void splitStr(List<String> lst, byte[] ba, int pos, byte split) {
|
|
||||||
while (pos < ba.length && ba[pos] != 0) {
|
|
||||||
int len;
|
|
||||||
for (len=0; pos+len < ba.length; ++len) {
|
|
||||||
if (ba[pos+len] == 0 || ba[pos+len] == split)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (len>0)
|
|
||||||
lst.add(new String(ba, pos, len));
|
|
||||||
pos += len;
|
|
||||||
if (ba[pos] == split)
|
|
||||||
++pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read bytes from 'ba' starting at 'pos', dividing them into strings
|
|
||||||
* along the character in 'split' and writing them into 'lst'
|
|
||||||
*/
|
|
||||||
public static List<String> splitStr(List<String> lst, String str) {
|
|
||||||
// split string on spaces, include trailing/leading
|
|
||||||
String[] tokenArray = str.split(" ", -1);
|
|
||||||
if (lst == null) {
|
|
||||||
lst = Arrays.asList( tokenArray );
|
|
||||||
} else {
|
|
||||||
lst.addAll( Arrays.asList( tokenArray ) );
|
|
||||||
}
|
|
||||||
return lst;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final char[] NYBBLES = {
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
|
||||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final String hex(byte[] ba) {
|
|
||||||
StringBuffer buf = new StringBuffer();
|
|
||||||
for (int i = 0; i < ba.length; ++i) {
|
|
||||||
int b = (ba[i]) & 0xff;
|
|
||||||
buf.append(NYBBLES[b >> 4]);
|
|
||||||
buf.append(NYBBLES[b&0x0f]);
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bytes() {};
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright 2005 Nick Mathewson, Roger Dingledine
|
|
||||||
// See LICENSE file for copying information
|
|
||||||
package net.freehaven.tor.control;
|
|
||||||
|
|
||||||
/** A single key-value pair from Tor's configuration. */
|
|
||||||
public class ConfigEntry {
|
|
||||||
public ConfigEntry(String k, String v) {
|
|
||||||
key = k;
|
|
||||||
value = v;
|
|
||||||
is_default = false;
|
|
||||||
}
|
|
||||||
public ConfigEntry(String k) {
|
|
||||||
key = k;
|
|
||||||
value = "";
|
|
||||||
is_default = true;
|
|
||||||
}
|
|
||||||
public final String key;
|
|
||||||
public final String value;
|
|
||||||
public final boolean is_default;
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
// Copyright 2005 Nick Mathewson, Roger Dingledine
|
|
||||||
// See LICENSE file for copying information
|
|
||||||
package net.freehaven.tor.control;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract interface whose methods are invoked when Tor sends us an event.
|
|
||||||
*
|
|
||||||
* @see TorControlConnection#setEventHandler
|
|
||||||
* @see TorControlConnection#setEvents
|
|
||||||
*/
|
|
||||||
public interface EventHandler {
|
|
||||||
/**
|
|
||||||
* Invoked when a circuit's status has changed.
|
|
||||||
* Possible values for <b>status</b> are:
|
|
||||||
* <ul>
|
|
||||||
* <li>"LAUNCHED" : circuit ID assigned to new circuit</li>
|
|
||||||
* <li>"BUILT" : all hops finished, can now accept streams</li>
|
|
||||||
* <li>"EXTENDED" : one more hop has been completed</li>
|
|
||||||
* <li>"FAILED" : circuit closed (was not built)</li>
|
|
||||||
* <li>"CLOSED" : circuit closed (was built)</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* <b>circID</b> is the alphanumeric identifier of the affected circuit,
|
|
||||||
* and <b>path</b> is a comma-separated list of alphanumeric ServerIDs.
|
|
||||||
*/
|
|
||||||
public void circuitStatus(String status, String circID, String path);
|
|
||||||
/**
|
|
||||||
* Invoked when a stream's status has changed.
|
|
||||||
* Possible values for <b>status</b> are:
|
|
||||||
* <ul>
|
|
||||||
* <li>"NEW" : New request to connect</li>
|
|
||||||
* <li>"NEWRESOLVE" : New request to resolve an address</li>
|
|
||||||
* <li>"SENTCONNECT" : Sent a connect cell along a circuit</li>
|
|
||||||
* <li>"SENTRESOLVE" : Sent a resolve cell along a circuit</li>
|
|
||||||
* <li>"SUCCEEDED" : Received a reply; stream established</li>
|
|
||||||
* <li>"FAILED" : Stream failed and not retriable.</li>
|
|
||||||
* <li>"CLOSED" : Stream closed</li>
|
|
||||||
* <li>"DETACHED" : Detached from circuit; still retriable.</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* <b>streamID</b> is the alphanumeric identifier of the affected stream,
|
|
||||||
* and its <b>target</b> is specified as address:port.
|
|
||||||
*/
|
|
||||||
public void streamStatus(String status, String streamID, String target);
|
|
||||||
/**
|
|
||||||
* Invoked when the status of a connection to an OR has changed.
|
|
||||||
* Possible values for <b>status</b> are ["LAUNCHED" | "CONNECTED" | "FAILED" | "CLOSED"].
|
|
||||||
* <b>orName</b> is the alphanumeric identifier of the OR affected.
|
|
||||||
*/
|
|
||||||
public void orConnStatus(String status, String orName);
|
|
||||||
/**
|
|
||||||
* Invoked once per second. <b>read</b> and <b>written</b> are
|
|
||||||
* the number of bytes read and written, respectively, in
|
|
||||||
* the last second.
|
|
||||||
*/
|
|
||||||
public void bandwidthUsed(long read, long written);
|
|
||||||
/**
|
|
||||||
* Invoked whenever Tor learns about new ORs. The <b>orList</b> object
|
|
||||||
* contains the alphanumeric ServerIDs associated with the new ORs.
|
|
||||||
*/
|
|
||||||
public void newDescriptors(java.util.List<String> orList);
|
|
||||||
/**
|
|
||||||
* Invoked when Tor logs a message.
|
|
||||||
* <b>severity</b> is one of ["DEBUG" | "INFO" | "NOTICE" | "WARN" | "ERR"],
|
|
||||||
* and <b>msg</b> is the message string.
|
|
||||||
*/
|
|
||||||
public void message(String severity, String msg);
|
|
||||||
/**
|
|
||||||
* Invoked when an unspecified message is received.
|
|
||||||
* <type> is the message type, and <msg> is the message string.
|
|
||||||
*/
|
|
||||||
public void unrecognized(String type, String msg);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// Copyright 2005 Nick Mathewson, Roger Dingledine
|
|
||||||
// See LICENSE file for copying information
|
|
||||||
package net.freehaven.tor.control;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of EventHandler that ignores all events. Useful
|
|
||||||
* when you only want to override one method.
|
|
||||||
*/
|
|
||||||
public class NullEventHandler implements EventHandler {
|
|
||||||
public void circuitStatus(String status, String circID, String path) {}
|
|
||||||
public void streamStatus(String status, String streamID, String target) {}
|
|
||||||
public void orConnStatus(String status, String orName) {}
|
|
||||||
public void bandwidthUsed(long read, long written) {}
|
|
||||||
public void newDescriptors(java.util.List<String> orList) {}
|
|
||||||
public void message(String severity, String msg) {}
|
|
||||||
public void unrecognized(String type, String msg) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
// Copyright 2005 Nick Mathewson, Roger Dingledine
|
|
||||||
// See LICENSE file for copying information
|
|
||||||
package net.freehaven.tor.control;
|
|
||||||
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A hashed digest of a secret password (used to set control connection
|
|
||||||
* security.)
|
|
||||||
*
|
|
||||||
* For the actual hashing algorithm, see RFC2440's secret-to-key conversion.
|
|
||||||
*/
|
|
||||||
public class PasswordDigest {
|
|
||||||
|
|
||||||
private final byte[] secret;
|
|
||||||
private final String hashedKey;
|
|
||||||
|
|
||||||
/** Return a new password digest with a random secret and salt. */
|
|
||||||
public static PasswordDigest generateDigest() {
|
|
||||||
byte[] secret = new byte[20];
|
|
||||||
SecureRandom rng = new SecureRandom();
|
|
||||||
rng.nextBytes(secret);
|
|
||||||
return new PasswordDigest(secret);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Construct a new password digest with a given secret and random salt */
|
|
||||||
public PasswordDigest(byte[] secret) {
|
|
||||||
this(secret, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Construct a new password digest with a given secret and random salt.
|
|
||||||
* Note that the 9th byte of the specifier determines the number of hash
|
|
||||||
* iterations as in RFC2440.
|
|
||||||
*/
|
|
||||||
public PasswordDigest(byte[] secret, byte[] specifier) {
|
|
||||||
this.secret = secret.clone();
|
|
||||||
if (specifier == null) {
|
|
||||||
specifier = new byte[9];
|
|
||||||
SecureRandom rng = new SecureRandom();
|
|
||||||
rng.nextBytes(specifier);
|
|
||||||
specifier[8] = 96;
|
|
||||||
}
|
|
||||||
hashedKey = "16:"+encodeBytes(secretToKey(secret, specifier));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return the secret used to generate this password hash.
|
|
||||||
*/
|
|
||||||
public byte[] getSecret() {
|
|
||||||
return secret.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return the hashed password in the format used by Tor. */
|
|
||||||
public String getHashedPassword() {
|
|
||||||
return hashedKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Parameter used by RFC2440's s2k algorithm. */
|
|
||||||
private static final int EXPBIAS = 6;
|
|
||||||
|
|
||||||
/** Implement rfc2440 s2k */
|
|
||||||
public static byte[] secretToKey(byte[] secret, byte[] specifier) {
|
|
||||||
MessageDigest d;
|
|
||||||
try {
|
|
||||||
d = MessageDigest.getInstance("SHA-1");
|
|
||||||
} catch (NoSuchAlgorithmException ex) {
|
|
||||||
throw new RuntimeException("Can't run without sha-1.");
|
|
||||||
}
|
|
||||||
int c = (specifier[8])&0xff;
|
|
||||||
int count = (16 + (c&15)) << ((c>>4) + EXPBIAS);
|
|
||||||
|
|
||||||
byte[] tmp = new byte[8+secret.length];
|
|
||||||
System.arraycopy(specifier, 0, tmp, 0, 8);
|
|
||||||
System.arraycopy(secret, 0, tmp, 8, secret.length);
|
|
||||||
while (count > 0) {
|
|
||||||
if (count >= tmp.length) {
|
|
||||||
d.update(tmp);
|
|
||||||
count -= tmp.length;
|
|
||||||
} else {
|
|
||||||
d.update(tmp, 0, count);
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
byte[] key = new byte[20+9];
|
|
||||||
System.arraycopy(d.digest(), 0, key, 9, 20);
|
|
||||||
System.arraycopy(specifier, 0, key, 0, 9);
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return a hexadecimal encoding of a byte array. */
|
|
||||||
// XXX There must be a better way to do this in Java.
|
|
||||||
private static final String encodeBytes(byte[] ba) {
|
|
||||||
return Bytes.hex(ba);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
We broke the version detection stuff in Tor 0.1.2.16 / 0.2.0.4-alpha.
|
|
||||||
Somebody should rip out the v0 control protocol stuff from here, and
|
|
||||||
it should start working again. -RD
|
|
||||||
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
// Copyright 2005 Nick Mathewson, Roger Dingledine
|
|
||||||
// See LICENSE file for copying information
|
|
||||||
package net.freehaven.tor.control;
|
|
||||||
|
|
||||||
/** Interface defining constants used by the Tor controller protocol.
|
|
||||||
*/
|
|
||||||
// XXXX Take documentation for these from control-spec.txt
|
|
||||||
public interface TorControlCommands {
|
|
||||||
|
|
||||||
public static final short CMD_ERROR = 0x0000;
|
|
||||||
public static final short CMD_DONE = 0x0001;
|
|
||||||
public static final short CMD_SETCONF = 0x0002;
|
|
||||||
public static final short CMD_GETCONF = 0x0003;
|
|
||||||
public static final short CMD_CONFVALUE = 0x0004;
|
|
||||||
public static final short CMD_SETEVENTS = 0x0005;
|
|
||||||
public static final short CMD_EVENT = 0x0006;
|
|
||||||
public static final short CMD_AUTH = 0x0007;
|
|
||||||
public static final short CMD_SAVECONF = 0x0008;
|
|
||||||
public static final short CMD_SIGNAL = 0x0009;
|
|
||||||
public static final short CMD_MAPADDRESS = 0x000A;
|
|
||||||
public static final short CMD_GETINFO = 0x000B;
|
|
||||||
public static final short CMD_INFOVALUE = 0x000C;
|
|
||||||
public static final short CMD_EXTENDCIRCUIT = 0x000D;
|
|
||||||
public static final short CMD_ATTACHSTREAM = 0x000E;
|
|
||||||
public static final short CMD_POSTDESCRIPTOR = 0x000F;
|
|
||||||
public static final short CMD_FRAGMENTHEADER = 0x0010;
|
|
||||||
public static final short CMD_FRAGMENT = 0x0011;
|
|
||||||
public static final short CMD_REDIRECTSTREAM = 0x0012;
|
|
||||||
public static final short CMD_CLOSESTREAM = 0x0013;
|
|
||||||
public static final short CMD_CLOSECIRCUIT = 0x0014;
|
|
||||||
|
|
||||||
public static final String[] CMD_NAMES = {
|
|
||||||
"ERROR",
|
|
||||||
"DONE",
|
|
||||||
"SETCONF",
|
|
||||||
"GETCONF",
|
|
||||||
"CONFVALUE",
|
|
||||||
"SETEVENTS",
|
|
||||||
"EVENT",
|
|
||||||
"AUTH",
|
|
||||||
"SAVECONF",
|
|
||||||
"SIGNAL",
|
|
||||||
"MAPADDRESS",
|
|
||||||
"GETINFO",
|
|
||||||
"INFOVALUE",
|
|
||||||
"EXTENDCIRCUIT",
|
|
||||||
"ATTACHSTREAM",
|
|
||||||
"POSTDESCRIPTOR",
|
|
||||||
"FRAGMENTHEADER",
|
|
||||||
"FRAGMENT",
|
|
||||||
"REDIRECTSTREAM",
|
|
||||||
"CLOSESTREAM",
|
|
||||||
"CLOSECIRCUIT",
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final short EVENT_CIRCSTATUS = 0x0001;
|
|
||||||
public static final short EVENT_STREAMSTATUS = 0x0002;
|
|
||||||
public static final short EVENT_ORCONNSTATUS = 0x0003;
|
|
||||||
public static final short EVENT_BANDWIDTH = 0x0004;
|
|
||||||
public static final short EVENT_NEWDESCRIPTOR = 0x0006;
|
|
||||||
public static final short EVENT_MSG_DEBUG = 0x0007;
|
|
||||||
public static final short EVENT_MSG_INFO = 0x0008;
|
|
||||||
public static final short EVENT_MSG_NOTICE = 0x0009;
|
|
||||||
public static final short EVENT_MSG_WARN = 0x000A;
|
|
||||||
public static final short EVENT_MSG_ERROR = 0x000B;
|
|
||||||
|
|
||||||
public static final String[] EVENT_NAMES = {
|
|
||||||
"(0)",
|
|
||||||
"CIRC",
|
|
||||||
"STREAM",
|
|
||||||
"ORCONN",
|
|
||||||
"BW",
|
|
||||||
"OLDLOG",
|
|
||||||
"NEWDESC",
|
|
||||||
"DEBUG",
|
|
||||||
"INFO",
|
|
||||||
"NOTICE",
|
|
||||||
"WARN",
|
|
||||||
"ERR",
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final byte CIRC_STATUS_LAUNCHED = 0x01;
|
|
||||||
public static final byte CIRC_STATUS_BUILT = 0x02;
|
|
||||||
public static final byte CIRC_STATUS_EXTENDED = 0x03;
|
|
||||||
public static final byte CIRC_STATUS_FAILED = 0x04;
|
|
||||||
public static final byte CIRC_STATUS_CLOSED = 0x05;
|
|
||||||
|
|
||||||
public static final String[] CIRC_STATUS_NAMES = {
|
|
||||||
"LAUNCHED",
|
|
||||||
"BUILT",
|
|
||||||
"EXTENDED",
|
|
||||||
"FAILED",
|
|
||||||
"CLOSED",
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final byte STREAM_STATUS_SENT_CONNECT = 0x00;
|
|
||||||
public static final byte STREAM_STATUS_SENT_RESOLVE = 0x01;
|
|
||||||
public static final byte STREAM_STATUS_SUCCEEDED = 0x02;
|
|
||||||
public static final byte STREAM_STATUS_FAILED = 0x03;
|
|
||||||
public static final byte STREAM_STATUS_CLOSED = 0x04;
|
|
||||||
public static final byte STREAM_STATUS_NEW_CONNECT = 0x05;
|
|
||||||
public static final byte STREAM_STATUS_NEW_RESOLVE = 0x06;
|
|
||||||
public static final byte STREAM_STATUS_DETACHED = 0x07;
|
|
||||||
|
|
||||||
public static final String[] STREAM_STATUS_NAMES = {
|
|
||||||
"SENT_CONNECT",
|
|
||||||
"SENT_RESOLVE",
|
|
||||||
"SUCCEEDED",
|
|
||||||
"FAILED",
|
|
||||||
"CLOSED",
|
|
||||||
"NEW_CONNECT",
|
|
||||||
"NEW_RESOLVE",
|
|
||||||
"DETACHED"
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final byte OR_CONN_STATUS_LAUNCHED = 0x00;
|
|
||||||
public static final byte OR_CONN_STATUS_CONNECTED = 0x01;
|
|
||||||
public static final byte OR_CONN_STATUS_FAILED = 0x02;
|
|
||||||
public static final byte OR_CONN_STATUS_CLOSED = 0x03;
|
|
||||||
|
|
||||||
public static final String[] OR_CONN_STATUS_NAMES = {
|
|
||||||
"LAUNCHED","CONNECTED","FAILED","CLOSED"
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final byte SIGNAL_HUP = 0x01;
|
|
||||||
public static final byte SIGNAL_INT = 0x02;
|
|
||||||
public static final byte SIGNAL_USR1 = 0x0A;
|
|
||||||
public static final byte SIGNAL_USR2 = 0x0C;
|
|
||||||
public static final byte SIGNAL_TERM = 0x0F;
|
|
||||||
|
|
||||||
public static final String ERROR_MSGS[] = {
|
|
||||||
"Unspecified error",
|
|
||||||
"Internal error",
|
|
||||||
"Unrecognized message type",
|
|
||||||
"Syntax error",
|
|
||||||
"Unrecognized configuration key",
|
|
||||||
"Invalid configuration value",
|
|
||||||
"Unrecognized byte code",
|
|
||||||
"Unauthorized",
|
|
||||||
"Failed authentication attempt",
|
|
||||||
"Resource exhausted",
|
|
||||||
"No such stream",
|
|
||||||
"No such circuit",
|
|
||||||
"No such OR",
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final String HS_ADDRESS = "onionAddress";
|
|
||||||
public static final String HS_PRIVKEY = "onionPrivKey";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,998 +0,0 @@
|
|||||||
// Copyright 2005 Nick Mathewson, Roger Dingledine
|
|
||||||
// See LICENSE file for copying information
|
|
||||||
package net.freehaven.tor.control;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A connection to a running Tor process as specified in control-spec.txt.
|
|
||||||
*/
|
|
||||||
public class TorControlConnection implements TorControlCommands {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
getLogger(TorControlConnection.class.getName());
|
|
||||||
|
|
||||||
private final LinkedList<Waiter> waiters;
|
|
||||||
private final BufferedReader input;
|
|
||||||
private final Writer output;
|
|
||||||
|
|
||||||
private ControlParseThread thread; // Locking: this
|
|
||||||
|
|
||||||
private volatile EventHandler handler;
|
|
||||||
private volatile PrintWriter debugOutput;
|
|
||||||
private volatile IOException parseThreadException;
|
|
||||||
|
|
||||||
static class Waiter {
|
|
||||||
|
|
||||||
List<ReplyLine> response; // Locking: this
|
|
||||||
boolean interrupted;
|
|
||||||
|
|
||||||
List<ReplyLine> getResponse() throws InterruptedException {
|
|
||||||
LOG.info("Entering synchronized (waiter " + hashCode() + ")");
|
|
||||||
synchronized (this) {
|
|
||||||
LOG.info("Entered synchronized (waiter " + hashCode() + ")");
|
|
||||||
while (response == null) {
|
|
||||||
LOG.info("Waiter " + hashCode() + " waiting for response");
|
|
||||||
wait();
|
|
||||||
if (interrupted) {
|
|
||||||
LOG.info("Waiter " + hashCode() + " interrupted");
|
|
||||||
throw new InterruptedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOG.info("Waiter " + hashCode() + " got response " + response);
|
|
||||||
LOG.info("Leaving synchronized (waiter " + hashCode() + ")");
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setResponse(List<ReplyLine> response) {
|
|
||||||
LOG.info("Entering synchronized (waiter " + hashCode() + ")");
|
|
||||||
synchronized (this) {
|
|
||||||
LOG.info("Entered synchronized (waiter " + hashCode() + ")");
|
|
||||||
LOG.info("Setting response for waiter " + hashCode() + ": "
|
|
||||||
+ response);
|
|
||||||
this.response = response;
|
|
||||||
notifyAll();
|
|
||||||
LOG.info("Leaving synchronized (waiter " + hashCode() + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void interrupt() {
|
|
||||||
LOG.info("Entering synchronized (waiter " + hashCode() + ")");
|
|
||||||
synchronized (this) {
|
|
||||||
LOG.info("Entered synchronized (waiter " + hashCode() + ")");
|
|
||||||
LOG.info("Interrupting waiter " + hashCode());
|
|
||||||
interrupted = true;
|
|
||||||
notifyAll();
|
|
||||||
LOG.info("Leaving synchronized (waiter " + hashCode() + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ReplyLine {
|
|
||||||
|
|
||||||
final String status;
|
|
||||||
final String msg;
|
|
||||||
final String rest;
|
|
||||||
|
|
||||||
ReplyLine(String status, String msg, String rest) {
|
|
||||||
this.status = status;
|
|
||||||
this.msg = msg;
|
|
||||||
this.rest = rest;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return status + " " + msg + " " + rest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new TorControlConnection to communicate with Tor over
|
|
||||||
* a given socket. After calling this constructor, it is typical to
|
|
||||||
* call launchThread and authenticate.
|
|
||||||
*/
|
|
||||||
public TorControlConnection(Socket connection) throws IOException {
|
|
||||||
this(connection.getInputStream(), connection.getOutputStream());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new TorControlConnection to communicate with Tor over
|
|
||||||
* an arbitrary pair of data streams.
|
|
||||||
*/
|
|
||||||
public TorControlConnection(InputStream i, OutputStream o) {
|
|
||||||
this(new InputStreamReader(i), new OutputStreamWriter(o));
|
|
||||||
}
|
|
||||||
|
|
||||||
public TorControlConnection(Reader i, Writer o) {
|
|
||||||
this.output = o;
|
|
||||||
if (i instanceof BufferedReader)
|
|
||||||
this.input = (BufferedReader) i;
|
|
||||||
else
|
|
||||||
this.input = new BufferedReader(i);
|
|
||||||
this.waiters = new LinkedList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final void writeEscaped(String s) throws IOException {
|
|
||||||
StringTokenizer st = new StringTokenizer(s, "\n");
|
|
||||||
while (st.hasMoreTokens()) {
|
|
||||||
String line = st.nextToken();
|
|
||||||
if (line.startsWith("."))
|
|
||||||
line = "." + line;
|
|
||||||
if (line.endsWith("\r"))
|
|
||||||
line += "\n";
|
|
||||||
else
|
|
||||||
line += "\r\n";
|
|
||||||
if (debugOutput != null)
|
|
||||||
debugOutput.print(">> " + line);
|
|
||||||
output.write(line);
|
|
||||||
}
|
|
||||||
output.write(".\r\n");
|
|
||||||
if (debugOutput != null)
|
|
||||||
debugOutput.print(">> .\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static String quote(String s) {
|
|
||||||
StringBuffer sb = new StringBuffer("\"");
|
|
||||||
for (int i = 0; i < s.length(); ++i) {
|
|
||||||
char c = s.charAt(i);
|
|
||||||
switch (c) {
|
|
||||||
case '\r':
|
|
||||||
case '\n':
|
|
||||||
case '\\':
|
|
||||||
case '\"':
|
|
||||||
sb.append('\\');
|
|
||||||
}
|
|
||||||
sb.append(c);
|
|
||||||
}
|
|
||||||
sb.append('\"');
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final ArrayList<ReplyLine> readReply() throws IOException {
|
|
||||||
ArrayList<ReplyLine> reply = new ArrayList<>();
|
|
||||||
char c;
|
|
||||||
do {
|
|
||||||
String line = input.readLine();
|
|
||||||
if (line == null) {
|
|
||||||
// if line is null, the end of the stream has been reached, i.e.
|
|
||||||
// the connection to Tor has been closed!
|
|
||||||
if (reply.isEmpty()) {
|
|
||||||
// nothing received so far, can exit cleanly
|
|
||||||
return reply;
|
|
||||||
}
|
|
||||||
// received half of a reply before the connection broke down
|
|
||||||
throw new TorControlSyntaxError("Connection to Tor " +
|
|
||||||
" broke down while receiving reply!");
|
|
||||||
}
|
|
||||||
if (debugOutput != null)
|
|
||||||
debugOutput.println("<< " + line);
|
|
||||||
if (line.length() < 4)
|
|
||||||
throw new TorControlSyntaxError(
|
|
||||||
"Line (\"" + line + "\") too short");
|
|
||||||
String status = line.substring(0, 3);
|
|
||||||
c = line.charAt(3);
|
|
||||||
String msg = line.substring(4);
|
|
||||||
String rest = null;
|
|
||||||
if (c == '+') {
|
|
||||||
StringBuffer data = new StringBuffer();
|
|
||||||
while (true) {
|
|
||||||
line = input.readLine();
|
|
||||||
if (debugOutput != null)
|
|
||||||
debugOutput.print("<< " + line);
|
|
||||||
if (line.equals("."))
|
|
||||||
break;
|
|
||||||
else if (line.startsWith("."))
|
|
||||||
line = line.substring(1);
|
|
||||||
data.append(line).append('\n');
|
|
||||||
}
|
|
||||||
rest = data.toString();
|
|
||||||
}
|
|
||||||
reply.add(new ReplyLine(status, msg, rest));
|
|
||||||
} while (c != ' ');
|
|
||||||
|
|
||||||
return reply;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<ReplyLine> sendAndWaitForResponse(String s,
|
|
||||||
String rest) throws IOException {
|
|
||||||
LOG.info("Entering synchronized (connection)");
|
|
||||||
synchronized (this) {
|
|
||||||
LOG.info("Entered synchronized (connection)");
|
|
||||||
LOG.info("Sending '" + s + "', '" + rest +
|
|
||||||
"' and waiting for response");
|
|
||||||
if (parseThreadException != null) {
|
|
||||||
LOG.info("Throwing previously caught exception "
|
|
||||||
+ parseThreadException);
|
|
||||||
throw parseThreadException;
|
|
||||||
}
|
|
||||||
checkThread();
|
|
||||||
Waiter w = new Waiter();
|
|
||||||
LOG.info("Created waiter " + w.hashCode());
|
|
||||||
if (debugOutput != null)
|
|
||||||
debugOutput.print(">> " + s);
|
|
||||||
LOG.info("Entering synchronized (waiters)");
|
|
||||||
synchronized (waiters) {
|
|
||||||
LOG.info("Entered synchronized (waiters)");
|
|
||||||
output.write(s);
|
|
||||||
LOG.info("Wrote '" + s + "'");
|
|
||||||
if (rest != null) {
|
|
||||||
writeEscaped(rest);
|
|
||||||
LOG.info("Wrote escaped '" + rest + "'");
|
|
||||||
}
|
|
||||||
output.flush();
|
|
||||||
LOG.info("Flushed output");
|
|
||||||
waiters.addLast(w);
|
|
||||||
LOG.info("Added waiter, " + waiters.size() + " waiting");
|
|
||||||
LOG.info("Leaving synchronized (waiters)");
|
|
||||||
}
|
|
||||||
List<ReplyLine> lst;
|
|
||||||
try {
|
|
||||||
LOG.info("Getting response from waiter " + w.hashCode());
|
|
||||||
lst = w.getResponse();
|
|
||||||
LOG.info("Got response from waiter " + w.hashCode() + ": " +
|
|
||||||
lst);
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
throw new IOException("Interrupted");
|
|
||||||
}
|
|
||||||
for (Iterator<ReplyLine> i = lst.iterator(); i.hasNext(); ) {
|
|
||||||
ReplyLine c = i.next();
|
|
||||||
if (!c.status.startsWith("2"))
|
|
||||||
throw new TorControlError("Error reply: " + c.msg);
|
|
||||||
}
|
|
||||||
LOG.info("Leaving synchronized (connection)");
|
|
||||||
return lst;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper: decode a CMD_EVENT command and dispatch it to our
|
|
||||||
* EventHandler (if any).
|
|
||||||
*/
|
|
||||||
protected void handleEvent(ArrayList<ReplyLine> events) {
|
|
||||||
if (handler == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (Iterator<ReplyLine> i = events.iterator(); i.hasNext(); ) {
|
|
||||||
ReplyLine line = i.next();
|
|
||||||
int idx = line.msg.indexOf(' ');
|
|
||||||
String tp = line.msg.substring(0, idx).toUpperCase();
|
|
||||||
String rest = line.msg.substring(idx + 1);
|
|
||||||
if (tp.equals("CIRC")) {
|
|
||||||
List<String> lst = Bytes.splitStr(null, rest);
|
|
||||||
handler.circuitStatus(lst.get(1),
|
|
||||||
lst.get(0),
|
|
||||||
lst.get(1).equals("LAUNCHED")
|
|
||||||
|| lst.size() < 3 ? ""
|
|
||||||
: lst.get(2));
|
|
||||||
} else if (tp.equals("STREAM")) {
|
|
||||||
List<String> lst = Bytes.splitStr(null, rest);
|
|
||||||
handler.streamStatus(lst.get(1),
|
|
||||||
lst.get(0),
|
|
||||||
lst.get(3));
|
|
||||||
// XXXX circID.
|
|
||||||
} else if (tp.equals("ORCONN")) {
|
|
||||||
List<String> lst = Bytes.splitStr(null, rest);
|
|
||||||
handler.orConnStatus(lst.get(1), lst.get(0));
|
|
||||||
} else if (tp.equals("BW")) {
|
|
||||||
List<String> lst = Bytes.splitStr(null, rest);
|
|
||||||
handler.bandwidthUsed(Integer.parseInt(lst.get(0)),
|
|
||||||
Integer.parseInt(lst.get(1)));
|
|
||||||
} else if (tp.equals("NEWDESC")) {
|
|
||||||
List<String> lst = Bytes.splitStr(null, rest);
|
|
||||||
handler.newDescriptors(lst);
|
|
||||||
} else if (tp.equals("DEBUG") ||
|
|
||||||
tp.equals("INFO") ||
|
|
||||||
tp.equals("NOTICE") ||
|
|
||||||
tp.equals("WARN") ||
|
|
||||||
tp.equals("ERR")) {
|
|
||||||
handler.message(tp, rest);
|
|
||||||
} else {
|
|
||||||
handler.unrecognized(tp, rest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets <b>w</b> as the PrintWriter for debugging output,
|
|
||||||
* which writes out all messages passed between Tor and the controller.
|
|
||||||
* Outgoing messages are preceded by "\>\>" and incoming messages are preceded
|
|
||||||
* by "\<\<"
|
|
||||||
*/
|
|
||||||
public void setDebugging(PrintWriter w) {
|
|
||||||
debugOutput = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets <b>s</b> as the PrintStream for debugging output,
|
|
||||||
* which writes out all messages passed between Tor and the controller.
|
|
||||||
* Outgoing messages are preceded by "\>\>" and incoming messages are preceded
|
|
||||||
* by "\<\<"
|
|
||||||
*/
|
|
||||||
public void setDebugging(PrintStream s) {
|
|
||||||
debugOutput = new PrintWriter(s, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the EventHandler object that will be notified of any
|
|
||||||
* events Tor delivers to this connection. To make Tor send us
|
|
||||||
* events, call setEvents().
|
|
||||||
*/
|
|
||||||
public void setEventHandler(EventHandler handler) {
|
|
||||||
this.handler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a thread to react to Tor's responses in the background.
|
|
||||||
* This is necessary to handle asynchronous events and synchronous
|
|
||||||
* responses that arrive independantly over the same socket.
|
|
||||||
*/
|
|
||||||
public Thread launchThread(boolean daemon) {
|
|
||||||
LOG.info("Entering synchronized (connection)");
|
|
||||||
synchronized (this) {
|
|
||||||
LOG.info("Entered synchronized (connection)");
|
|
||||||
ControlParseThread th = new ControlParseThread();
|
|
||||||
LOG.info("Launching parse thread " + th.hashCode());
|
|
||||||
if (daemon)
|
|
||||||
th.setDaemon(true);
|
|
||||||
th.start();
|
|
||||||
this.thread = th;
|
|
||||||
LOG.info("Leaving synchronized (connection)");
|
|
||||||
return th;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class ControlParseThread extends Thread {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
react();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOG.info("Parse thread " + hashCode()
|
|
||||||
+ " caught exception " + ex);
|
|
||||||
parseThreadException = ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void checkThread() {
|
|
||||||
LOG.info("Entering synchronized (connection)");
|
|
||||||
synchronized (this) {
|
|
||||||
LOG.info("Entered synchronized (connection)");
|
|
||||||
if (thread == null)
|
|
||||||
launchThread(true);
|
|
||||||
LOG.info("Leaving synchronized (connection)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* helper: implement the main background loop.
|
|
||||||
*/
|
|
||||||
protected void react() throws IOException {
|
|
||||||
while (true) {
|
|
||||||
ArrayList<ReplyLine> lst = readReply();
|
|
||||||
LOG.info("Read reply: " + lst);
|
|
||||||
if (lst.isEmpty()) {
|
|
||||||
// interrupted queued waiters, there won't be any response.
|
|
||||||
LOG.info("Entering synchronized (waiters)");
|
|
||||||
synchronized (waiters) {
|
|
||||||
LOG.info("Entered synchronized (waiters)");
|
|
||||||
if (!waiters.isEmpty()) {
|
|
||||||
for (Waiter w : waiters) {
|
|
||||||
LOG.info("Interrupting waiter " + w.hashCode());
|
|
||||||
w.interrupt();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG.info("No waiters");
|
|
||||||
}
|
|
||||||
LOG.info("Leaving synchronized (waiters)");
|
|
||||||
}
|
|
||||||
throw new IOException("Tor is no longer running");
|
|
||||||
}
|
|
||||||
if ((lst.get(0)).status.startsWith("6")) {
|
|
||||||
LOG.info("Reply is an event");
|
|
||||||
handleEvent(lst);
|
|
||||||
} else {
|
|
||||||
LOG.info("Entering synchronized (waiters)");
|
|
||||||
synchronized (waiters) {
|
|
||||||
LOG.info("Entered synchronized (waiters)");
|
|
||||||
if (!waiters.isEmpty()) {
|
|
||||||
Waiter w;
|
|
||||||
w = waiters.removeFirst();
|
|
||||||
LOG.info("Setting response for waiter " + w.hashCode());
|
|
||||||
w.setResponse(lst);
|
|
||||||
} else {
|
|
||||||
LOG.info("No waiters");
|
|
||||||
}
|
|
||||||
LOG.info("Leaving synchronized (waiters)");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the value of the configuration option 'key' to 'val'.
|
|
||||||
*/
|
|
||||||
public void setConf(String key, String value) throws IOException {
|
|
||||||
List<String> lst = new ArrayList<>();
|
|
||||||
lst.add(key + " " + value);
|
|
||||||
setConf(lst);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the values of the configuration options stored in kvMap.
|
|
||||||
*/
|
|
||||||
public void setConf(Map<String, String> kvMap) throws IOException {
|
|
||||||
List<String> lst = new ArrayList<>();
|
|
||||||
for (Iterator<Map.Entry<String, String>> it =
|
|
||||||
kvMap.entrySet().iterator(); it.hasNext(); ) {
|
|
||||||
Map.Entry<String, String> ent = it.next();
|
|
||||||
lst.add(ent.getKey() + " " + ent.getValue() + "\n");
|
|
||||||
}
|
|
||||||
setConf(lst);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the values of the configuration options stored in
|
|
||||||
* <b>kvList</b>. Each list element in <b>kvList</b> is expected to be
|
|
||||||
* String of the format "key value".
|
|
||||||
* <p>
|
|
||||||
* Tor behaves as though it had just read each of the key-value pairs
|
|
||||||
* from its configuration file. Keywords with no corresponding values have
|
|
||||||
* their configuration values reset to their defaults. setConf is
|
|
||||||
* all-or-nothing: if there is an error in any of the configuration settings,
|
|
||||||
* Tor sets none of them.
|
|
||||||
* <p>
|
|
||||||
* When a configuration option takes multiple values, or when multiple
|
|
||||||
* configuration keys form a context-sensitive group (see getConf below), then
|
|
||||||
* setting any of the options in a setConf command is taken to reset all of
|
|
||||||
* the others. For example, if two ORBindAddress values are configured, and a
|
|
||||||
* command arrives containing a single ORBindAddress value, the new
|
|
||||||
* command's value replaces the two old values.
|
|
||||||
* <p>
|
|
||||||
* To remove all settings for a given option entirely (and go back to its
|
|
||||||
* default value), include a String in <b>kvList</b> containing the key and no value.
|
|
||||||
*/
|
|
||||||
public void setConf(Collection<String> kvList) throws IOException {
|
|
||||||
if (kvList.size() == 0)
|
|
||||||
return;
|
|
||||||
StringBuffer b = new StringBuffer("SETCONF");
|
|
||||||
for (Iterator<String> it = kvList.iterator(); it.hasNext(); ) {
|
|
||||||
String kv = it.next();
|
|
||||||
int i = kv.indexOf(' ');
|
|
||||||
if (i == -1)
|
|
||||||
b.append(" ").append(kv);
|
|
||||||
b.append(" ").append(kv.substring(0, i)).append("=")
|
|
||||||
.append(quote(kv.substring(i + 1)));
|
|
||||||
}
|
|
||||||
b.append("\r\n");
|
|
||||||
sendAndWaitForResponse(b.toString(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to reset the values listed in the collection 'keys' to their
|
|
||||||
* default values.
|
|
||||||
**/
|
|
||||||
public void resetConf(Collection<String> keys) throws IOException {
|
|
||||||
if (keys.size() == 0)
|
|
||||||
return;
|
|
||||||
StringBuffer b = new StringBuffer("RESETCONF");
|
|
||||||
for (Iterator<String> it = keys.iterator(); it.hasNext(); ) {
|
|
||||||
String key = it.next();
|
|
||||||
b.append(" ").append(key);
|
|
||||||
}
|
|
||||||
b.append("\r\n");
|
|
||||||
sendAndWaitForResponse(b.toString(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the value of the configuration option 'key'
|
|
||||||
*/
|
|
||||||
public List<ConfigEntry> getConf(String key) throws IOException {
|
|
||||||
List<String> lst = new ArrayList<>();
|
|
||||||
lst.add(key);
|
|
||||||
return getConf(lst);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Requests the values of the configuration variables listed in <b>keys</b>.
|
|
||||||
* Results are returned as a list of ConfigEntry objects.
|
|
||||||
* <p>
|
|
||||||
* If an option appears multiple times in the configuration, all of its
|
|
||||||
* key-value pairs are returned in order.
|
|
||||||
* <p>
|
|
||||||
* Some options are context-sensitive, and depend on other options with
|
|
||||||
* different keywords. These cannot be fetched directly. Currently there
|
|
||||||
* is only one such option: clients should use the "HiddenServiceOptions"
|
|
||||||
* virtual keyword to get all HiddenServiceDir, HiddenServicePort,
|
|
||||||
* HiddenServiceNodes, and HiddenServiceExcludeNodes option settings.
|
|
||||||
*/
|
|
||||||
public List<ConfigEntry> getConf(Collection<String> keys)
|
|
||||||
throws IOException {
|
|
||||||
StringBuffer sb = new StringBuffer("GETCONF");
|
|
||||||
for (Iterator<String> it = keys.iterator(); it.hasNext(); ) {
|
|
||||||
String key = it.next();
|
|
||||||
sb.append(" ").append(key);
|
|
||||||
}
|
|
||||||
sb.append("\r\n");
|
|
||||||
List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null);
|
|
||||||
List<ConfigEntry> result = new ArrayList<>();
|
|
||||||
for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) {
|
|
||||||
String kv = (it.next()).msg;
|
|
||||||
int idx = kv.indexOf('=');
|
|
||||||
if (idx >= 0)
|
|
||||||
result.add(new ConfigEntry(kv.substring(0, idx),
|
|
||||||
kv.substring(idx + 1)));
|
|
||||||
else
|
|
||||||
result.add(new ConfigEntry(kv));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request that the server inform the client about interesting events.
|
|
||||||
* Each element of <b>events</b> is one of the following Strings:
|
|
||||||
* ["CIRC" | "STREAM" | "ORCONN" | "BW" | "DEBUG" |
|
|
||||||
* "INFO" | "NOTICE" | "WARN" | "ERR" | "NEWDESC" | "ADDRMAP"] .
|
|
||||||
* <p>
|
|
||||||
* Any events not listed in the <b>events</b> are turned off; thus, calling
|
|
||||||
* setEvents with an empty <b>events</b> argument turns off all event reporting.
|
|
||||||
*/
|
|
||||||
public void setEvents(List<String> events) throws IOException {
|
|
||||||
StringBuffer sb = new StringBuffer("SETEVENTS");
|
|
||||||
for (Iterator<String> it = events.iterator(); it.hasNext(); ) {
|
|
||||||
sb.append(" ").append(it.next());
|
|
||||||
}
|
|
||||||
sb.append("\r\n");
|
|
||||||
sendAndWaitForResponse(sb.toString(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authenticates the controller to the Tor server.
|
|
||||||
* <p>
|
|
||||||
* By default, the current Tor implementation trusts all local users, and
|
|
||||||
* the controller can authenticate itself by calling authenticate(new byte[0]).
|
|
||||||
* <p>
|
|
||||||
* If the 'CookieAuthentication' option is true, Tor writes a "magic cookie"
|
|
||||||
* file named "control_auth_cookie" into its data directory. To authenticate,
|
|
||||||
* the controller must send the contents of this file in <b>auth</b>.
|
|
||||||
* <p>
|
|
||||||
* If the 'HashedControlPassword' option is set, <b>auth</b> must contain the salted
|
|
||||||
* hash of a secret password. The salted hash is computed according to the
|
|
||||||
* S2K algorithm in RFC 2440 (OpenPGP), and prefixed with the s2k specifier.
|
|
||||||
* This is then encoded in hexadecimal, prefixed by the indicator sequence
|
|
||||||
* "16:".
|
|
||||||
* <p>
|
|
||||||
* You can generate the salt of a password by calling
|
|
||||||
* 'tor --hash-password <password>'
|
|
||||||
* or by using the provided PasswordDigest class.
|
|
||||||
* To authenticate under this scheme, the controller sends Tor the original
|
|
||||||
* secret that was used to generate the password.
|
|
||||||
*/
|
|
||||||
public void authenticate(byte[] auth) throws IOException {
|
|
||||||
String cmd = "AUTHENTICATE " + Bytes.hex(auth) + "\r\n";
|
|
||||||
sendAndWaitForResponse(cmd, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instructs the server to write out its configuration options into its torrc.
|
|
||||||
*/
|
|
||||||
public void saveConf() throws IOException {
|
|
||||||
sendAndWaitForResponse("SAVECONF\r\n", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a signal from the controller to the Tor server.
|
|
||||||
* <b>signal</b> is one of the following Strings:
|
|
||||||
* <ul>
|
|
||||||
* <li>"RELOAD" or "HUP" : Reload config items, refetch directory</li>
|
|
||||||
* <li>"SHUTDOWN" or "INT" : Controlled shutdown: if server is an OP, exit immediately.
|
|
||||||
* If it's an OR, close listeners and exit after 30 seconds</li>
|
|
||||||
* <li>"DUMP" or "USR1" : Dump stats: log information about open connections and circuits</li>
|
|
||||||
* <li>"DEBUG" or "USR2" : Debug: switch all open logs to loglevel debug</li>
|
|
||||||
* <li>"HALT" or "TERM" : Immediate shutdown: clean up and exit now</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public void signal(String signal) throws IOException {
|
|
||||||
String cmd = "SIGNAL " + signal + "\r\n";
|
|
||||||
sendAndWaitForResponse(cmd, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a signal to the Tor process to shut it down or halt it.
|
|
||||||
* Does not wait for a response.
|
|
||||||
*/
|
|
||||||
public void shutdownTor(String signal) throws IOException {
|
|
||||||
String s = "SIGNAL " + signal + "\r\n";
|
|
||||||
Waiter w = new Waiter();
|
|
||||||
if (debugOutput != null)
|
|
||||||
debugOutput.print(">> " + s);
|
|
||||||
LOG.info("Entering synchronized (waiters)");
|
|
||||||
synchronized (waiters) {
|
|
||||||
LOG.info("Entered synchronized (waiters)");
|
|
||||||
output.write(s);
|
|
||||||
output.flush();
|
|
||||||
LOG.info("Leaving synchronized (waiters)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells the Tor server that future SOCKS requests for connections to a set of original
|
|
||||||
* addresses should be replaced with connections to the specified replacement
|
|
||||||
* addresses. Each element of <b>kvLines</b> is a String of the form
|
|
||||||
* "old-address new-address". This function returns the new address mapping.
|
|
||||||
* <p>
|
|
||||||
* The client may decline to provide a body for the original address, and
|
|
||||||
* instead send a special null address ("0.0.0.0" for IPv4, "::0" for IPv6, or
|
|
||||||
* "." for hostname), signifying that the server should choose the original
|
|
||||||
* address itself, and return that address in the reply. The server
|
|
||||||
* should ensure that it returns an element of address space that is unlikely
|
|
||||||
* to be in actual use. If there is already an address mapped to the
|
|
||||||
* destination address, the server may reuse that mapping.
|
|
||||||
* <p>
|
|
||||||
* If the original address is already mapped to a different address, the old
|
|
||||||
* mapping is removed. If the original address and the destination address
|
|
||||||
* are the same, the server removes any mapping in place for the original
|
|
||||||
* address.
|
|
||||||
* <p>
|
|
||||||
* Mappings set by the controller last until the Tor process exits:
|
|
||||||
* they never expire. If the controller wants the mapping to last only
|
|
||||||
* a certain time, then it must explicitly un-map the address when that
|
|
||||||
* time has elapsed.
|
|
||||||
*/
|
|
||||||
public Map<String, String> mapAddresses(Collection<String> kvLines)
|
|
||||||
throws IOException {
|
|
||||||
StringBuffer sb = new StringBuffer("MAPADDRESS");
|
|
||||||
for (Iterator<String> it = kvLines.iterator(); it.hasNext(); ) {
|
|
||||||
String kv = it.next();
|
|
||||||
int i = kv.indexOf(' ');
|
|
||||||
sb.append(" ").append(kv.substring(0, i)).append("=")
|
|
||||||
.append(quote(kv.substring(i + 1)));
|
|
||||||
}
|
|
||||||
sb.append("\r\n");
|
|
||||||
List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null);
|
|
||||||
Map<String, String> result = new HashMap<>();
|
|
||||||
for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) {
|
|
||||||
String kv = (it.next()).msg;
|
|
||||||
int idx = kv.indexOf('=');
|
|
||||||
result.put(kv.substring(0, idx),
|
|
||||||
kv.substring(idx + 1));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> mapAddresses(Map<String, String> addresses)
|
|
||||||
throws IOException {
|
|
||||||
List<String> kvList = new ArrayList<>();
|
|
||||||
for (Iterator<Map.Entry<String, String>> it =
|
|
||||||
addresses.entrySet().iterator(); it.hasNext(); ) {
|
|
||||||
Map.Entry<String, String> e = it.next();
|
|
||||||
kvList.add(e.getKey() + " " + e.getValue());
|
|
||||||
}
|
|
||||||
return mapAddresses(kvList);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String mapAddress(String fromAddr, String toAddr)
|
|
||||||
throws IOException {
|
|
||||||
List<String> lst = new ArrayList<>();
|
|
||||||
lst.add(fromAddr + " " + toAddr + "\n");
|
|
||||||
Map<String, String> m = mapAddresses(lst);
|
|
||||||
return m.get(fromAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queries the Tor server for keyed values that are not stored in the torrc
|
|
||||||
* configuration file. Returns a map of keys to values.
|
|
||||||
* <p>
|
|
||||||
* Recognized keys include:
|
|
||||||
* <ul>
|
|
||||||
* <li>"version" : The version of the server's software, including the name
|
|
||||||
* of the software. (example: "Tor 0.0.9.4")</li>
|
|
||||||
* <li>"desc/id/<OR identity>" or "desc/name/<OR nickname>" : the latest server
|
|
||||||
* descriptor for a given OR, NUL-terminated. If no such OR is known, the
|
|
||||||
* corresponding value is an empty string.</li>
|
|
||||||
* <li>"network-status" : a space-separated list of all known OR identities.
|
|
||||||
* This is in the same format as the router-status line in directories;
|
|
||||||
* see tor-spec.txt for details.</li>
|
|
||||||
* <li>"addr-mappings/all"</li>
|
|
||||||
* <li>"addr-mappings/config"</li>
|
|
||||||
* <li>"addr-mappings/cache"</li>
|
|
||||||
* <li>"addr-mappings/control" : a space-separated list of address mappings, each
|
|
||||||
* in the form of "from-address=to-address". The 'config' key
|
|
||||||
* returns those address mappings set in the configuration; the 'cache'
|
|
||||||
* key returns the mappings in the client-side DNS cache; the 'control'
|
|
||||||
* key returns the mappings set via the control interface; the 'all'
|
|
||||||
* target returns the mappings set through any mechanism.</li>
|
|
||||||
* <li>"circuit-status" : A series of lines as for a circuit status event. Each line is of the form:
|
|
||||||
* "CircuitID CircStatus Path"</li>
|
|
||||||
* <li>"stream-status" : A series of lines as for a stream status event. Each is of the form:
|
|
||||||
* "StreamID StreamStatus CircID Target"</li>
|
|
||||||
* <li>"orconn-status" : A series of lines as for an OR connection status event. Each is of the
|
|
||||||
* form: "ServerID ORStatus"</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public Map<String, String> getInfo(Collection<String> keys)
|
|
||||||
throws IOException {
|
|
||||||
StringBuffer sb = new StringBuffer("GETINFO");
|
|
||||||
for (Iterator<String> it = keys.iterator(); it.hasNext(); ) {
|
|
||||||
sb.append(" ").append(it.next());
|
|
||||||
}
|
|
||||||
sb.append("\r\n");
|
|
||||||
List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null);
|
|
||||||
Map<String, String> m = new HashMap<>();
|
|
||||||
for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) {
|
|
||||||
ReplyLine line = it.next();
|
|
||||||
int idx = line.msg.indexOf('=');
|
|
||||||
if (idx < 0)
|
|
||||||
break;
|
|
||||||
String k = line.msg.substring(0, idx);
|
|
||||||
String v;
|
|
||||||
if (line.rest != null) {
|
|
||||||
v = line.rest;
|
|
||||||
} else {
|
|
||||||
v = line.msg.substring(idx + 1);
|
|
||||||
}
|
|
||||||
m.put(k, v);
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the value of the information field 'key'
|
|
||||||
*/
|
|
||||||
public String getInfo(String key) throws IOException {
|
|
||||||
List<String> lst = new ArrayList<>();
|
|
||||||
lst.add(key);
|
|
||||||
Map<String, String> m = getInfo(lst);
|
|
||||||
return m.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An extendCircuit request takes one of two forms: either the <b>circID</b> is zero, in
|
|
||||||
* which case it is a request for the server to build a new circuit according
|
|
||||||
* to the specified path, or the <b>circID</b> is nonzero, in which case it is a
|
|
||||||
* request for the server to extend an existing circuit with that ID according
|
|
||||||
* to the specified <b>path</b>.
|
|
||||||
* <p>
|
|
||||||
* If successful, returns the Circuit ID of the (maybe newly created) circuit.
|
|
||||||
*/
|
|
||||||
public String extendCircuit(String circID, String path) throws IOException {
|
|
||||||
List<ReplyLine> lst = sendAndWaitForResponse(
|
|
||||||
"EXTENDCIRCUIT " + circID + " " + path + "\r\n", null);
|
|
||||||
return (lst.get(0)).msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Informs the Tor server that the stream specified by <b>streamID</b> should be
|
|
||||||
* associated with the circuit specified by <b>circID</b>.
|
|
||||||
* <p>
|
|
||||||
* Each stream may be associated with
|
|
||||||
* at most one circuit, and multiple streams may share the same circuit.
|
|
||||||
* Streams can only be attached to completed circuits (that is, circuits that
|
|
||||||
* have sent a circuit status "BUILT" event or are listed as built in a
|
|
||||||
* getInfo circuit-status request).
|
|
||||||
* <p>
|
|
||||||
* If <b>circID</b> is 0, responsibility for attaching the given stream is
|
|
||||||
* returned to Tor.
|
|
||||||
* <p>
|
|
||||||
* By default, Tor automatically attaches streams to
|
|
||||||
* circuits itself, unless the configuration variable
|
|
||||||
* "__LeaveStreamsUnattached" is set to "1". Attempting to attach streams
|
|
||||||
* via TC when "__LeaveStreamsUnattached" is false may cause a race between
|
|
||||||
* Tor and the controller, as both attempt to attach streams to circuits.
|
|
||||||
*/
|
|
||||||
public void attachStream(String streamID, String circID)
|
|
||||||
throws IOException {
|
|
||||||
sendAndWaitForResponse(
|
|
||||||
"ATTACHSTREAM " + streamID + " " + circID + "\r\n", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Tor about the server descriptor in <b>desc</b>.
|
|
||||||
* <p>
|
|
||||||
* The descriptor, when parsed, must contain a number of well-specified
|
|
||||||
* fields, including fields for its nickname and identity.
|
|
||||||
*/
|
|
||||||
// More documentation here on format of desc?
|
|
||||||
// No need for return value? control-spec.txt says reply is merely "250 OK" on success...
|
|
||||||
public String postDescriptor(String desc) throws IOException {
|
|
||||||
List<ReplyLine> lst =
|
|
||||||
sendAndWaitForResponse("+POSTDESCRIPTOR\r\n", desc);
|
|
||||||
return (lst.get(0)).msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Tor to change the exit address of the stream identified by <b>streamID</b>
|
|
||||||
* to <b>address</b>. No remapping is performed on the new provided address.
|
|
||||||
* <p>
|
|
||||||
* To be sure that the modified address will be used, this event must be sent
|
|
||||||
* after a new stream event is received, and before attaching this stream to
|
|
||||||
* a circuit.
|
|
||||||
*/
|
|
||||||
public void redirectStream(String streamID, String address)
|
|
||||||
throws IOException {
|
|
||||||
sendAndWaitForResponse(
|
|
||||||
"REDIRECTSTREAM " + streamID + " " + address + "\r\n",
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Tor to close the stream identified by <b>streamID</b>.
|
|
||||||
* <b>reason</b> should be one of the Tor RELAY_END reasons given in tor-spec.txt, as a decimal:
|
|
||||||
* <ul>
|
|
||||||
* <li>1 -- REASON_MISC (catch-all for unlisted reasons)</li>
|
|
||||||
* <li>2 -- REASON_RESOLVEFAILED (couldn't look up hostname)</li>
|
|
||||||
* <li>3 -- REASON_CONNECTREFUSED (remote host refused connection)</li>
|
|
||||||
* <li>4 -- REASON_EXITPOLICY (OR refuses to connect to host or port)</li>
|
|
||||||
* <li>5 -- REASON_DESTROY (Circuit is being destroyed)</li>
|
|
||||||
* <li>6 -- REASON_DONE (Anonymized TCP connection was closed)</li>
|
|
||||||
* <li>7 -- REASON_TIMEOUT (Connection timed out, or OR timed out while connecting)</li>
|
|
||||||
* <li>8 -- (unallocated)</li>
|
|
||||||
* <li>9 -- REASON_HIBERNATING (OR is temporarily hibernating)</li>
|
|
||||||
* <li>10 -- REASON_INTERNAL (Internal error at the OR)</li>
|
|
||||||
* <li>11 -- REASON_RESOURCELIMIT (OR has no resources to fulfill request)</li>
|
|
||||||
* <li>12 -- REASON_CONNRESET (Connection was unexpectedly reset)</li>
|
|
||||||
* <li>13 -- REASON_TORPROTOCOL (Sent when closing connection because of Tor protocol violations)</li>
|
|
||||||
* </ul>
|
|
||||||
* <p>
|
|
||||||
* Tor may hold the stream open for a while to flush any data that is pending.
|
|
||||||
*/
|
|
||||||
public void closeStream(String streamID, byte reason)
|
|
||||||
throws IOException {
|
|
||||||
sendAndWaitForResponse(
|
|
||||||
"CLOSESTREAM " + streamID + " " + reason + "\r\n", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Tor to close the circuit identified by <b>circID</b>.
|
|
||||||
* If <b>ifUnused</b> is true, do not close the circuit unless it is unused.
|
|
||||||
*/
|
|
||||||
public void closeCircuit(String circID, boolean ifUnused)
|
|
||||||
throws IOException {
|
|
||||||
sendAndWaitForResponse("CLOSECIRCUIT " + circID +
|
|
||||||
(ifUnused ? " IFUNUSED" : "") + "\r\n", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Tor to exit when this control connection is closed. This command
|
|
||||||
* was added in Tor 0.2.2.28-beta.
|
|
||||||
*/
|
|
||||||
public void takeOwnership() throws IOException {
|
|
||||||
sendAndWaitForResponse("TAKEOWNERSHIP\r\n", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Tor to generate and set up a new onion service using the best
|
|
||||||
* supported algorithm.
|
|
||||||
* <p/>
|
|
||||||
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
|
||||||
*/
|
|
||||||
public Map<String, String> addOnion(Map<Integer, String> portLines)
|
|
||||||
throws IOException {
|
|
||||||
return addOnion("NEW:BEST", portLines, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Tor to generate and set up a new onion service using the best
|
|
||||||
* supported algorithm.
|
|
||||||
* <p/>
|
|
||||||
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
|
||||||
*/
|
|
||||||
public Map<String, String> addOnion(Map<Integer, String> portLines,
|
|
||||||
boolean ephemeral, boolean detach)
|
|
||||||
throws IOException {
|
|
||||||
return addOnion("NEW:BEST", portLines, ephemeral, detach);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Tor to set up an onion service using the provided private key.
|
|
||||||
* <p/>
|
|
||||||
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
|
||||||
*/
|
|
||||||
public Map<String, String> addOnion(String privKey,
|
|
||||||
Map<Integer, String> portLines)
|
|
||||||
throws IOException {
|
|
||||||
return addOnion(privKey, portLines, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Tor to set up an onion service using the provided private key.
|
|
||||||
* <p/>
|
|
||||||
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
|
||||||
*/
|
|
||||||
public Map<String, String> addOnion(String privKey,
|
|
||||||
Map<Integer, String> portLines,
|
|
||||||
boolean ephemeral, boolean detach)
|
|
||||||
throws IOException {
|
|
||||||
List<String> flags = new ArrayList<>();
|
|
||||||
if (ephemeral)
|
|
||||||
flags.add("DiscardPK");
|
|
||||||
if (detach)
|
|
||||||
flags.add("Detach");
|
|
||||||
return addOnion(privKey, portLines, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Tor to set up an onion service.
|
|
||||||
* <p/>
|
|
||||||
* ADD_ONION was added in Tor 0.2.7.1-alpha.
|
|
||||||
*/
|
|
||||||
public Map<String, String> addOnion(String privKey,
|
|
||||||
Map<Integer, String> portLines,
|
|
||||||
List<String> flags)
|
|
||||||
throws IOException {
|
|
||||||
if (privKey.indexOf(':') < 0)
|
|
||||||
throw new IllegalArgumentException("Invalid privKey");
|
|
||||||
if (portLines == null || portLines.size() < 1)
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Must provide at least one port line");
|
|
||||||
StringBuilder b = new StringBuilder();
|
|
||||||
b.append("ADD_ONION ").append(privKey);
|
|
||||||
if (flags != null && flags.size() > 0) {
|
|
||||||
b.append(" Flags=");
|
|
||||||
String separator = "";
|
|
||||||
for (String flag : flags) {
|
|
||||||
b.append(separator).append(flag);
|
|
||||||
separator = ",";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (Map.Entry<Integer, String> portLine : portLines.entrySet()) {
|
|
||||||
int virtPort = portLine.getKey();
|
|
||||||
String target = portLine.getValue();
|
|
||||||
b.append(" Port=").append(virtPort);
|
|
||||||
if (target != null && target.length() > 0)
|
|
||||||
b.append(",").append(target);
|
|
||||||
}
|
|
||||||
b.append("\r\n");
|
|
||||||
List<ReplyLine> lst = sendAndWaitForResponse(b.toString(), null);
|
|
||||||
Map<String, String> ret = new HashMap<>();
|
|
||||||
ret.put(HS_ADDRESS, (lst.get(0)).msg.split("=", 2)[1]);
|
|
||||||
if (lst.size() > 2)
|
|
||||||
ret.put(HS_PRIVKEY, (lst.get(1)).msg.split("=", 2)[1]);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Tor to take down an onion service previously set up with
|
|
||||||
* addOnion(). The hostname excludes the .onion extension.
|
|
||||||
* <p/>
|
|
||||||
* DEL_ONION was added in Tor 0.2.7.1-alpha.
|
|
||||||
*/
|
|
||||||
public void delOnion(String hostname) throws IOException {
|
|
||||||
sendAndWaitForResponse("DEL_ONION " + hostname + "\r\n", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Tor to forget any cached client state relating to the hidden
|
|
||||||
* service with the given hostname (excluding the .onion extension).
|
|
||||||
*/
|
|
||||||
public void forgetHiddenService(String hostname) throws IOException {
|
|
||||||
sendAndWaitForResponse("HSFORGET " + hostname + "\r\n", null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// Copyright 2005 Nick Mathewson, Roger Dingledine
|
|
||||||
// See LICENSE file for copying information
|
|
||||||
package net.freehaven.tor.control;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An exception raised when Tor tells us about an error.
|
|
||||||
*/
|
|
||||||
public class TorControlError extends IOException {
|
|
||||||
|
|
||||||
static final long serialVersionUID = 3;
|
|
||||||
|
|
||||||
private final int errorType;
|
|
||||||
|
|
||||||
public TorControlError(int type, String s) {
|
|
||||||
super(s);
|
|
||||||
errorType = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TorControlError(String s) {
|
|
||||||
this(-1, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getErrorType() {
|
|
||||||
return errorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getErrorMsg() {
|
|
||||||
try {
|
|
||||||
if (errorType == -1)
|
|
||||||
return null;
|
|
||||||
return TorControlCommands.ERROR_MSGS[errorType];
|
|
||||||
} catch (ArrayIndexOutOfBoundsException ex) {
|
|
||||||
return "Unrecongized error #"+errorType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
// Copyright 2005 Nick Mathewson, Roger Dingledine
|
|
||||||
// See LICENSE file for copying information
|
|
||||||
package net.freehaven.tor.control;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An exception raised when Tor behaves in an unexpected way.
|
|
||||||
*/
|
|
||||||
public class TorControlSyntaxError extends IOException {
|
|
||||||
|
|
||||||
static final long serialVersionUID = 3;
|
|
||||||
|
|
||||||
public TorControlSyntaxError(String s) { super(s); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
*.class
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
// Copyright 2005 Nick Mathewson, Roger Dingledine
|
|
||||||
// See LICENSE file for copying information
|
|
||||||
package net.freehaven.tor.control.examples;
|
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import net.freehaven.tor.control.EventHandler;
|
|
||||||
|
|
||||||
public class DebuggingEventHandler implements EventHandler {
|
|
||||||
|
|
||||||
private final PrintWriter out;
|
|
||||||
|
|
||||||
public DebuggingEventHandler(PrintWriter p) {
|
|
||||||
out = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void circuitStatus(String status, String circID, String path) {
|
|
||||||
out.println("Circuit "+circID+" is now "+status+" (path="+path+")");
|
|
||||||
}
|
|
||||||
public void streamStatus(String status, String streamID, String target) {
|
|
||||||
out.println("Stream "+streamID+" is now "+status+" (target="+target+")");
|
|
||||||
}
|
|
||||||
public void orConnStatus(String status, String orName) {
|
|
||||||
out.println("OR connection to "+orName+" is now "+status);
|
|
||||||
}
|
|
||||||
public void bandwidthUsed(long read, long written) {
|
|
||||||
out.println("Bandwidth usage: "+read+" bytes read; "+
|
|
||||||
written+" bytes written.");
|
|
||||||
}
|
|
||||||
public void newDescriptors(java.util.List<String> orList) {
|
|
||||||
out.println("New descriptors for routers:");
|
|
||||||
for (Iterator<String> i = orList.iterator(); i.hasNext(); )
|
|
||||||
out.println(" "+i.next());
|
|
||||||
}
|
|
||||||
public void message(String type, String msg) {
|
|
||||||
out.println("["+type+"] "+msg.trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unrecognized(String type, String msg) {
|
|
||||||
out.println("unrecognized event ["+type+"] "+msg.trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
// Copyright 2005 Nick Mathewson, Roger Dingledine
|
|
||||||
// See LICENSE file for copying information
|
|
||||||
package net.freehaven.tor.control.examples;
|
|
||||||
|
|
||||||
import net.freehaven.tor.control.*;
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
public class Main implements TorControlCommands {
|
|
||||||
|
|
||||||
public static void main(String args[]) {
|
|
||||||
if (args.length < 1) {
|
|
||||||
System.err.println("No command given.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (args[0].equals("set-config")) {
|
|
||||||
setConfig(args);
|
|
||||||
} else if (args[0].equals("get-config")) {
|
|
||||||
getConfig(args);
|
|
||||||
} else if (args[0].equals("get-info")) {
|
|
||||||
getInfo(args);
|
|
||||||
} else if (args[0].equals("listen")) {
|
|
||||||
listenForEvents(args);
|
|
||||||
} else if (args[0].equals("signal")) {
|
|
||||||
signal(args);
|
|
||||||
} else if (args[0].equals("auth")) {
|
|
||||||
authDemo(args);
|
|
||||||
} else {
|
|
||||||
System.err.println("Unrecognized command: "+args[0]);
|
|
||||||
}
|
|
||||||
} catch (EOFException ex) {
|
|
||||||
System.out.println("Control socket closed by Tor.");
|
|
||||||
} catch (TorControlError ex) {
|
|
||||||
System.err.println("Error from Tor process: "+
|
|
||||||
ex+" ["+ex.getErrorMsg()+"]");
|
|
||||||
} catch (IOException ex) {
|
|
||||||
System.err.println("IO exception when talking to Tor process: "+
|
|
||||||
ex);
|
|
||||||
ex.printStackTrace(System.err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TorControlConnection getConnection(String[] args,
|
|
||||||
boolean daemon) throws IOException {
|
|
||||||
Socket s = new Socket("127.0.0.1", 9100);
|
|
||||||
TorControlConnection conn = new TorControlConnection(s);
|
|
||||||
conn.launchThread(daemon);
|
|
||||||
conn.authenticate(new byte[0]);
|
|
||||||
return conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TorControlConnection getConnection(String[] args)
|
|
||||||
throws IOException {
|
|
||||||
return getConnection(args, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setConfig(String[] args) throws IOException {
|
|
||||||
// Usage: "set-config [-save] key value key value key value"
|
|
||||||
TorControlConnection conn = getConnection(args);
|
|
||||||
ArrayList<String> lst = new ArrayList<String>();
|
|
||||||
int i = 1;
|
|
||||||
boolean save = false;
|
|
||||||
if (args[i].equals("-save")) {
|
|
||||||
save = true;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
for (; i < args.length; i +=2) {
|
|
||||||
lst.add(args[i]+" "+args[i+1]);
|
|
||||||
}
|
|
||||||
conn.setConf(lst);
|
|
||||||
if (save) {
|
|
||||||
conn.saveConf();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void getConfig(String[] args) throws IOException {
|
|
||||||
// Usage: get-config key key key
|
|
||||||
TorControlConnection conn = getConnection(args);
|
|
||||||
List<ConfigEntry> lst = conn.getConf(Arrays.asList(args).subList(1,args.length));
|
|
||||||
for (Iterator<ConfigEntry> i = lst.iterator(); i.hasNext(); ) {
|
|
||||||
ConfigEntry e = i.next();
|
|
||||||
System.out.println("KEY: "+e.key);
|
|
||||||
System.out.println("VAL: "+e.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void getInfo(String[] args) throws IOException {
|
|
||||||
TorControlConnection conn = getConnection(args);
|
|
||||||
Map<String,String> m = conn.getInfo(Arrays.asList(args).subList(1,args.length));
|
|
||||||
for (Iterator<Map.Entry<String, String>> i = m.entrySet().iterator(); i.hasNext(); ) {
|
|
||||||
Map.Entry<String,String> e = i.next();
|
|
||||||
System.out.println("KEY: "+e.getKey());
|
|
||||||
System.out.println("VAL: "+e.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void listenForEvents(String[] args) throws IOException {
|
|
||||||
// Usage: listen [circ|stream|orconn|bw|newdesc|info|notice|warn|error]*
|
|
||||||
TorControlConnection conn = getConnection(args, false);
|
|
||||||
ArrayList<String> lst = new ArrayList<String>();
|
|
||||||
for (int i = 1; i < args.length; ++i) {
|
|
||||||
lst.add(args[i]);
|
|
||||||
}
|
|
||||||
conn.setEventHandler(
|
|
||||||
new DebuggingEventHandler(new PrintWriter(System.out, true)));
|
|
||||||
conn.setEvents(lst);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void signal(String[] args) throws IOException {
|
|
||||||
// Usage signal [reload|shutdown|dump|debug|halt]
|
|
||||||
TorControlConnection conn = getConnection(args, false);
|
|
||||||
// distinguish shutdown signal from other signals
|
|
||||||
if ("SHUTDOWN".equalsIgnoreCase(args[1])
|
|
||||||
|| "HALT".equalsIgnoreCase(args[1])) {
|
|
||||||
conn.shutdownTor(args[1].toUpperCase());
|
|
||||||
} else {
|
|
||||||
conn.signal(args[1].toUpperCase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void authDemo(String[] args) throws IOException {
|
|
||||||
|
|
||||||
PasswordDigest pwd = PasswordDigest.generateDigest();
|
|
||||||
Socket s = new Socket("127.0.0.1", 9100);
|
|
||||||
TorControlConnection conn = new TorControlConnection(s);
|
|
||||||
conn.launchThread(true);
|
|
||||||
conn.authenticate(new byte[0]);
|
|
||||||
|
|
||||||
conn.setConf("HashedControlPassword", pwd.getHashedPassword());
|
|
||||||
|
|
||||||
s = new Socket("127.0.0.1", 9100);
|
|
||||||
conn = new TorControlConnection(s);
|
|
||||||
conn.launchThread(true);
|
|
||||||
conn.authenticate(pwd.getSecret());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -10,6 +10,7 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
|
|
||||||
import static java.util.logging.Level.FINE;
|
import static java.util.logging.Level.FINE;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +43,7 @@ public class PoliteExecutor implements Executor {
|
|||||||
int maxConcurrentTasks) {
|
int maxConcurrentTasks) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.maxConcurrentTasks = maxConcurrentTasks;
|
this.maxConcurrentTasks = maxConcurrentTasks;
|
||||||
log = Logger.getLogger(tag);
|
log = getLogger(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.FINE;
|
import static java.util.logging.Level.FINE;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -22,7 +23,7 @@ public class TimeLoggingExecutor extends ThreadPoolExecutor {
|
|||||||
RejectedExecutionHandler handler) {
|
RejectedExecutionHandler handler) {
|
||||||
super(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue,
|
super(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue,
|
||||||
handler);
|
handler);
|
||||||
log = Logger.getLogger(tag);
|
log = getLogger(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ import org.briarproject.bramble.api.crypto.SecretKey;
|
|||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -19,19 +17,21 @@ import java.io.InputStreamReader;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.util.IoUtils.deleteFileOrDir;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||||
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@NotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
|
||||||
class AccountManagerImpl implements AccountManager {
|
class AccountManagerImpl implements AccountManager {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(AccountManagerImpl.class.getName());
|
getLogger(AccountManagerImpl.class.getName());
|
||||||
|
|
||||||
private static final String DB_KEY_FILENAME = "db.key";
|
private static final String DB_KEY_FILENAME = "db.key";
|
||||||
private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak";
|
private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak";
|
||||||
@@ -68,7 +68,7 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
return databaseKey;
|
return databaseKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: stateChangeLock
|
@GuardedBy("stateChangeLock")
|
||||||
@Nullable
|
@Nullable
|
||||||
protected String loadEncryptedDatabaseKey() {
|
protected String loadEncryptedDatabaseKey() {
|
||||||
String key = readDbKeyFromFile(dbKeyFile);
|
String key = readDbKeyFromFile(dbKeyFile);
|
||||||
@@ -83,7 +83,7 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: stateChangeLock
|
@GuardedBy("stateChangeLock")
|
||||||
@Nullable
|
@Nullable
|
||||||
private String readDbKeyFromFile(File f) {
|
private String readDbKeyFromFile(File f) {
|
||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
@@ -102,8 +102,8 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: stateChangeLock
|
@GuardedBy("stateChangeLock")
|
||||||
protected boolean storeEncryptedDatabaseKey(String hex) {
|
boolean storeEncryptedDatabaseKey(String hex) {
|
||||||
LOG.info("Storing database key in file");
|
LOG.info("Storing database key in file");
|
||||||
// Create the directory if necessary
|
// Create the directory if necessary
|
||||||
if (databaseConfig.getDatabaseKeyDirectory().mkdirs())
|
if (databaseConfig.getDatabaseKeyDirectory().mkdirs())
|
||||||
@@ -140,7 +140,7 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: stateChangeLock
|
@GuardedBy("stateChangeLock")
|
||||||
private void writeDbKeyToFile(String key, File f) throws IOException {
|
private void writeDbKeyToFile(String key, File f) throws IOException {
|
||||||
FileOutputStream out = new FileOutputStream(f);
|
FileOutputStream out = new FileOutputStream(f);
|
||||||
out.write(key.getBytes("UTF-8"));
|
out.write(key.getBytes("UTF-8"));
|
||||||
@@ -170,7 +170,7 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: stateChangeLock
|
@GuardedBy("stateChangeLock")
|
||||||
private boolean encryptAndStoreDatabaseKey(SecretKey key, String password) {
|
private boolean encryptAndStoreDatabaseKey(SecretKey key, String password) {
|
||||||
byte[] plaintext = key.getBytes();
|
byte[] plaintext = key.getBytes();
|
||||||
byte[] ciphertext = crypto.encryptWithPassword(plaintext, password);
|
byte[] ciphertext = crypto.encryptWithPassword(plaintext, password);
|
||||||
@@ -181,8 +181,8 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
public void deleteAccount() {
|
public void deleteAccount() {
|
||||||
synchronized (stateChangeLock) {
|
synchronized (stateChangeLock) {
|
||||||
LOG.info("Deleting account");
|
LOG.info("Deleting account");
|
||||||
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
|
deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
|
||||||
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
|
deleteFileOrDir(databaseConfig.getDatabaseDirectory());
|
||||||
databaseKey = null;
|
databaseKey = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,7 +197,7 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: stateChangeLock
|
@GuardedBy("stateChangeLock")
|
||||||
@Nullable
|
@Nullable
|
||||||
private SecretKey loadAndDecryptDatabaseKey(String password) {
|
private SecretKey loadAndDecryptDatabaseKey(String password) {
|
||||||
String hex = loadEncryptedDatabaseKey();
|
String hex = loadEncryptedDatabaseKey();
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ package org.briarproject.bramble.contact;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.client.ClientHelper;
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
|
import org.briarproject.bramble.api.contact.ContactExchangeListener;
|
||||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactExchangeFailedEvent;
|
|
||||||
import org.briarproject.bramble.api.contact.event.ContactExchangeSucceededEvent;
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||||
@@ -14,7 +13,6 @@ import org.briarproject.bramble.api.data.BdfList;
|
|||||||
import org.briarproject.bramble.api.db.ContactExistsException;
|
import org.briarproject.bramble.api.db.ContactExistsException;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
@@ -45,6 +43,7 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.contact.RecordTypes.CONTACT_INFO;
|
import static org.briarproject.bramble.api.contact.RecordTypes.CONTACT_INFO;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
@@ -56,7 +55,7 @@ import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
|||||||
class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(ContactExchangeTaskImpl.class.getName());
|
getLogger(ContactExchangeTaskImpl.class.getName());
|
||||||
|
|
||||||
private static final String SIGNING_LABEL_EXCHANGE =
|
private static final String SIGNING_LABEL_EXCHANGE =
|
||||||
"org.briarproject.briar.contact/EXCHANGE";
|
"org.briarproject.briar.contact/EXCHANGE";
|
||||||
@@ -65,7 +64,6 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
private final ClientHelper clientHelper;
|
private final ClientHelper clientHelper;
|
||||||
private final RecordReaderFactory recordReaderFactory;
|
private final RecordReaderFactory recordReaderFactory;
|
||||||
private final RecordWriterFactory recordWriterFactory;
|
private final RecordWriterFactory recordWriterFactory;
|
||||||
private final EventBus eventBus;
|
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final ConnectionManager connectionManager;
|
private final ConnectionManager connectionManager;
|
||||||
private final ContactManager contactManager;
|
private final ContactManager contactManager;
|
||||||
@@ -74,6 +72,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
private final StreamReaderFactory streamReaderFactory;
|
private final StreamReaderFactory streamReaderFactory;
|
||||||
private final StreamWriterFactory streamWriterFactory;
|
private final StreamWriterFactory streamWriterFactory;
|
||||||
|
|
||||||
|
private volatile ContactExchangeListener listener;
|
||||||
private volatile LocalAuthor localAuthor;
|
private volatile LocalAuthor localAuthor;
|
||||||
private volatile DuplexTransportConnection conn;
|
private volatile DuplexTransportConnection conn;
|
||||||
private volatile TransportId transportId;
|
private volatile TransportId transportId;
|
||||||
@@ -83,9 +82,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
@Inject
|
@Inject
|
||||||
ContactExchangeTaskImpl(DatabaseComponent db, ClientHelper clientHelper,
|
ContactExchangeTaskImpl(DatabaseComponent db, ClientHelper clientHelper,
|
||||||
RecordReaderFactory recordReaderFactory,
|
RecordReaderFactory recordReaderFactory,
|
||||||
RecordWriterFactory recordWriterFactory, EventBus eventBus,
|
RecordWriterFactory recordWriterFactory, Clock clock,
|
||||||
Clock clock, ConnectionManager connectionManager,
|
ConnectionManager connectionManager, ContactManager contactManager,
|
||||||
ContactManager contactManager,
|
|
||||||
TransportPropertyManager transportPropertyManager,
|
TransportPropertyManager transportPropertyManager,
|
||||||
CryptoComponent crypto, StreamReaderFactory streamReaderFactory,
|
CryptoComponent crypto, StreamReaderFactory streamReaderFactory,
|
||||||
StreamWriterFactory streamWriterFactory) {
|
StreamWriterFactory streamWriterFactory) {
|
||||||
@@ -93,7 +91,6 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
this.clientHelper = clientHelper;
|
this.clientHelper = clientHelper;
|
||||||
this.recordReaderFactory = recordReaderFactory;
|
this.recordReaderFactory = recordReaderFactory;
|
||||||
this.recordWriterFactory = recordWriterFactory;
|
this.recordWriterFactory = recordWriterFactory;
|
||||||
this.eventBus = eventBus;
|
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.connectionManager = connectionManager;
|
this.connectionManager = connectionManager;
|
||||||
this.contactManager = contactManager;
|
this.contactManager = contactManager;
|
||||||
@@ -104,9 +101,11 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startExchange(LocalAuthor localAuthor, SecretKey masterSecret,
|
public void startExchange(ContactExchangeListener listener,
|
||||||
|
LocalAuthor localAuthor, SecretKey masterSecret,
|
||||||
DuplexTransportConnection conn, TransportId transportId,
|
DuplexTransportConnection conn, TransportId transportId,
|
||||||
boolean alice) {
|
boolean alice) {
|
||||||
|
this.listener = listener;
|
||||||
this.localAuthor = localAuthor;
|
this.localAuthor = localAuthor;
|
||||||
this.conn = conn;
|
this.conn = conn;
|
||||||
this.transportId = transportId;
|
this.transportId = transportId;
|
||||||
@@ -125,8 +124,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
out = conn.getWriter().getOutputStream();
|
out = conn.getWriter().getOutputStream();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
|
listener.contactExchangeFailed();
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +135,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
localProperties = transportPropertyManager.getLocalProperties();
|
localProperties = transportPropertyManager.getLocalProperties();
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
listener.contactExchangeFailed();
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -192,13 +191,14 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
streamWriter.sendEndOfStream();
|
streamWriter.sendEndOfStream();
|
||||||
// Skip any remaining records from the incoming stream
|
// Skip any remaining records from the incoming stream
|
||||||
try {
|
try {
|
||||||
|
//noinspection InfiniteLoopStatement
|
||||||
while (true) recordReader.readRecord();
|
while (true) recordReader.readRecord();
|
||||||
} catch (EOFException expected) {
|
} catch (EOFException expected) {
|
||||||
LOG.info("End of stream");
|
LOG.info("End of stream");
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
listener.contactExchangeFailed();
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -206,7 +206,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
// Verify the contact's signature
|
// Verify the contact's signature
|
||||||
if (!verify(remoteInfo.author, remoteNonce, remoteInfo.signature)) {
|
if (!verify(remoteInfo.author, remoteNonce, remoteInfo.signature)) {
|
||||||
LOG.warning("Invalid signature");
|
LOG.warning("Invalid signature");
|
||||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
listener.contactExchangeFailed();
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -223,17 +223,15 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
conn);
|
conn);
|
||||||
// Pseudonym exchange succeeded
|
// Pseudonym exchange succeeded
|
||||||
LOG.info("Pseudonym exchange succeeded");
|
LOG.info("Pseudonym exchange succeeded");
|
||||||
eventBus.broadcast(
|
listener.contactExchangeSucceeded(remoteInfo.author);
|
||||||
new ContactExchangeSucceededEvent(remoteInfo.author));
|
|
||||||
} catch (ContactExistsException e) {
|
} catch (ContactExistsException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
eventBus.broadcast(
|
listener.duplicateContact(remoteInfo.author);
|
||||||
new ContactExchangeFailedEvent(remoteInfo.author));
|
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
listener.contactExchangeFailed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,18 +2,20 @@ package org.briarproject.bramble.crypto;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class AsciiArmour {
|
class AsciiArmour {
|
||||||
|
|
||||||
static String wrap(byte[] b, int lineLength) {
|
static String wrap(byte[] b, int lineLength) {
|
||||||
String wrapped = StringUtils.toHexString(b);
|
String wrapped = toHexString(b);
|
||||||
StringBuilder s = new StringBuilder();
|
StringBuilder s = new StringBuilder();
|
||||||
int length = wrapped.length();
|
int length = wrapped.length();
|
||||||
for (int i = 0; i < length; i += lineLength) {
|
for (int i = 0; i < length; i += lineLength) {
|
||||||
int end = Math.min(i + lineLength, length);
|
int end = Math.min(i + lineLength, length);
|
||||||
s.append(wrapped.substring(i, end));
|
s.append(wrapped, i, end);
|
||||||
s.append("\r\n");
|
s.append("\r\n");
|
||||||
}
|
}
|
||||||
return s.toString();
|
return s.toString();
|
||||||
@@ -21,7 +23,7 @@ class AsciiArmour {
|
|||||||
|
|
||||||
static byte[] unwrap(String s) throws FormatException {
|
static byte[] unwrap(String s) throws FormatException {
|
||||||
try {
|
try {
|
||||||
return StringUtils.fromHexString(s.replaceAll("[^0-9a-fA-F]", ""));
|
return fromHexString(s.replaceAll("[^0-9a-fA-F]", ""));
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import org.briarproject.bramble.api.crypto.PublicKey;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.system.SecureRandomProvider;
|
import org.briarproject.bramble.api.system.SecureRandomProvider;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
import org.spongycastle.crypto.CryptoException;
|
import org.spongycastle.crypto.CryptoException;
|
||||||
import org.spongycastle.crypto.Digest;
|
import org.spongycastle.crypto.Digest;
|
||||||
import org.spongycastle.crypto.digests.Blake2bDigest;
|
import org.spongycastle.crypto.digests.Blake2bDigest;
|
||||||
@@ -30,16 +28,21 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.lang.System.arraycopy;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.readUint32;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint32;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class CryptoComponentImpl implements CryptoComponent {
|
class CryptoComponentImpl implements CryptoComponent {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(CryptoComponentImpl.class.getName());
|
getLogger(CryptoComponentImpl.class.getName());
|
||||||
|
|
||||||
private static final int SIGNATURE_KEY_PAIR_BITS = 256;
|
private static final int SIGNATURE_KEY_PAIR_BITS = 256;
|
||||||
private static final int STORAGE_IV_BYTES = 24; // 196 bits
|
private static final int STORAGE_IV_BYTES = 24; // 196 bits
|
||||||
@@ -188,7 +191,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
PrivateKey ourPriv = ourKeyPair.getPrivate();
|
PrivateKey ourPriv = ourKeyPair.getPrivate();
|
||||||
byte[][] hashInputs = new byte[inputs.length + 1][];
|
byte[][] hashInputs = new byte[inputs.length + 1][];
|
||||||
hashInputs[0] = performRawKeyAgreement(ourPriv, theirPublicKey);
|
hashInputs[0] = performRawKeyAgreement(ourPriv, theirPublicKey);
|
||||||
System.arraycopy(inputs, 0, hashInputs, 1, inputs.length);
|
arraycopy(inputs, 0, hashInputs, 1, inputs.length);
|
||||||
byte[] hash = hash(label, hashInputs);
|
byte[] hash = hash(label, hashInputs);
|
||||||
if (hash.length != SecretKey.LENGTH) throw new IllegalStateException();
|
if (hash.length != SecretKey.LENGTH) throw new IllegalStateException();
|
||||||
return new SecretKey(hash);
|
return new SecretKey(hash);
|
||||||
@@ -216,26 +219,26 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
|
|
||||||
private void updateSignature(Signature signature, String label,
|
private void updateSignature(Signature signature, String label,
|
||||||
byte[] toSign) throws GeneralSecurityException {
|
byte[] toSign) throws GeneralSecurityException {
|
||||||
byte[] labelBytes = StringUtils.toUtf8(label);
|
byte[] labelBytes = toUtf8(label);
|
||||||
byte[] length = new byte[INT_32_BYTES];
|
byte[] length = new byte[INT_32_BYTES];
|
||||||
ByteUtils.writeUint32(labelBytes.length, length, 0);
|
writeUint32(labelBytes.length, length, 0);
|
||||||
signature.update(length);
|
signature.update(length);
|
||||||
signature.update(labelBytes);
|
signature.update(labelBytes);
|
||||||
ByteUtils.writeUint32(toSign.length, length, 0);
|
writeUint32(toSign.length, length, 0);
|
||||||
signature.update(length);
|
signature.update(length);
|
||||||
signature.update(toSign);
|
signature.update(toSign);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] hash(String label, byte[]... inputs) {
|
public byte[] hash(String label, byte[]... inputs) {
|
||||||
byte[] labelBytes = StringUtils.toUtf8(label);
|
byte[] labelBytes = toUtf8(label);
|
||||||
Digest digest = new Blake2bDigest(256);
|
Digest digest = new Blake2bDigest(256);
|
||||||
byte[] length = new byte[INT_32_BYTES];
|
byte[] length = new byte[INT_32_BYTES];
|
||||||
ByteUtils.writeUint32(labelBytes.length, length, 0);
|
writeUint32(labelBytes.length, length, 0);
|
||||||
digest.update(length, 0, length.length);
|
digest.update(length, 0, length.length);
|
||||||
digest.update(labelBytes, 0, labelBytes.length);
|
digest.update(labelBytes, 0, labelBytes.length);
|
||||||
for (byte[] input : inputs) {
|
for (byte[] input : inputs) {
|
||||||
ByteUtils.writeUint32(input.length, length, 0);
|
writeUint32(input.length, length, 0);
|
||||||
digest.update(length, 0, length.length);
|
digest.update(length, 0, length.length);
|
||||||
digest.update(input, 0, input.length);
|
digest.update(input, 0, input.length);
|
||||||
}
|
}
|
||||||
@@ -246,14 +249,14 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] mac(String label, SecretKey macKey, byte[]... inputs) {
|
public byte[] mac(String label, SecretKey macKey, byte[]... inputs) {
|
||||||
byte[] labelBytes = StringUtils.toUtf8(label);
|
byte[] labelBytes = toUtf8(label);
|
||||||
Digest mac = new Blake2bDigest(macKey.getBytes(), 32, null, null);
|
Digest mac = new Blake2bDigest(macKey.getBytes(), 32, null, null);
|
||||||
byte[] length = new byte[INT_32_BYTES];
|
byte[] length = new byte[INT_32_BYTES];
|
||||||
ByteUtils.writeUint32(labelBytes.length, length, 0);
|
writeUint32(labelBytes.length, length, 0);
|
||||||
mac.update(length, 0, length.length);
|
mac.update(length, 0, length.length);
|
||||||
mac.update(labelBytes, 0, labelBytes.length);
|
mac.update(labelBytes, 0, labelBytes.length);
|
||||||
for (byte[] input : inputs) {
|
for (byte[] input : inputs) {
|
||||||
ByteUtils.writeUint32(input.length, length, 0);
|
writeUint32(input.length, length, 0);
|
||||||
mac.update(length, 0, length.length);
|
mac.update(length, 0, length.length);
|
||||||
mac.update(input, 0, input.length);
|
mac.update(input, 0, input.length);
|
||||||
}
|
}
|
||||||
@@ -297,13 +300,13 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
output[outputOff] = PBKDF_FORMAT_SCRYPT;
|
output[outputOff] = PBKDF_FORMAT_SCRYPT;
|
||||||
outputOff++;
|
outputOff++;
|
||||||
// Salt
|
// Salt
|
||||||
System.arraycopy(salt, 0, output, outputOff, salt.length);
|
arraycopy(salt, 0, output, outputOff, salt.length);
|
||||||
outputOff += salt.length;
|
outputOff += salt.length;
|
||||||
// Cost parameter
|
// Cost parameter
|
||||||
ByteUtils.writeUint32(cost, output, outputOff);
|
writeUint32(cost, output, outputOff);
|
||||||
outputOff += INT_32_BYTES;
|
outputOff += INT_32_BYTES;
|
||||||
// IV
|
// IV
|
||||||
System.arraycopy(iv, 0, output, outputOff, iv.length);
|
arraycopy(iv, 0, output, outputOff, iv.length);
|
||||||
outputOff += iv.length;
|
outputOff += iv.length;
|
||||||
// Initialise the cipher and encrypt the plaintext
|
// Initialise the cipher and encrypt the plaintext
|
||||||
try {
|
try {
|
||||||
@@ -333,16 +336,16 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
return null; // Unknown format
|
return null; // Unknown format
|
||||||
// Salt
|
// Salt
|
||||||
byte[] salt = new byte[PBKDF_SALT_BYTES];
|
byte[] salt = new byte[PBKDF_SALT_BYTES];
|
||||||
System.arraycopy(input, inputOff, salt, 0, salt.length);
|
arraycopy(input, inputOff, salt, 0, salt.length);
|
||||||
inputOff += salt.length;
|
inputOff += salt.length;
|
||||||
// Cost parameter
|
// Cost parameter
|
||||||
long cost = ByteUtils.readUint32(input, inputOff);
|
long cost = readUint32(input, inputOff);
|
||||||
inputOff += INT_32_BYTES;
|
inputOff += INT_32_BYTES;
|
||||||
if (cost < 2 || cost > Integer.MAX_VALUE)
|
if (cost < 2 || cost > Integer.MAX_VALUE)
|
||||||
return null; // Invalid cost parameter
|
return null; // Invalid cost parameter
|
||||||
// IV
|
// IV
|
||||||
byte[] iv = new byte[STORAGE_IV_BYTES];
|
byte[] iv = new byte[STORAGE_IV_BYTES];
|
||||||
System.arraycopy(input, inputOff, iv, 0, iv.length);
|
arraycopy(input, inputOff, iv, 0, iv.length);
|
||||||
inputOff += iv.length;
|
inputOff += iv.length;
|
||||||
// Derive the key from the password
|
// Derive the key from the password
|
||||||
SecretKey key = passwordBasedKdf.deriveKey(password, salt, (int) cost);
|
SecretKey key = passwordBasedKdf.deriveKey(password, salt, (int) cost);
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
|
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
|
|
||||||
|
import static java.lang.System.arraycopy;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class Curve25519KeyParser implements KeyParser {
|
class Curve25519KeyParser implements KeyParser {
|
||||||
|
|
||||||
@@ -26,7 +28,7 @@ class Curve25519KeyParser implements KeyParser {
|
|||||||
|
|
||||||
static byte[] clamp(byte[] b) {
|
static byte[] clamp(byte[] b) {
|
||||||
byte[] clamped = new byte[32];
|
byte[] clamped = new byte[32];
|
||||||
System.arraycopy(b, 0, clamped, 0, 32);
|
arraycopy(b, 0, clamped, 0, 32);
|
||||||
clamped[0] &= 248;
|
clamped[0] &= 248;
|
||||||
clamped[31] &= 127;
|
clamped[31] &= 127;
|
||||||
clamped[31] |= 64;
|
clamped[31] |= 64;
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
package org.briarproject.bramble.crypto;
|
package org.briarproject.bramble.crypto;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NONCE_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NONCE_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.readUint16;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint16;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint64;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class FrameEncoder {
|
class FrameEncoder {
|
||||||
@@ -16,7 +18,7 @@ class FrameEncoder {
|
|||||||
if (dest.length < FRAME_NONCE_LENGTH)
|
if (dest.length < FRAME_NONCE_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if (frameNumber < 0) throw new IllegalArgumentException();
|
if (frameNumber < 0) throw new IllegalArgumentException();
|
||||||
ByteUtils.writeUint64(frameNumber, dest, 0);
|
writeUint64(frameNumber, dest, 0);
|
||||||
if (header) dest[0] |= 0x80;
|
if (header) dest[0] |= 0x80;
|
||||||
for (int i = INT_64_BYTES; i < FRAME_NONCE_LENGTH; i++) dest[i] = 0;
|
for (int i = INT_64_BYTES; i < FRAME_NONCE_LENGTH; i++) dest[i] = 0;
|
||||||
}
|
}
|
||||||
@@ -29,8 +31,8 @@ class FrameEncoder {
|
|||||||
if (paddingLength < 0) throw new IllegalArgumentException();
|
if (paddingLength < 0) throw new IllegalArgumentException();
|
||||||
if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH)
|
if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
ByteUtils.writeUint16(payloadLength, dest, 0);
|
writeUint16(payloadLength, dest, 0);
|
||||||
ByteUtils.writeUint16(paddingLength, dest, INT_16_BYTES);
|
writeUint16(paddingLength, dest, INT_16_BYTES);
|
||||||
if (finalFrame) dest[0] |= 0x80;
|
if (finalFrame) dest[0] |= 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,12 +45,12 @@ class FrameEncoder {
|
|||||||
static int getPayloadLength(byte[] header) {
|
static int getPayloadLength(byte[] header) {
|
||||||
if (header.length < FRAME_HEADER_PLAINTEXT_LENGTH)
|
if (header.length < FRAME_HEADER_PLAINTEXT_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
return ByteUtils.readUint16(header, 0) & 0x7FFF;
|
return readUint16(header, 0) & 0x7FFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getPaddingLength(byte[] header) {
|
static int getPaddingLength(byte[] header) {
|
||||||
if (header.length < FRAME_HEADER_PLAINTEXT_LENGTH)
|
if (header.length < FRAME_HEADER_PLAINTEXT_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
return ByteUtils.readUint16(header, INT_16_BYTES);
|
return readUint16(header, INT_16_BYTES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.crypto.SecretKey;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.lang.System.arraycopy;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
||||||
|
|
||||||
class KeyAgreementCryptoImpl implements KeyAgreementCrypto {
|
class KeyAgreementCryptoImpl implements KeyAgreementCrypto {
|
||||||
@@ -24,7 +25,7 @@ class KeyAgreementCryptoImpl implements KeyAgreementCrypto {
|
|||||||
byte[] hash = crypto.hash(COMMIT_LABEL, publicKey.getEncoded());
|
byte[] hash = crypto.hash(COMMIT_LABEL, publicKey.getEncoded());
|
||||||
// The output is the first COMMIT_LENGTH bytes of the hash
|
// The output is the first COMMIT_LENGTH bytes of the hash
|
||||||
byte[] commitment = new byte[COMMIT_LENGTH];
|
byte[] commitment = new byte[COMMIT_LENGTH];
|
||||||
System.arraycopy(hash, 0, commitment, 0, COMMIT_LENGTH);
|
arraycopy(hash, 0, commitment, 0, COMMIT_LENGTH);
|
||||||
return commitment;
|
return commitment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.crypto.KeyParser;
|
|||||||
import org.briarproject.bramble.api.crypto.PrivateKey;
|
import org.briarproject.bramble.api.crypto.PrivateKey;
|
||||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
|
import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
|
||||||
import org.spongycastle.asn1.x9.X9ECParameters;
|
import org.spongycastle.asn1.x9.X9ECParameters;
|
||||||
import org.spongycastle.crypto.AsymmetricCipherKeyPair;
|
import org.spongycastle.crypto.AsymmetricCipherKeyPair;
|
||||||
@@ -45,6 +44,9 @@ import java.util.Scanner;
|
|||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class MessageEncrypter {
|
public class MessageEncrypter {
|
||||||
@@ -157,6 +159,7 @@ public class MessageEncrypter {
|
|||||||
printUsage();
|
printUsage();
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
//noinspection IfCanBeSwitch
|
||||||
if (args[0].equals("generate")) {
|
if (args[0].equals("generate")) {
|
||||||
if (args.length != 3) {
|
if (args.length != 3) {
|
||||||
printUsage();
|
printUsage();
|
||||||
@@ -210,11 +213,11 @@ public class MessageEncrypter {
|
|||||||
MessageEncrypter encrypter = new MessageEncrypter(random);
|
MessageEncrypter encrypter = new MessageEncrypter(random);
|
||||||
KeyPair keyPair = encrypter.generateKeyPair();
|
KeyPair keyPair = encrypter.generateKeyPair();
|
||||||
PrintStream out = new PrintStream(new FileOutputStream(publicKeyFile));
|
PrintStream out = new PrintStream(new FileOutputStream(publicKeyFile));
|
||||||
out.print(StringUtils.toHexString(keyPair.getPublic().getEncoded()));
|
out.print(toHexString(keyPair.getPublic().getEncoded()));
|
||||||
out.flush();
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
out = new PrintStream(new FileOutputStream(privateKeyFile));
|
out = new PrintStream(new FileOutputStream(privateKeyFile));
|
||||||
out.print(StringUtils.toHexString(keyPair.getPrivate().getEncoded()));
|
out.print(toHexString(keyPair.getPrivate().getEncoded()));
|
||||||
out.flush();
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
@@ -223,7 +226,7 @@ public class MessageEncrypter {
|
|||||||
SecureRandom random = new SecureRandom();
|
SecureRandom random = new SecureRandom();
|
||||||
MessageEncrypter encrypter = new MessageEncrypter(random);
|
MessageEncrypter encrypter = new MessageEncrypter(random);
|
||||||
InputStream in = new FileInputStream(publicKeyFile);
|
InputStream in = new FileInputStream(publicKeyFile);
|
||||||
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
byte[] keyBytes = fromHexString(readFully(in).trim());
|
||||||
PublicKey publicKey =
|
PublicKey publicKey =
|
||||||
encrypter.getKeyParser().parsePublicKey(keyBytes);
|
encrypter.getKeyParser().parsePublicKey(keyBytes);
|
||||||
String message = readFully(System.in);
|
String message = readFully(System.in);
|
||||||
@@ -236,7 +239,7 @@ public class MessageEncrypter {
|
|||||||
SecureRandom random = new SecureRandom();
|
SecureRandom random = new SecureRandom();
|
||||||
MessageEncrypter encrypter = new MessageEncrypter(random);
|
MessageEncrypter encrypter = new MessageEncrypter(random);
|
||||||
InputStream in = new FileInputStream(privateKeyFile);
|
InputStream in = new FileInputStream(privateKeyFile);
|
||||||
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
byte[] keyBytes = fromHexString(readFully(in).trim());
|
||||||
PrivateKey privateKey =
|
PrivateKey privateKey =
|
||||||
encrypter.getKeyParser().parsePrivateKey(keyBytes);
|
encrypter.getKeyParser().parsePrivateKey(keyBytes);
|
||||||
byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in));
|
byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in));
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.bramble.crypto;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
import org.spongycastle.crypto.generators.SCrypt;
|
import org.spongycastle.crypto.generators.SCrypt;
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -10,13 +9,14 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||||
|
|
||||||
class ScryptKdf implements PasswordBasedKdf {
|
class ScryptKdf implements PasswordBasedKdf {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG = getLogger(ScryptKdf.class.getName());
|
||||||
Logger.getLogger(ScryptKdf.class.getName());
|
|
||||||
|
|
||||||
private static final int MIN_COST = 256; // Min parameter N
|
private static final int MIN_COST = 256; // Min parameter N
|
||||||
private static final int MAX_COST = 1024 * 1024; // Max parameter N
|
private static final int MAX_COST = 1024 * 1024; // Max parameter N
|
||||||
@@ -53,7 +53,7 @@ class ScryptKdf implements PasswordBasedKdf {
|
|||||||
@Override
|
@Override
|
||||||
public SecretKey deriveKey(String password, byte[] salt, int cost) {
|
public SecretKey deriveKey(String password, byte[] salt, int cost) {
|
||||||
long start = now();
|
long start = now();
|
||||||
byte[] passwordBytes = StringUtils.toUtf8(password);
|
byte[] passwordBytes = toUtf8(password);
|
||||||
SecretKey k = new SecretKey(SCrypt.generate(passwordBytes, salt, cost,
|
SecretKey k = new SecretKey(SCrypt.generate(passwordBytes, salt, cost,
|
||||||
BLOCK_SIZE, PARALLELIZATION, SecretKey.LENGTH));
|
BLOCK_SIZE, PARALLELIZATION, SecretKey.LENGTH));
|
||||||
logDuration(LOG, "Deriving key from password", start);
|
logDuration(LOG, "Deriving key from password", start);
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
import static java.lang.System.arraycopy;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
@@ -28,8 +30,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class Sec1KeyParser implements KeyParser {
|
class Sec1KeyParser implements KeyParser {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG = getLogger(Sec1KeyParser.class.getName());
|
||||||
Logger.getLogger(Sec1KeyParser.class.getName());
|
|
||||||
|
|
||||||
private final ECDomainParameters params;
|
private final ECDomainParameters params;
|
||||||
private final BigInteger modulus;
|
private final BigInteger modulus;
|
||||||
@@ -56,12 +57,12 @@ class Sec1KeyParser implements KeyParser {
|
|||||||
if (encodedKey[0] != 4) throw new GeneralSecurityException();
|
if (encodedKey[0] != 4) throw new GeneralSecurityException();
|
||||||
// The x co-ordinate must be >= 0 and < p
|
// The x co-ordinate must be >= 0 and < p
|
||||||
byte[] xBytes = new byte[bytesPerInt];
|
byte[] xBytes = new byte[bytesPerInt];
|
||||||
System.arraycopy(encodedKey, 1, xBytes, 0, bytesPerInt);
|
arraycopy(encodedKey, 1, xBytes, 0, bytesPerInt);
|
||||||
BigInteger x = new BigInteger(1, xBytes); // Positive signum
|
BigInteger x = new BigInteger(1, xBytes); // Positive signum
|
||||||
if (x.compareTo(modulus) >= 0) throw new GeneralSecurityException();
|
if (x.compareTo(modulus) >= 0) throw new GeneralSecurityException();
|
||||||
// The y co-ordinate must be >= 0 and < p
|
// The y co-ordinate must be >= 0 and < p
|
||||||
byte[] yBytes = new byte[bytesPerInt];
|
byte[] yBytes = new byte[bytesPerInt];
|
||||||
System.arraycopy(encodedKey, 1 + bytesPerInt, yBytes, 0, bytesPerInt);
|
arraycopy(encodedKey, 1 + bytesPerInt, yBytes, 0, bytesPerInt);
|
||||||
BigInteger y = new BigInteger(1, yBytes); // Positive signum
|
BigInteger y = new BigInteger(1, yBytes); // Positive signum
|
||||||
if (y.compareTo(modulus) >= 0) throw new GeneralSecurityException();
|
if (y.compareTo(modulus) >= 0) throw new GeneralSecurityException();
|
||||||
// Verify that y^2 == x^3 + ax + b (mod p)
|
// Verify that y^2 == x^3 + ax + b (mod p)
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package org.briarproject.bramble.crypto;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import static java.lang.System.arraycopy;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class Sec1Utils {
|
class Sec1Utils {
|
||||||
|
|
||||||
@@ -10,10 +12,10 @@ class Sec1Utils {
|
|||||||
if (src.length < destLen) {
|
if (src.length < destLen) {
|
||||||
int padding = destLen - src.length;
|
int padding = destLen - src.length;
|
||||||
for (int i = destOff; i < destOff + padding; i++) dest[i] = 0;
|
for (int i = destOff; i < destOff + padding; i++) dest[i] = 0;
|
||||||
System.arraycopy(src, 0, dest, destOff + padding, src.length);
|
arraycopy(src, 0, dest, destOff + padding, src.length);
|
||||||
} else {
|
} else {
|
||||||
int srcOff = src.length - destLen;
|
int srcOff = src.length - destLen;
|
||||||
System.arraycopy(src, srcOff, dest, destOff, destLen);
|
arraycopy(src, srcOff, dest, destOff, destLen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.FormatException;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.crypto.StreamDecrypter;
|
import org.briarproject.bramble.api.crypto.StreamDecrypter;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -14,6 +13,7 @@ import java.security.GeneralSecurityException;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
|
import static java.lang.System.arraycopy;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NONCE_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NONCE_LENGTH;
|
||||||
@@ -26,6 +26,8 @@ import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_H
|
|||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.readUint16;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.readUint64;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -130,7 +132,7 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
}
|
}
|
||||||
// Extract the nonce
|
// Extract the nonce
|
||||||
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
||||||
System.arraycopy(streamHeaderCiphertext, 0, streamHeaderNonce, 0,
|
arraycopy(streamHeaderCiphertext, 0, streamHeaderNonce, 0,
|
||||||
STREAM_HEADER_NONCE_LENGTH);
|
STREAM_HEADER_NONCE_LENGTH);
|
||||||
// Decrypt and authenticate the stream header
|
// Decrypt and authenticate the stream header
|
||||||
try {
|
try {
|
||||||
@@ -145,17 +147,16 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
// Check the protocol version
|
// Check the protocol version
|
||||||
int receivedProtocolVersion =
|
int receivedProtocolVersion = readUint16(streamHeaderPlaintext, 0);
|
||||||
ByteUtils.readUint16(streamHeaderPlaintext, 0);
|
|
||||||
if (receivedProtocolVersion != PROTOCOL_VERSION)
|
if (receivedProtocolVersion != PROTOCOL_VERSION)
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
// Check the stream number
|
// Check the stream number
|
||||||
long receivedStreamNumber = ByteUtils.readUint64(streamHeaderPlaintext,
|
long receivedStreamNumber = readUint64(streamHeaderPlaintext,
|
||||||
INT_16_BYTES);
|
INT_16_BYTES);
|
||||||
if (receivedStreamNumber != streamNumber) throw new FormatException();
|
if (receivedStreamNumber != streamNumber) throw new FormatException();
|
||||||
// Extract the frame key
|
// Extract the frame key
|
||||||
byte[] frameKeyBytes = new byte[SecretKey.LENGTH];
|
byte[] frameKeyBytes = new byte[SecretKey.LENGTH];
|
||||||
System.arraycopy(streamHeaderPlaintext, INT_16_BYTES + INT_64_BYTES,
|
arraycopy(streamHeaderPlaintext, INT_16_BYTES + INT_64_BYTES,
|
||||||
frameKeyBytes, 0, SecretKey.LENGTH);
|
frameKeyBytes, 0, SecretKey.LENGTH);
|
||||||
frameKey = new SecretKey(frameKeyBytes);
|
frameKey = new SecretKey(frameKeyBytes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.briarproject.bramble.crypto;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.crypto.StreamEncrypter;
|
import org.briarproject.bramble.api.crypto.StreamEncrypter;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@@ -12,6 +11,7 @@ import java.security.GeneralSecurityException;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
|
import static java.lang.System.arraycopy;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NONCE_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NONCE_LENGTH;
|
||||||
@@ -24,6 +24,8 @@ import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_H
|
|||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint16;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint64;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -88,7 +90,7 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
throw new RuntimeException(badCipher);
|
throw new RuntimeException(badCipher);
|
||||||
}
|
}
|
||||||
// Combine the payload and padding
|
// Combine the payload and padding
|
||||||
System.arraycopy(payload, 0, framePlaintext, 0, payloadLength);
|
arraycopy(payload, 0, framePlaintext, 0, payloadLength);
|
||||||
for (int i = 0; i < paddingLength; i++)
|
for (int i = 0; i < paddingLength; i++)
|
||||||
framePlaintext[payloadLength + i] = 0;
|
framePlaintext[payloadLength + i] = 0;
|
||||||
// Encrypt and authenticate the payload and padding
|
// Encrypt and authenticate the payload and padding
|
||||||
@@ -118,13 +120,12 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
private void writeStreamHeader() throws IOException {
|
private void writeStreamHeader() throws IOException {
|
||||||
// The header contains the protocol version, stream number and frame key
|
// The header contains the protocol version, stream number and frame key
|
||||||
byte[] streamHeaderPlaintext = new byte[STREAM_HEADER_PLAINTEXT_LENGTH];
|
byte[] streamHeaderPlaintext = new byte[STREAM_HEADER_PLAINTEXT_LENGTH];
|
||||||
ByteUtils.writeUint16(PROTOCOL_VERSION, streamHeaderPlaintext, 0);
|
writeUint16(PROTOCOL_VERSION, streamHeaderPlaintext, 0);
|
||||||
ByteUtils.writeUint64(streamNumber, streamHeaderPlaintext,
|
writeUint64(streamNumber, streamHeaderPlaintext, INT_16_BYTES);
|
||||||
INT_16_BYTES);
|
arraycopy(frameKey.getBytes(), 0, streamHeaderPlaintext,
|
||||||
System.arraycopy(frameKey.getBytes(), 0, streamHeaderPlaintext,
|
|
||||||
INT_16_BYTES + INT_64_BYTES, SecretKey.LENGTH);
|
INT_16_BYTES + INT_64_BYTES, SecretKey.LENGTH);
|
||||||
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
|
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
|
||||||
System.arraycopy(streamHeaderNonce, 0, streamHeaderCiphertext, 0,
|
arraycopy(streamHeaderNonce, 0, streamHeaderCiphertext, 0,
|
||||||
STREAM_HEADER_NONCE_LENGTH);
|
STREAM_HEADER_NONCE_LENGTH);
|
||||||
// Encrypt and authenticate the stream header key
|
// Encrypt and authenticate the stream header key
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -7,13 +7,12 @@ import org.briarproject.bramble.api.plugin.TransportId;
|
|||||||
import org.briarproject.bramble.api.transport.IncomingKeys;
|
import org.briarproject.bramble.api.transport.IncomingKeys;
|
||||||
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
import org.spongycastle.crypto.Digest;
|
import org.spongycastle.crypto.Digest;
|
||||||
import org.spongycastle.crypto.digests.Blake2bDigest;
|
import org.spongycastle.crypto.digests.Blake2bDigest;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.lang.System.arraycopy;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_HEADER_LABEL;
|
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_HEADER_LABEL;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_TAG_LABEL;
|
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_TAG_LABEL;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_HEADER_LABEL;
|
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_HEADER_LABEL;
|
||||||
@@ -24,6 +23,9 @@ import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
|||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint16;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint64;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||||
|
|
||||||
class TransportCryptoImpl implements TransportCrypto {
|
class TransportCryptoImpl implements TransportCrypto {
|
||||||
|
|
||||||
@@ -91,21 +93,21 @@ class TransportCryptoImpl implements TransportCrypto {
|
|||||||
|
|
||||||
private SecretKey rotateKey(SecretKey k, long rotationPeriod) {
|
private SecretKey rotateKey(SecretKey k, long rotationPeriod) {
|
||||||
byte[] period = new byte[INT_64_BYTES];
|
byte[] period = new byte[INT_64_BYTES];
|
||||||
ByteUtils.writeUint64(rotationPeriod, period, 0);
|
writeUint64(rotationPeriod, period, 0);
|
||||||
return crypto.deriveKey(ROTATE_LABEL, k, period);
|
return crypto.deriveKey(ROTATE_LABEL, k, period);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey deriveTagKey(SecretKey master, TransportId t,
|
private SecretKey deriveTagKey(SecretKey master, TransportId t,
|
||||||
boolean alice) {
|
boolean alice) {
|
||||||
String label = alice ? ALICE_TAG_LABEL : BOB_TAG_LABEL;
|
String label = alice ? ALICE_TAG_LABEL : BOB_TAG_LABEL;
|
||||||
byte[] id = StringUtils.toUtf8(t.getString());
|
byte[] id = toUtf8(t.getString());
|
||||||
return crypto.deriveKey(label, master, id);
|
return crypto.deriveKey(label, master, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey deriveHeaderKey(SecretKey master, TransportId t,
|
private SecretKey deriveHeaderKey(SecretKey master, TransportId t,
|
||||||
boolean alice) {
|
boolean alice) {
|
||||||
String label = alice ? ALICE_HEADER_LABEL : BOB_HEADER_LABEL;
|
String label = alice ? ALICE_HEADER_LABEL : BOB_HEADER_LABEL;
|
||||||
byte[] id = StringUtils.toUtf8(t.getString());
|
byte[] id = toUtf8(t.getString());
|
||||||
return crypto.deriveKey(label, master, id);
|
return crypto.deriveKey(label, master, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,14 +127,14 @@ class TransportCryptoImpl implements TransportCrypto {
|
|||||||
// The input is the protocol version as a 16-bit integer, followed by
|
// The input is the protocol version as a 16-bit integer, followed by
|
||||||
// the stream number as a 64-bit integer
|
// the stream number as a 64-bit integer
|
||||||
byte[] protocolVersionBytes = new byte[INT_16_BYTES];
|
byte[] protocolVersionBytes = new byte[INT_16_BYTES];
|
||||||
ByteUtils.writeUint16(protocolVersion, protocolVersionBytes, 0);
|
writeUint16(protocolVersion, protocolVersionBytes, 0);
|
||||||
prf.update(protocolVersionBytes, 0, protocolVersionBytes.length);
|
prf.update(protocolVersionBytes, 0, protocolVersionBytes.length);
|
||||||
byte[] streamNumberBytes = new byte[INT_64_BYTES];
|
byte[] streamNumberBytes = new byte[INT_64_BYTES];
|
||||||
ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0);
|
writeUint64(streamNumber, streamNumberBytes, 0);
|
||||||
prf.update(streamNumberBytes, 0, streamNumberBytes.length);
|
prf.update(streamNumberBytes, 0, streamNumberBytes.length);
|
||||||
byte[] mac = new byte[macLength];
|
byte[] mac = new byte[macLength];
|
||||||
prf.doFinal(mac, 0);
|
prf.doFinal(mac, 0);
|
||||||
// The output is the first TAG_LENGTH bytes of the MAC
|
// The output is the first TAG_LENGTH bytes of the MAC
|
||||||
System.arraycopy(mac, 0, tag, 0, TAG_LENGTH);
|
arraycopy(mac, 0, tag, 0, TAG_LENGTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ interface Database<T> {
|
|||||||
* bytes. This is based on the minimum of the space available on the device
|
* bytes. This is based on the minimum of the space available on the device
|
||||||
* where the database is stored and the database's configured size.
|
* where the database is stored and the database's configured size.
|
||||||
*/
|
*/
|
||||||
long getFreeSpace() throws DbException;
|
long getFreeSpace();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the group with the given ID.
|
* Returns the group with the given ID.
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ import org.briarproject.bramble.api.transport.TransportKeys;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@@ -72,7 +71,9 @@ import javax.annotation.Nullable;
|
|||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||||
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
|
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
|
||||||
@@ -87,7 +88,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
|
|||||||
class DatabaseComponentImpl<T> implements DatabaseComponent {
|
class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(DatabaseComponentImpl.class.getName());
|
getLogger(DatabaseComponentImpl.class.getName());
|
||||||
|
|
||||||
private final Database<T> db;
|
private final Database<T> db;
|
||||||
private final Class<T> txnClass;
|
private final Class<T> txnClass;
|
||||||
@@ -898,7 +899,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
if (old == INVISIBLE) db.addGroupVisibility(txn, c, g, v == SHARED);
|
if (old == INVISIBLE) db.addGroupVisibility(txn, c, g, v == SHARED);
|
||||||
else if (v == INVISIBLE) db.removeGroupVisibility(txn, c, g);
|
else if (v == INVISIBLE) db.removeGroupVisibility(txn, c, g);
|
||||||
else db.setGroupVisibility(txn, c, g, v == SHARED);
|
else db.setGroupVisibility(txn, c, g, v == SHARED);
|
||||||
List<ContactId> affected = Collections.singletonList(c);
|
List<ContactId> affected = singletonList(c);
|
||||||
transaction.attach(new GroupVisibilityUpdatedEvent(affected));
|
transaction.attach(new GroupVisibilityUpdatedEvent(affected));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import org.briarproject.bramble.api.db.MigrationListener;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
@@ -23,6 +22,7 @@ import javax.inject.Inject;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains all the H2-specific code for the database.
|
* Contains all the H2-specific code for the database.
|
||||||
@@ -107,7 +107,7 @@ class H2Database extends JdbcDatabase {
|
|||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.setProperty("user", "user");
|
props.setProperty("user", "user");
|
||||||
// Separate the file password from the user password with a space
|
// Separate the file password from the user password with a space
|
||||||
String hex = StringUtils.toHexString(key.getBytes());
|
String hex = toHexString(key.getBytes());
|
||||||
props.put("password", hex + " password");
|
props.put("password", hex + " password");
|
||||||
return DriverManager.getConnection(getUrl(), props);
|
return DriverManager.getConnection(getUrl(), props);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import org.briarproject.bramble.api.db.MigrationListener;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
@@ -22,6 +21,7 @@ import javax.inject.Inject;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains all the HSQLDB-specific code for the database.
|
* Contains all the HSQLDB-specific code for the database.
|
||||||
@@ -114,7 +114,7 @@ class HyperSqlDatabase extends JdbcDatabase {
|
|||||||
protected Connection createConnection() throws SQLException {
|
protected Connection createConnection() throws SQLException {
|
||||||
SecretKey key = this.key;
|
SecretKey key = this.key;
|
||||||
if (key == null) throw new IllegalStateException();
|
if (key == null) throw new IllegalStateException();
|
||||||
String hex = StringUtils.toHexString(key.getBytes());
|
String hex = toHexString(key.getBytes());
|
||||||
return DriverManager.getConnection(url + ";crypt_key=" + hex);
|
return DriverManager.getConnection(url + ";crypt_key=" + hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,9 +38,7 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@@ -54,11 +52,17 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
|
|
||||||
|
import static java.lang.System.arraycopy;
|
||||||
import static java.sql.Types.INTEGER;
|
import static java.sql.Types.INTEGER;
|
||||||
import static java.sql.Types.VARCHAR;
|
import static java.sql.Types.VARCHAR;
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.emptyMap;
|
||||||
|
import static java.util.Collections.emptySet;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||||
@@ -309,19 +313,20 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
"CREATE INDEX IF NOT EXISTS statusesByContactIdTimestamp"
|
"CREATE INDEX IF NOT EXISTS statusesByContactIdTimestamp"
|
||||||
+ " ON statuses (contactId, timestamp)";
|
+ " ON statuses (contactId, timestamp)";
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG = getLogger(JdbcDatabase.class.getName());
|
||||||
Logger.getLogger(JdbcDatabase.class.getName());
|
|
||||||
|
|
||||||
// Different database libraries use different names for certain types
|
// Different database libraries use different names for certain types
|
||||||
private final MessageFactory messageFactory;
|
private final MessageFactory messageFactory;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final DatabaseTypes dbTypes;
|
private final DatabaseTypes dbTypes;
|
||||||
|
|
||||||
// Locking: connectionsLock
|
@GuardedBy("connectionsLock")
|
||||||
private final LinkedList<Connection> connections = new LinkedList<>();
|
private final LinkedList<Connection> connections = new LinkedList<>();
|
||||||
|
|
||||||
private int openConnections = 0; // Locking: connectionsLock
|
@GuardedBy("connectionsLock")
|
||||||
private boolean closed = false; // Locking: connectionsLock
|
private int openConnections = 0;
|
||||||
|
@GuardedBy("connectionsLock")
|
||||||
|
private boolean closed = false;
|
||||||
|
|
||||||
protected abstract Connection createConnection() throws SQLException;
|
protected abstract Connection createConnection() throws SQLException;
|
||||||
|
|
||||||
@@ -337,6 +342,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
protected void open(String driverClass, boolean reopen, SecretKey key,
|
protected void open(String driverClass, boolean reopen, SecretKey key,
|
||||||
@Nullable MigrationListener listener) throws DbException {
|
@Nullable MigrationListener listener) throws DbException {
|
||||||
// Load the JDBC driver
|
// Load the JDBC driver
|
||||||
@@ -424,7 +430,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
// Package access for testing
|
// Package access for testing
|
||||||
List<Migration<Connection>> getMigrations() {
|
List<Migration<Connection>> getMigrations() {
|
||||||
return Arrays.asList(
|
return asList(
|
||||||
new Migration38_39(),
|
new Migration38_39(),
|
||||||
new Migration39_40(),
|
new Migration39_40(),
|
||||||
new Migration40_41(dbTypes)
|
new Migration40_41(dbTypes)
|
||||||
@@ -766,7 +772,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
for (Entry<ContactId, Boolean> e : visibility.entrySet()) {
|
for (Entry<ContactId, Boolean> e : visibility.entrySet()) {
|
||||||
ContactId c = e.getKey();
|
ContactId c = e.getKey();
|
||||||
boolean offered = removeOfferedMessage(txn, c, m.getId());
|
boolean offered = removeOfferedMessage(txn, c, m.getId());
|
||||||
boolean seen = offered || (sender != null && c.equals(sender));
|
boolean seen = offered || c.equals(sender);
|
||||||
addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(),
|
addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(),
|
||||||
raw.length, state, e.getValue(), messageShared,
|
raw.length, state, e.getValue(), messageShared,
|
||||||
false, seen);
|
false, seen);
|
||||||
@@ -1536,7 +1542,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
if (raw == null) throw new MessageDeletedException();
|
if (raw == null) throw new MessageDeletedException();
|
||||||
if (raw.length <= MESSAGE_HEADER_LENGTH) throw new AssertionError();
|
if (raw.length <= MESSAGE_HEADER_LENGTH) throw new AssertionError();
|
||||||
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
|
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
|
||||||
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
|
arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
|
||||||
return new Message(m, g, timestamp, body);
|
return new Message(m, g, timestamp, body);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
tryToClose(rs, LOG, WARNING);
|
tryToClose(rs, LOG, WARNING);
|
||||||
@@ -1596,7 +1602,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
if (intersection == null) intersection = ids;
|
if (intersection == null) intersection = ids;
|
||||||
else intersection.retainAll(ids);
|
else intersection.retainAll(ids);
|
||||||
// Return early if there are no matches
|
// Return early if there are no matches
|
||||||
if (intersection.isEmpty()) return Collections.emptySet();
|
if (intersection.isEmpty()) return emptySet();
|
||||||
}
|
}
|
||||||
if (intersection == null) throw new AssertionError();
|
if (intersection == null) throw new AssertionError();
|
||||||
return intersection;
|
return intersection;
|
||||||
@@ -1645,7 +1651,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
GroupId g, Metadata query) throws DbException {
|
GroupId g, Metadata query) throws DbException {
|
||||||
// Retrieve the matching message IDs
|
// Retrieve the matching message IDs
|
||||||
Collection<MessageId> matches = getMessageIds(txn, g, query);
|
Collection<MessageId> matches = getMessageIds(txn, g, query);
|
||||||
if (matches.isEmpty()) return Collections.emptyMap();
|
if (matches.isEmpty()) return emptyMap();
|
||||||
// Retrieve the metadata for each match
|
// Retrieve the metadata for each match
|
||||||
Map<MessageId, Metadata> all = new HashMap<>(matches.size());
|
Map<MessageId, Metadata> all = new HashMap<>(matches.size());
|
||||||
for (MessageId m : matches) all.put(m, getMessageMetadata(txn, m));
|
for (MessageId m : matches) all.put(m, getMessageMetadata(txn, m));
|
||||||
@@ -2395,7 +2401,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
ps.close();
|
ps.close();
|
||||||
}
|
}
|
||||||
if (notRemoved.isEmpty()) return Collections.emptyMap();
|
if (notRemoved.isEmpty()) return emptyMap();
|
||||||
// Update any keys that already exist
|
// Update any keys that already exist
|
||||||
String sql = "UPDATE " + tableName + " SET value = ?"
|
String sql = "UPDATE " + tableName + " SET value = ?"
|
||||||
+ " WHERE " + columnName + " = ? AND metaKey = ?";
|
+ " WHERE " + columnName + " = ? AND metaKey = ?";
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ import java.sql.Statement;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
||||||
|
|
||||||
class Migration38_39 implements Migration<Connection> {
|
class Migration38_39 implements Migration<Connection> {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG = getLogger(Migration38_39.class.getName());
|
||||||
Logger.getLogger(Migration38_39.class.getName());
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getStartVersion() {
|
public int getStartVersion() {
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ import java.sql.Statement;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
||||||
|
|
||||||
class Migration39_40 implements Migration<Connection> {
|
class Migration39_40 implements Migration<Connection> {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG = getLogger(Migration39_40.class.getName());
|
||||||
Logger.getLogger(Migration39_40.class.getName());
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getStartVersion() {
|
public int getStartVersion() {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class Migration40_41 implements Migration<Connection> {
|
|||||||
|
|
||||||
private final DatabaseTypes dbTypes;
|
private final DatabaseTypes dbTypes;
|
||||||
|
|
||||||
public Migration40_41(DatabaseTypes databaseTypes) {
|
Migration40_41(DatabaseTypes databaseTypes) {
|
||||||
this.dbTypes = databaseTypes;
|
this.dbTypes = databaseTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import org.briarproject.bramble.api.identity.AuthorId;
|
|||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -16,6 +14,8 @@ import javax.inject.Inject;
|
|||||||
import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION;
|
import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorId.LABEL;
|
import static org.briarproject.bramble.api.identity.AuthorId.LABEL;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint32;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -58,8 +58,8 @@ class AuthorFactoryImpl implements AuthorFactory {
|
|||||||
|
|
||||||
private AuthorId getId(int formatVersion, String name, byte[] publicKey) {
|
private AuthorId getId(int formatVersion, String name, byte[] publicKey) {
|
||||||
byte[] formatVersionBytes = new byte[INT_32_BYTES];
|
byte[] formatVersionBytes = new byte[INT_32_BYTES];
|
||||||
ByteUtils.writeUint32(formatVersion, formatVersionBytes, 0);
|
writeUint32(formatVersion, formatVersionBytes, 0);
|
||||||
return new AuthorId(crypto.hash(LABEL, formatVersionBytes,
|
return new AuthorId(crypto.hash(LABEL, formatVersionBytes,
|
||||||
StringUtils.toUtf8(name), publicKey));
|
toUtf8(name), publicKey));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import javax.annotation.Nullable;
|
|||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
|
|||||||
class IdentityManagerImpl implements IdentityManager {
|
class IdentityManagerImpl implements IdentityManager {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(IdentityManagerImpl.class.getName());
|
getLogger(IdentityManagerImpl.class.getName());
|
||||||
|
|
||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package org.briarproject.bramble.keyagreement;
|
|||||||
|
|
||||||
class AbortException extends Exception {
|
class AbortException extends Exception {
|
||||||
|
|
||||||
boolean receivedAbort;
|
final boolean receivedAbort;
|
||||||
|
|
||||||
AbortException() {
|
AbortException() {
|
||||||
this(false);
|
this(false);
|
||||||
|
|||||||
@@ -20,13 +20,14 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
class ConnectionChooserImpl implements ConnectionChooser {
|
class ConnectionChooserImpl implements ConnectionChooser {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(ConnectionChooserImpl.class.getName());
|
getLogger(ConnectionChooserImpl.class.getName());
|
||||||
|
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import javax.annotation.Nullable;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.CONNECTION_TIMEOUT;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.CONNECTION_TIMEOUT;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ class KeyAgreementConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(KeyAgreementConnector.class.getName());
|
getLogger(KeyAgreementConnector.class.getName());
|
||||||
|
|
||||||
private final Callbacks callbacks;
|
private final Callbacks callbacks;
|
||||||
private final KeyAgreementCrypto keyAgreementCrypto;
|
private final KeyAgreementCrypto keyAgreementCrypto;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@@ -36,7 +37,7 @@ class KeyAgreementTaskImpl extends Thread implements KeyAgreementTask,
|
|||||||
KeyAgreementProtocol.Callbacks, KeyAgreementConnector.Callbacks {
|
KeyAgreementProtocol.Callbacks, KeyAgreementConnector.Callbacks {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(KeyAgreementTaskImpl.class.getName());
|
getLogger(KeyAgreementTaskImpl.class.getName());
|
||||||
|
|
||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
private final KeyAgreementCrypto keyAgreementCrypto;
|
private final KeyAgreementCrypto keyAgreementCrypto;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.io.OutputStream;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.keyagreement.RecordTypes.ABORT;
|
import static org.briarproject.bramble.api.keyagreement.RecordTypes.ABORT;
|
||||||
import static org.briarproject.bramble.api.keyagreement.RecordTypes.CONFIRM;
|
import static org.briarproject.bramble.api.keyagreement.RecordTypes.CONFIRM;
|
||||||
@@ -29,7 +30,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
|
|||||||
class KeyAgreementTransport {
|
class KeyAgreementTransport {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(KeyAgreementTransport.class.getName());
|
getLogger(KeyAgreementTransport.class.getName());
|
||||||
|
|
||||||
private final KeyAgreementConnection kac;
|
private final KeyAgreementConnection kac;
|
||||||
private final RecordReader reader;
|
private final RecordReader reader;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import javax.inject.Inject;
|
|||||||
import static java.util.logging.Level.FINE;
|
import static java.util.logging.Level.FINE;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.COMPACTING_DATABASE;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.COMPACTING_DATABASE;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
|
||||||
@@ -49,7 +50,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
|
|||||||
class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(LifecycleManagerImpl.class.getName());
|
getLogger(LifecycleManagerImpl.class.getName());
|
||||||
|
|
||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
|
|||||||
@@ -26,13 +26,14 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
class ConnectionManagerImpl implements ConnectionManager {
|
class ConnectionManagerImpl implements ConnectionManager {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(ConnectionManagerImpl.class.getName());
|
getLogger(ConnectionManagerImpl.class.getName());
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final KeyManager keyManager;
|
private final KeyManager keyManager;
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -24,14 +23,16 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class ConnectionRegistryImpl implements ConnectionRegistry {
|
class ConnectionRegistryImpl implements ConnectionRegistry {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(ConnectionRegistryImpl.class.getName());
|
getLogger(ConnectionRegistryImpl.class.getName());
|
||||||
|
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final Lock lock = new ReentrantLock();
|
private final Lock lock = new ReentrantLock();
|
||||||
@@ -103,7 +104,7 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
|||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
Multiset<ContactId> m = connections.get(t);
|
Multiset<ContactId> m = connections.get(t);
|
||||||
if (m == null) return Collections.emptyList();
|
if (m == null) return emptyList();
|
||||||
List<ContactId> ids = new ArrayList<>(m.keySet());
|
List<ContactId> ids = new ArrayList<>(m.keySet());
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(ids.size() + " contacts connected: " + t);
|
LOG.info(ids.size() + " contacts connected: " + t);
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import javax.inject.Inject;
|
|||||||
import static java.util.logging.Level.FINE;
|
import static java.util.logging.Level.FINE;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
@@ -61,7 +62,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
|
|||||||
class PluginManagerImpl implements PluginManager, Service {
|
class PluginManagerImpl implements PluginManager, Service {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(PluginManagerImpl.class.getName());
|
getLogger(PluginManagerImpl.class.getName());
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
|
|||||||
@@ -36,18 +36,20 @@ import java.util.concurrent.locks.Lock;
|
|||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class Poller implements EventListener {
|
class Poller implements EventListener {
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger(Poller.class.getName());
|
private static final Logger LOG = getLogger(Poller.class.getName());
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
@@ -58,7 +60,8 @@ class Poller implements EventListener {
|
|||||||
private final SecureRandom random;
|
private final SecureRandom random;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final Lock lock;
|
private final Lock lock;
|
||||||
private final Map<TransportId, ScheduledPollTask> tasks; // Locking: lock
|
@GuardedBy("lock")
|
||||||
|
private final Map<TransportId, ScheduledPollTask> tasks;
|
||||||
|
|
||||||
Poller(@IoExecutor Executor ioExecutor,
|
Poller(@IoExecutor Executor ioExecutor,
|
||||||
@Scheduler ScheduledExecutorService scheduler,
|
@Scheduler ScheduledExecutorService scheduler,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ interface BluetoothConnectionLimiter {
|
|||||||
* Returns true if a contact connection can be opened. This method does not
|
* Returns true if a contact connection can be opened. This method does not
|
||||||
* need to be called for key agreement connections.
|
* need to be called for key agreement connections.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||||
boolean canOpenContactConnection();
|
boolean canOpenContactConnection();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -20,7 +21,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
|
|||||||
class BluetoothConnectionLimiterImpl implements BluetoothConnectionLimiter {
|
class BluetoothConnectionLimiterImpl implements BluetoothConnectionLimiter {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(BluetoothConnectionLimiterImpl.class.getName());
|
getLogger(BluetoothConnectionLimiterImpl.class.getName());
|
||||||
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
// The following are locking: lock
|
// The following are locking: lock
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import javax.annotation.Nullable;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||||
import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID;
|
import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID;
|
||||||
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_BT_ENABLE;
|
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_BT_ENABLE;
|
||||||
@@ -54,7 +55,7 @@ import static org.briarproject.bramble.util.StringUtils.macToString;
|
|||||||
abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(BluetoothPlugin.class.getName());
|
getLogger(BluetoothPlugin.class.getName());
|
||||||
|
|
||||||
final BluetoothConnectionLimiter connectionLimiter;
|
final BluetoothConnectionLimiter connectionLimiter;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import java.io.IOException;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.plugin.FileConstants.PROP_PATH;
|
import static org.briarproject.bramble.api.plugin.FileConstants.PROP_PATH;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||||
@@ -21,8 +22,7 @@ import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
abstract class FilePlugin implements SimplexPlugin {
|
abstract class FilePlugin implements SimplexPlugin {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG = getLogger(FilePlugin.class.getName());
|
||||||
Logger.getLogger(FilePlugin.class.getName());
|
|
||||||
|
|
||||||
protected final SimplexPluginCallback callback;
|
protected final SimplexPluginCallback callback;
|
||||||
protected final int maxLatency;
|
protected final int maxLatency;
|
||||||
|
|||||||
@@ -8,13 +8,14 @@ import java.io.InputStream;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class FileTransportReader implements TransportConnectionReader {
|
class FileTransportReader implements TransportConnectionReader {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(FileTransportReader.class.getName());
|
getLogger(FileTransportReader.class.getName());
|
||||||
|
|
||||||
private final File file;
|
private final File file;
|
||||||
private final InputStream in;
|
private final InputStream in;
|
||||||
|
|||||||
@@ -8,13 +8,14 @@ import java.io.OutputStream;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class FileTransportWriter implements TransportConnectionWriter {
|
class FileTransportWriter implements TransportConnectionWriter {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(FileTransportWriter.class.getName());
|
getLogger(FileTransportWriter.class.getName());
|
||||||
|
|
||||||
private final File file;
|
private final File file;
|
||||||
private final OutputStream out;
|
private final OutputStream out;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
|||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
@@ -23,26 +22,30 @@ import java.net.Socket;
|
|||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import static java.util.Collections.addAll;
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.sort;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
||||||
import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
|
||||||
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PREF_LAN_IP_PORTS;
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PREF_LAN_IP_PORTS;
|
||||||
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_IP_PORTS;
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_IP_PORTS;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.join;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class LanTcpPlugin extends TcpPlugin {
|
class LanTcpPlugin extends TcpPlugin {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG = getLogger(LanTcpPlugin.class.getName());
|
||||||
Logger.getLogger(LanTcpPlugin.class.getName());
|
|
||||||
|
|
||||||
private static final LanAddressComparator ADDRESS_COMPARATOR =
|
private static final LanAddressComparator ADDRESS_COMPARATOR =
|
||||||
new LanAddressComparator();
|
new LanAddressComparator();
|
||||||
@@ -77,12 +80,13 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
locals.add(new InetSocketAddress(local, 0));
|
locals.add(new InetSocketAddress(local, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(locals, ADDRESS_COMPARATOR);
|
//noinspection Java8ListSort
|
||||||
|
sort(locals, ADDRESS_COMPARATOR);
|
||||||
return locals;
|
return locals;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<InetSocketAddress> parseSocketAddresses(String ipPorts) {
|
private List<InetSocketAddress> parseSocketAddresses(String ipPorts) {
|
||||||
if (StringUtils.isNullOrEmpty(ipPorts)) return Collections.emptyList();
|
if (isNullOrEmpty(ipPorts)) return emptyList();
|
||||||
String[] split = ipPorts.split(SEPARATOR);
|
String[] split = ipPorts.split(SEPARATOR);
|
||||||
List<InetSocketAddress> addresses = new ArrayList<>();
|
List<InetSocketAddress> addresses = new ArrayList<>();
|
||||||
for (String ipPort : split) {
|
for (String ipPort : split) {
|
||||||
@@ -98,24 +102,23 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
// Get the list of recently used addresses
|
// Get the list of recently used addresses
|
||||||
String setting = callback.getSettings().get(PREF_LAN_IP_PORTS);
|
String setting = callback.getSettings().get(PREF_LAN_IP_PORTS);
|
||||||
List<String> recent = new ArrayList<>();
|
List<String> recent = new ArrayList<>();
|
||||||
if (!StringUtils.isNullOrEmpty(setting))
|
if (!isNullOrEmpty(setting)) addAll(recent, setting.split(SEPARATOR));
|
||||||
Collections.addAll(recent, setting.split(SEPARATOR));
|
|
||||||
// Is the address already in the list?
|
// Is the address already in the list?
|
||||||
if (recent.remove(ipPort)) {
|
if (recent.remove(ipPort)) {
|
||||||
// Move the address to the start of the list
|
// Move the address to the start of the list
|
||||||
recent.add(0, ipPort);
|
recent.add(0, ipPort);
|
||||||
setting = StringUtils.join(recent, SEPARATOR);
|
setting = join(recent, SEPARATOR);
|
||||||
} else {
|
} else {
|
||||||
// Add the address to the start of the list
|
// Add the address to the start of the list
|
||||||
recent.add(0, ipPort);
|
recent.add(0, ipPort);
|
||||||
// Drop the least recently used address if the list is full
|
// Drop the least recently used address if the list is full
|
||||||
if (recent.size() > MAX_ADDRESSES)
|
if (recent.size() > MAX_ADDRESSES)
|
||||||
recent = recent.subList(0, MAX_ADDRESSES);
|
recent = recent.subList(0, MAX_ADDRESSES);
|
||||||
setting = StringUtils.join(recent, SEPARATOR);
|
setting = join(recent, SEPARATOR);
|
||||||
// Update the list of addresses shared with contacts
|
// Update the list of addresses shared with contacts
|
||||||
List<String> shared = new ArrayList<>(recent);
|
List<String> shared = new ArrayList<>(recent);
|
||||||
Collections.sort(shared);
|
sort(shared);
|
||||||
String property = StringUtils.join(shared, SEPARATOR);
|
String property = join(shared, SEPARATOR);
|
||||||
TransportProperties properties = new TransportProperties();
|
TransportProperties properties = new TransportProperties();
|
||||||
properties.put(PROP_IP_PORTS, property);
|
properties.put(PROP_IP_PORTS, property);
|
||||||
callback.mergeLocalProperties(properties);
|
callback.mergeLocalProperties(properties);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import javax.xml.parsers.ParserConfigurationException;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubInetAddress;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubInetAddress;
|
||||||
|
|
||||||
@@ -25,8 +26,7 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubInetAddress;
|
|||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
class PortMapperImpl implements PortMapper {
|
class PortMapperImpl implements PortMapper {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG = getLogger(PortMapperImpl.class.getName());
|
||||||
Logger.getLogger(PortMapperImpl.class.getName());
|
|
||||||
|
|
||||||
private final ShutdownManager shutdownManager;
|
private final ShutdownManager shutdownManager;
|
||||||
private final AtomicBoolean started = new AtomicBoolean(false);
|
private final AtomicBoolean started = new AtomicBoolean(false);
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
@@ -41,17 +40,19 @@ import static java.util.Collections.emptyList;
|
|||||||
import static java.util.Collections.list;
|
import static java.util.Collections.list;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
abstract class TcpPlugin implements DuplexPlugin {
|
abstract class TcpPlugin implements DuplexPlugin {
|
||||||
|
|
||||||
|
private static final Logger LOG = getLogger(TcpPlugin.class.getName());
|
||||||
|
|
||||||
private static final Pattern DOTTED_QUAD =
|
private static final Pattern DOTTED_QUAD =
|
||||||
Pattern.compile("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$");
|
Pattern.compile("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$");
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(TcpPlugin.class.getName());
|
|
||||||
|
|
||||||
protected final Executor ioExecutor, bindExecutor;
|
protected final Executor ioExecutor, bindExecutor;
|
||||||
protected final Backoff backoff;
|
protected final Backoff backoff;
|
||||||
@@ -84,6 +85,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
/**
|
/**
|
||||||
* Returns true if connections to the given address can be attempted.
|
* Returns true if connections to the given address can be attempted.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||||
protected abstract boolean isConnectable(InetSocketAddress remote);
|
protected abstract boolean isConnectable(InetSocketAddress remote);
|
||||||
|
|
||||||
TcpPlugin(Executor ioExecutor, Backoff backoff,
|
TcpPlugin(Executor ioExecutor, Backoff backoff,
|
||||||
@@ -263,7 +265,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
InetSocketAddress parseSocketAddress(String ipPort) {
|
InetSocketAddress parseSocketAddress(String ipPort) {
|
||||||
if (StringUtils.isNullOrEmpty(ipPort)) return null;
|
if (isNullOrEmpty(ipPort)) return null;
|
||||||
String[] split = ipPort.split(":");
|
String[] split = ipPort.split(":");
|
||||||
if (split.length != 2) return null;
|
if (split.length != 2) return null;
|
||||||
String addr = split[0], port = split[1];
|
String addr = split[0], port = split[1];
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ import org.briarproject.bramble.api.properties.TransportProperties;
|
|||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
import static org.briarproject.bramble.api.plugin.WanTcpConstants.ID;
|
import static org.briarproject.bramble.api.plugin.WanTcpConstants.ID;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@@ -80,8 +81,7 @@ class WanTcpPlugin extends TcpPlugin {
|
|||||||
protected List<InetSocketAddress> getRemoteSocketAddresses(
|
protected List<InetSocketAddress> getRemoteSocketAddresses(
|
||||||
TransportProperties p) {
|
TransportProperties p) {
|
||||||
InetSocketAddress parsed = parseSocketAddress(p.get(PROP_IP_PORT));
|
InetSocketAddress parsed = parseSocketAddress(p.get(PROP_IP_PORT));
|
||||||
if (parsed == null) return Collections.emptyList();
|
return parsed == null ? emptyList() : singletonList(parsed);
|
||||||
return Collections.singletonList(parsed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -17,24 +17,16 @@ public interface CircumventionProvider {
|
|||||||
String[] BLOCKED = {"CN", "IR", "EG", "BY", "TR", "SY", "VE"};
|
String[] BLOCKED = {"CN", "IR", "EG", "BY", "TR", "SY", "VE"};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Countries where obfs4 bridge connection are likely to work.
|
* Countries where vanilla bridge connection are likely to work.
|
||||||
* Should be a subset of {@link #BLOCKED}.
|
* Should be a subset of {@link #BLOCKED}.
|
||||||
*/
|
*/
|
||||||
String[] BRIDGES = { "CN", "IR", "EG", "BY", "TR", "SY", "VE" };
|
String[] BRIDGES = { "EG", "BY", "TR", "SY", "VE" };
|
||||||
|
|
||||||
/**
|
|
||||||
* Countries where obfs4 bridges won't work and meek is needed.
|
|
||||||
* Should be a subset of {@link #BRIDGES}.
|
|
||||||
*/
|
|
||||||
String[] NEEDS_MEEK = {"CN", "IR"};
|
|
||||||
|
|
||||||
boolean isTorProbablyBlocked(String countryCode);
|
boolean isTorProbablyBlocked(String countryCode);
|
||||||
|
|
||||||
boolean doBridgesWork(String countryCode);
|
boolean doBridgesWork(String countryCode);
|
||||||
|
|
||||||
boolean needsMeek(String countryCode);
|
|
||||||
|
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
List<String> getBridges(boolean meek);
|
List<String> getBridges();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ class CircumventionProviderImpl implements CircumventionProvider {
|
|||||||
new HashSet<>(asList(BLOCKED));
|
new HashSet<>(asList(BLOCKED));
|
||||||
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
|
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
|
||||||
new HashSet<>(asList(BRIDGES));
|
new HashSet<>(asList(BRIDGES));
|
||||||
private static final Set<String> BRIDGES_NEED_MEEK =
|
|
||||||
new HashSet<>(asList(NEEDS_MEEK));
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private volatile List<String> bridges = null;
|
private volatile List<String> bridges = null;
|
||||||
@@ -42,14 +40,9 @@ class CircumventionProviderImpl implements CircumventionProvider {
|
|||||||
return BRIDGES_WORK_IN_COUNTRIES.contains(countryCode);
|
return BRIDGES_WORK_IN_COUNTRIES.contains(countryCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean needsMeek(String countryCode) {
|
|
||||||
return BRIDGES_NEED_MEEK.contains(countryCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
public List<String> getBridges(boolean useMeek) {
|
public List<String> getBridges() {
|
||||||
List<String> bridges = this.bridges;
|
List<String> bridges = this.bridges;
|
||||||
if (bridges != null) return new ArrayList<>(bridges);
|
if (bridges != null) return new ArrayList<>(bridges);
|
||||||
|
|
||||||
@@ -60,8 +53,6 @@ class CircumventionProviderImpl implements CircumventionProvider {
|
|||||||
bridges = new ArrayList<>();
|
bridges = new ArrayList<>();
|
||||||
while (scanner.hasNextLine()) {
|
while (scanner.hasNextLine()) {
|
||||||
String line = scanner.nextLine();
|
String line = scanner.nextLine();
|
||||||
boolean isMeekBridge = line.startsWith("Bridge meek");
|
|
||||||
if (useMeek && !isMeekBridge || !useMeek && isMeekBridge) continue;
|
|
||||||
if (!line.startsWith("#")) bridges.add(line);
|
if (!line.startsWith("#")) bridges.add(line);
|
||||||
}
|
}
|
||||||
scanner.close();
|
scanner.close();
|
||||||
|
|||||||
@@ -38,15 +38,11 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@@ -60,8 +56,12 @@ import java.util.zip.ZipInputStream;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
|
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
|
||||||
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
|
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
|
import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
|
||||||
@@ -75,6 +75,7 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_ONLY_WHE
|
|||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V2;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V2;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V3;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V3;
|
||||||
|
import static org.briarproject.bramble.util.IoUtils.copyAndClose;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
|
||||||
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||||
@@ -83,8 +84,7 @@ import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
|||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG = getLogger(TorPlugin.class.getName());
|
||||||
Logger.getLogger(TorPlugin.class.getName());
|
|
||||||
|
|
||||||
private static final String[] EVENTS = {
|
private static final String[] EVENTS = {
|
||||||
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
|
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
|
||||||
@@ -108,7 +108,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private final ResourceProvider resourceProvider;
|
private final ResourceProvider resourceProvider;
|
||||||
private final int maxLatency, maxIdleTime, socketTimeout;
|
private final int maxLatency, maxIdleTime, socketTimeout;
|
||||||
private final File torDirectory, torFile, geoIpFile, obfs4File, configFile;
|
private final File torDirectory, torFile, geoIpFile, obfs4File, configFile;
|
||||||
private final File doneFile, cookieFile, jtorCTLFile;
|
private final File doneFile, cookieFile;
|
||||||
private final ConnectionStatus connectionStatus;
|
private final ConnectionStatus connectionStatus;
|
||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
@@ -153,7 +153,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
configFile = new File(torDirectory, "torrc");
|
configFile = new File(torDirectory, "torrc");
|
||||||
doneFile = new File(torDirectory, "done");
|
doneFile = new File(torDirectory, "done");
|
||||||
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
|
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
|
||||||
jtorCTLFile = new File(torDirectory, "jtorctl.out");
|
|
||||||
connectionStatus = new ConnectionStatus();
|
connectionStatus = new ConnectionStatus();
|
||||||
// Don't execute more than one connection status check at a time
|
// Don't execute more than one connection status check at a time
|
||||||
connectionStatusExecutor =
|
connectionStatusExecutor =
|
||||||
@@ -208,19 +207,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
} catch (SecurityException | IOException e) {
|
} catch (SecurityException | IOException e) {
|
||||||
throw new PluginException(e);
|
throw new PluginException(e);
|
||||||
}
|
}
|
||||||
// FIXME
|
|
||||||
long torPid = getPid(torProcess);
|
|
||||||
LOG.info("Tor PID: " + torPid);
|
|
||||||
/*
|
|
||||||
pb = new ProcessBuilder("/usr/bin/strace", "-ff", "-o", "strace.out",
|
|
||||||
"-p", String.valueOf(torPid));
|
|
||||||
try {
|
|
||||||
pb.start();
|
|
||||||
LOG.info("Started strace");
|
|
||||||
} catch (SecurityException | IOException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// Log the process's standard output until it detaches
|
// Log the process's standard output until it detaches
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
Scanner stdout = new Scanner(torProcess.getInputStream());
|
Scanner stdout = new Scanner(torProcess.getInputStream());
|
||||||
@@ -265,18 +251,13 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
controlSocket = new Socket("127.0.0.1", CONTROL_PORT);
|
controlSocket = new Socket("127.0.0.1", CONTROL_PORT);
|
||||||
controlConnection = new TorControlConnection(controlSocket);
|
controlConnection = new TorControlConnection(controlSocket);
|
||||||
controlConnection.authenticate(read(cookieFile));
|
controlConnection.authenticate(read(cookieFile));
|
||||||
controlConnection.setConf("LOG", "debug file torlog");
|
|
||||||
controlConnection.setDebugging(
|
|
||||||
new PrintWriter(new FileOutputStream(jtorCTLFile), true));
|
|
||||||
// FIXME Spam the control port with enable/disable network commands
|
|
||||||
spamControlPort();
|
|
||||||
// Tell Tor to exit when the control connection is closed
|
// Tell Tor to exit when the control connection is closed
|
||||||
controlConnection.takeOwnership();
|
controlConnection.takeOwnership();
|
||||||
controlConnection.resetConf(Collections.singletonList(OWNER));
|
controlConnection.resetConf(singletonList(OWNER));
|
||||||
running = true;
|
running = true;
|
||||||
// Register to receive events from the Tor process
|
// Register to receive events from the Tor process
|
||||||
controlConnection.setEventHandler(this);
|
controlConnection.setEventHandler(this);
|
||||||
controlConnection.setEvents(Arrays.asList(EVENTS));
|
controlConnection.setEvents(asList(EVENTS));
|
||||||
// Check whether Tor has already bootstrapped
|
// Check whether Tor has already bootstrapped
|
||||||
String phase = controlConnection.getInfo("status/bootstrap-phase");
|
String phase = controlConnection.getInfo("status/bootstrap-phase");
|
||||||
if (phase != null && phase.contains("PROGRESS=100")) {
|
if (phase != null && phase.contains("PROGRESS=100")) {
|
||||||
@@ -293,38 +274,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
bind();
|
bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME
|
|
||||||
private long getPid(Process p) {
|
|
||||||
long pid = -1;
|
|
||||||
try {
|
|
||||||
if (p.getClass().getName().equals("java.lang.UNIXProcess")) {
|
|
||||||
Field f = p.getClass().getDeclaredField("pid");
|
|
||||||
f.setAccessible(true);
|
|
||||||
pid = f.getLong(p);
|
|
||||||
f.setAccessible(false);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logException(LOG, INFO, e);
|
|
||||||
}
|
|
||||||
return pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
private void spamControlPort() {
|
|
||||||
ioExecutor.execute(() -> {
|
|
||||||
LOG.info("Spamming control port");
|
|
||||||
try {
|
|
||||||
//noinspection InfiniteLoopStatement
|
|
||||||
for (boolean bridges = true; ; bridges = !bridges) {
|
|
||||||
LOG.info("Enable bridges " + bridges);
|
|
||||||
enableBridges(bridges, false);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean assetsAreUpToDate() {
|
private boolean assetsAreUpToDate() {
|
||||||
return doneFile.lastModified() > getLastUpdateTime();
|
return doneFile.lastModified() > getLastUpdateTime();
|
||||||
}
|
}
|
||||||
@@ -333,28 +282,31 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
OutputStream out = null;
|
OutputStream out = null;
|
||||||
try {
|
try {
|
||||||
|
// The done file may already exist from a previous installation
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
doneFile.delete();
|
doneFile.delete();
|
||||||
// Unzip the Tor binary to the filesystem
|
// Unzip the Tor binary to the filesystem
|
||||||
in = getTorInputStream();
|
in = getTorInputStream();
|
||||||
out = new FileOutputStream(torFile);
|
out = new FileOutputStream(torFile);
|
||||||
IoUtils.copyAndClose(in, out);
|
copyAndClose(in, out);
|
||||||
// Make the Tor binary executable
|
// Make the Tor binary executable
|
||||||
if (!torFile.setExecutable(true, true)) throw new IOException();
|
if (!torFile.setExecutable(true, true)) throw new IOException();
|
||||||
// Unzip the GeoIP database to the filesystem
|
// Unzip the GeoIP database to the filesystem
|
||||||
in = getGeoIpInputStream();
|
in = getGeoIpInputStream();
|
||||||
out = new FileOutputStream(geoIpFile);
|
out = new FileOutputStream(geoIpFile);
|
||||||
IoUtils.copyAndClose(in, out);
|
copyAndClose(in, out);
|
||||||
// Unzip the Obfs4 proxy to the filesystem
|
// Unzip the Obfs4 proxy to the filesystem
|
||||||
in = getObfs4InputStream();
|
in = getObfs4InputStream();
|
||||||
out = new FileOutputStream(obfs4File);
|
out = new FileOutputStream(obfs4File);
|
||||||
IoUtils.copyAndClose(in, out);
|
copyAndClose(in, out);
|
||||||
// Make the Obfs4 proxy executable
|
// Make the Obfs4 proxy executable
|
||||||
if (!obfs4File.setExecutable(true, true)) throw new IOException();
|
if (!obfs4File.setExecutable(true, true)) throw new IOException();
|
||||||
// Copy the config file to the filesystem
|
// Copy the config file to the filesystem
|
||||||
in = getConfigInputStream();
|
in = getConfigInputStream();
|
||||||
out = new FileOutputStream(configFile);
|
out = new FileOutputStream(configFile);
|
||||||
IoUtils.copyAndClose(in, out);
|
copyAndClose(in, out);
|
||||||
doneFile.createNewFile();
|
if (!doneFile.createNewFile())
|
||||||
|
LOG.warning("Failed to create done file");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
IoUtils.tryToClose(in, LOG, WARNING);
|
IoUtils.tryToClose(in, LOG, WARNING);
|
||||||
IoUtils.tryToClose(out, LOG, WARNING);
|
IoUtils.tryToClose(out, LOG, WARNING);
|
||||||
@@ -463,8 +415,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (!running) return;
|
if (!running) return;
|
||||||
LOG.info("Creating hidden service");
|
LOG.info("Creating hidden service");
|
||||||
String privKey = settings.get(HS_PRIVKEY);
|
String privKey = settings.get(HS_PRIVKEY);
|
||||||
Map<Integer, String> portLines =
|
Map<Integer, String> portLines = singletonMap(80, "127.0.0.1:" + port);
|
||||||
Collections.singletonMap(80, "127.0.0.1:" + port);
|
|
||||||
Map<String, String> response;
|
Map<String, String> response;
|
||||||
try {
|
try {
|
||||||
// Use the control connection to set up the hidden service
|
// Use the control connection to set up the hidden service
|
||||||
@@ -523,19 +474,13 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (!enable) callback.transportDisabled();
|
if (!enable) callback.transportDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableBridges(boolean enable, boolean needsMeek)
|
private void enableBridges(boolean enable) throws IOException {
|
||||||
throws IOException {
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
Collection<String> conf = new ArrayList<>();
|
Collection<String> conf = new ArrayList<>();
|
||||||
conf.add("UseBridges 1");
|
conf.add("UseBridges 1");
|
||||||
if (needsMeek) {
|
conf.add("ClientTransportPlugin obfs4 exec " +
|
||||||
conf.add("ClientTransportPlugin meek_lite exec " +
|
obfs4File.getAbsolutePath());
|
||||||
obfs4File.getAbsolutePath());
|
conf.addAll(circumventionProvider.getBridges());
|
||||||
} else {
|
|
||||||
conf.add("ClientTransportPlugin obfs4 exec " +
|
|
||||||
obfs4File.getAbsolutePath());
|
|
||||||
}
|
|
||||||
conf.addAll(circumventionProvider.getBridges(needsMeek));
|
|
||||||
controlConnection.setConf(conf);
|
controlConnection.setConf(conf);
|
||||||
} else {
|
} else {
|
||||||
controlConnection.setConf("UseBridges", "0");
|
controlConnection.setConf("UseBridges", "0");
|
||||||
@@ -775,17 +720,12 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
enableNetwork(false);
|
enableNetwork(false);
|
||||||
} else if (network == PREF_TOR_NETWORK_WITH_BRIDGES ||
|
} else if (network == PREF_TOR_NETWORK_WITH_BRIDGES ||
|
||||||
(automatic && bridgesWork)) {
|
(automatic && bridgesWork)) {
|
||||||
if (circumventionProvider.needsMeek(country)) {
|
LOG.info("Enabling network, using bridges");
|
||||||
LOG.info("Enabling network, using meek bridges");
|
enableBridges(true);
|
||||||
enableBridges(true, true);
|
|
||||||
} else {
|
|
||||||
LOG.info("Enabling network, using obfs4 bridges");
|
|
||||||
enableBridges(true, false);
|
|
||||||
}
|
|
||||||
enableNetwork(true);
|
enableNetwork(true);
|
||||||
} else {
|
} else {
|
||||||
LOG.info("Enabling network, not using bridges");
|
LOG.info("Enabling network, not using bridges");
|
||||||
enableBridges(false, false);
|
enableBridges(false);
|
||||||
enableNetwork(true);
|
enableNetwork(true);
|
||||||
}
|
}
|
||||||
if (online && wifi && charging) {
|
if (online && wifi && charging) {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.FormatException;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.record.Record;
|
import org.briarproject.bramble.api.record.Record;
|
||||||
import org.briarproject.bramble.api.record.RecordReader;
|
import org.briarproject.bramble.api.record.RecordReader;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -14,6 +13,7 @@ import javax.annotation.concurrent.NotThreadSafe;
|
|||||||
|
|
||||||
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
|
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
|
||||||
import static org.briarproject.bramble.api.record.Record.RECORD_HEADER_BYTES;
|
import static org.briarproject.bramble.api.record.Record.RECORD_HEADER_BYTES;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.readUint16;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -31,7 +31,7 @@ class RecordReaderImpl implements RecordReader {
|
|||||||
in.readFully(header);
|
in.readFully(header);
|
||||||
byte protocolVersion = header[0];
|
byte protocolVersion = header[0];
|
||||||
byte recordType = header[1];
|
byte recordType = header[1];
|
||||||
int payloadLength = ByteUtils.readUint16(header, 2);
|
int payloadLength = readUint16(header, 2);
|
||||||
if (payloadLength < 0 || payloadLength > MAX_RECORD_PAYLOAD_BYTES)
|
if (payloadLength < 0 || payloadLength > MAX_RECORD_PAYLOAD_BYTES)
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
byte[] payload = new byte[payloadLength];
|
byte[] payload = new byte[payloadLength];
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.briarproject.bramble.record;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.record.Record;
|
import org.briarproject.bramble.api.record.Record;
|
||||||
import org.briarproject.bramble.api.record.RecordWriter;
|
import org.briarproject.bramble.api.record.RecordWriter;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@@ -11,6 +10,7 @@ import java.io.OutputStream;
|
|||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.record.Record.RECORD_HEADER_BYTES;
|
import static org.briarproject.bramble.api.record.Record.RECORD_HEADER_BYTES;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint16;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -28,7 +28,7 @@ class RecordWriterImpl implements RecordWriter {
|
|||||||
byte[] payload = r.getPayload();
|
byte[] payload = r.getPayload();
|
||||||
header[0] = r.getProtocolVersion();
|
header[0] = r.getProtocolVersion();
|
||||||
header[1] = r.getRecordType();
|
header[1] = r.getRecordType();
|
||||||
ByteUtils.writeUint16(payload.length, header, 2);
|
writeUint16(payload.length, header, 2);
|
||||||
out.write(header);
|
out.write(header);
|
||||||
out.write(payload);
|
out.write(payload);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package org.briarproject.bramble.reliability;
|
package org.briarproject.bramble.reliability;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.readUint16;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint16;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class Ack extends Frame {
|
class Ack extends Frame {
|
||||||
@@ -23,10 +25,10 @@ class Ack extends Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int getWindowSize() {
|
int getWindowSize() {
|
||||||
return ByteUtils.readUint16(buf, 5);
|
return readUint16(buf, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setWindowSize(int windowSize) {
|
void setWindowSize(int windowSize) {
|
||||||
ByteUtils.writeUint16(windowSize, buf, 5);
|
writeUint16(windowSize, buf, 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user