Compare commits

..

1 Commits

Author SHA1 Message Date
akwizgran
7f840d25d9 Add a simple Tor relay probe. 2018-10-24 10:38:49 +01:00
694 changed files with 7318 additions and 14938 deletions

View File

@@ -3,7 +3,7 @@
<module name="briar-headless" /> <module name="briar-headless" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" /> <option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="org.briarproject.briar.headless" /> <option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" /> <option name="TEST_OBJECT" value="package" />

View File

@@ -1,5 +1,3 @@
import com.android.build.gradle.tasks.MergeResources
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
apply plugin: 'witness' apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
@@ -11,8 +9,8 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 26 targetSdkVersion 26
versionCode 10105 versionCode 10103
versionName "1.1.5" versionName "1.1.3"
consumerProguardFiles 'proguard-rules.txt' consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -31,9 +29,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.4.8@zip' tor 'org.briarproject:tor-android:0.3.4.8@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.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0' compileOnly 'javax.annotation:jsr250-api:1.0'
@@ -42,29 +39,13 @@ dependencies {
testImplementation "org.jmock:jmock:2.8.2" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2" testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2" testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
} }
def torBinariesDir = 'src/main/res/raw' project.afterEvaluate {
copy {
task cleanTorBinaries { from configurations.tor.collect { zipTree(it) }
doLast { into 'src/main/res/raw'
delete fileTree(torBinariesDir) { include '*.zip' }
} }
} }
clean.dependsOn cleanTorBinaries
task unpackTorBinaries {
doLast {
copy {
from configurations.tor.collect { zipTree(it) }
into torBinariesDir
}
}
dependsOn cleanTorBinaries
}
tasks.withType(MergeResources) {
inputs.dir torBinariesDir
dependsOn unpackTorBinaries
}

View File

@@ -1,11 +0,0 @@
package org.briarproject.bramble;
import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.network.AndroidNetworkModule;
public interface BrambleAndroidEagerSingletons {
void inject(AndroidBatteryModule.EagerSingletons init);
void inject(AndroidNetworkModule.EagerSingletons init);
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble; package org.briarproject.bramble;
import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.network.AndroidNetworkModule; import org.briarproject.bramble.network.AndroidNetworkModule;
import org.briarproject.bramble.plugin.tor.CircumventionModule; import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.system.AndroidSystemModule; import org.briarproject.bramble.system.AndroidSystemModule;
@@ -8,15 +7,10 @@ import org.briarproject.bramble.system.AndroidSystemModule;
import dagger.Module; import dagger.Module;
@Module(includes = { @Module(includes = {
AndroidBatteryModule.class,
AndroidNetworkModule.class, AndroidNetworkModule.class,
AndroidSystemModule.class, AndroidSystemModule.class,
CircumventionModule.class CircumventionModule.class
}) })
public class BrambleAndroidModule { public class BrambleAndroidModule {
public static void initEagerSingletons(BrambleAndroidEagerSingletons c) {
c.inject(new AndroidBatteryModule.EagerSingletons());
c.inject(new AndroidNetworkModule.EagerSingletons());
}
} }

View File

@@ -9,22 +9,19 @@ 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.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.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 =
getLogger(AndroidAccountManager.class.getName()); Logger.getLogger(AndroidAccountManager.class.getName());
private static final String PREF_DB_KEY = "key"; private static final String PREF_DB_KEY = "key";
@@ -40,7 +37,7 @@ class AndroidAccountManager extends AccountManagerImpl
appContext = app.getApplicationContext(); appContext = app.getApplicationContext();
} }
@GuardedBy("stateChangeLock") // Locking: stateChangeLock
@Override @Override
@Nullable @Nullable
protected String loadEncryptedDatabaseKey() { protected String loadEncryptedDatabaseKey() {
@@ -50,7 +47,7 @@ class AndroidAccountManager extends AccountManagerImpl
return key; return key;
} }
@GuardedBy("stateChangeLock") // Locking: 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);
@@ -59,7 +56,7 @@ class AndroidAccountManager extends AccountManagerImpl
return key; return key;
} }
@GuardedBy("stateChangeLock") // Locking: 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())
@@ -84,7 +81,7 @@ class AndroidAccountManager extends AccountManagerImpl
return PreferenceManager.getDefaultSharedPreferences(appContext); return PreferenceManager.getDefaultSharedPreferences(appContext);
} }
@GuardedBy("stateChangeLock") // Locking: 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) {
@@ -100,7 +97,7 @@ class AndroidAccountManager extends AccountManagerImpl
for (File child : children) { for (File child : children) {
String name = child.getName(); String name = child.getName();
if (!name.equals("lib") && !name.equals("shared_prefs")) { if (!name.equals("lib") && !name.equals("shared_prefs")) {
deleteFileOrDir(child); IoUtils.deleteFileOrDir(child);
} }
} }
} }

View File

@@ -1,81 +0,0 @@
package org.briarproject.bramble.battery;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.battery.event.BatteryEvent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.Service;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.inject.Inject;
import static android.content.Intent.ACTION_BATTERY_CHANGED;
import static android.content.Intent.ACTION_POWER_CONNECTED;
import static android.content.Intent.ACTION_POWER_DISCONNECTED;
import static android.os.BatteryManager.EXTRA_PLUGGED;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
class AndroidBatteryManager implements BatteryManager, Service {
private static final Logger LOG =
getLogger(AndroidBatteryManager.class.getName());
private final Context appContext;
private final EventBus eventBus;
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile BroadcastReceiver batteryReceiver = null;
@Inject
AndroidBatteryManager(Application app, EventBus eventBus) {
this.appContext = app.getApplicationContext();
this.eventBus = eventBus;
}
@Override
public boolean isCharging() {
// Get the sticky intent for ACTION_BATTERY_CHANGED
IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
Intent i = appContext.registerReceiver(null, filter);
if (i == null) return false;
int status = i.getIntExtra(EXTRA_PLUGGED, 0);
return status != 0;
}
@Override
public void startService() {
if (used.getAndSet(true)) throw new IllegalStateException();
batteryReceiver = new BatteryReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_POWER_CONNECTED);
filter.addAction(ACTION_POWER_DISCONNECTED);
appContext.registerReceiver(batteryReceiver, filter);
}
@Override
public void stopService() {
if (batteryReceiver != null)
appContext.unregisterReceiver(batteryReceiver);
}
private class BatteryReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent i) {
String action = i.getAction();
if (LOG.isLoggable(INFO)) LOG.info("Received broadcast " + action);
if (ACTION_POWER_CONNECTED.equals(action))
eventBus.broadcast(new BatteryEvent(true));
else if (ACTION_POWER_DISCONNECTED.equals(action))
eventBus.broadcast(new BatteryEvent(false));
}
}
}

View File

@@ -1,27 +0,0 @@
package org.briarproject.bramble.battery;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidBatteryModule {
public static class EagerSingletons {
@Inject
BatteryManager batteryManager;
}
@Provides
@Singleton
BatteryManager provideBatteryManager(LifecycleManager lifecycleManager,
AndroidBatteryManager batteryManager) {
lifecycleManager.registerService(batteryManager);
return batteryManager;
}
}

View File

@@ -13,7 +13,8 @@ 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.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
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;
@@ -33,17 +34,16 @@ 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;
@NotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault
class AndroidNetworkManager implements NetworkManager, Service { class AndroidNetworkManager implements NetworkManager, Service {
private static final Logger LOG = private static final Logger LOG =
getLogger(AndroidNetworkManager.class.getName()); Logger.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,7 +56,6 @@ 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
@@ -90,8 +89,9 @@ class AndroidNetworkManager implements NetworkManager, Service {
@Override @Override
public NetworkStatus getNetworkStatus() { public NetworkStatus getNetworkStatus() {
ConnectivityManager cm = (ConnectivityManager) requireNonNull( ConnectivityManager cm = (ConnectivityManager)
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;

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.network;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import dagger.Module; import dagger.Module;
@@ -12,11 +11,6 @@ import dagger.Provides;
@Module @Module
public class AndroidNetworkModule { public class AndroidNetworkModule {
public static class EagerSingletons {
@Inject
NetworkManager networkManager;
}
@Provides @Provides
@Singleton @Singleton
NetworkManager provideNetworkManager(LifecycleManager lifecycleManager, NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,

View File

@@ -16,26 +16,18 @@ import org.briarproject.bramble.api.plugin.PluginException;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; 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.system.AndroidExecutor; import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.AndroidUtils; import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.IoUtils;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED;
import static android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED;
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED; import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED; import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE; import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
@@ -45,27 +37,18 @@ import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERA
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE; import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
import static android.bluetooth.BluetoothAdapter.STATE_OFF; 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.EXTRA_DEVICE;
import static java.util.Collections.shuffle;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
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.PrivacyUtils.scrubMacAddress;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> { class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
private static final Logger LOG = private static final Logger LOG =
getLogger(AndroidBluetoothPlugin.class.getName()); Logger.getLogger(AndroidBluetoothPlugin.class.getName());
private static final int MAX_DISCOVERY_MS = 10_000;
private final AndroidExecutor androidExecutor; private final AndroidExecutor androidExecutor;
private final Context appContext; private final Context appContext;
private final Clock clock;
private volatile boolean wasEnabledByUs = false; private volatile boolean wasEnabledByUs = false;
private volatile BluetoothStateReceiver receiver = null; private volatile BluetoothStateReceiver receiver = null;
@@ -75,13 +58,12 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter, AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
Executor ioExecutor, AndroidExecutor androidExecutor, Executor ioExecutor, AndroidExecutor androidExecutor,
Context appContext, SecureRandom secureRandom, Clock clock, Context appContext, SecureRandom secureRandom, Backoff backoff,
Backoff backoff, DuplexPluginCallback callback, int maxLatency) { DuplexPluginCallback callback, int maxLatency) {
super(connectionLimiter, ioExecutor, secureRandom, backoff, callback, super(connectionLimiter, ioExecutor, secureRandom, backoff, callback,
maxLatency); maxLatency);
this.androidExecutor = androidExecutor; this.androidExecutor = androidExecutor;
this.appContext = appContext; this.appContext = appContext;
this.clock = clock;
} }
@Override @Override
@@ -161,7 +143,11 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
@Override @Override
void tryToClose(@Nullable BluetoothServerSocket ss) { void tryToClose(@Nullable BluetoothServerSocket ss) {
IoUtils.tryToClose(ss, LOG, WARNING); try {
if (ss != null) ss.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
} }
@Override @Override
@@ -191,77 +177,17 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
s.connect(); s.connect();
return wrapSocket(s); return wrapSocket(s);
} catch (IOException e) { } catch (IOException e) {
IoUtils.tryToClose(s, LOG, WARNING); tryToClose(s);
throw e; throw e;
} }
} }
@Override private void tryToClose(@Nullable Closeable c) {
@Nullable
DuplexTransportConnection discoverAndConnect(String uuid) {
if (adapter == null) return null;
for (String address : discoverDevices()) {
try {
if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubMacAddress(address));
return connectTo(address, uuid);
} catch (IOException e) {
if (LOG.isLoggable(INFO)) {
LOG.info("Could not connect to "
+ scrubMacAddress(address));
}
}
}
LOG.info("Could not connect to any devices");
return null;
}
private Collection<String> discoverDevices() {
List<String> addresses = new ArrayList<>();
BlockingQueue<Intent> intents = new LinkedBlockingQueue<>();
DiscoveryReceiver receiver = new DiscoveryReceiver(intents);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_DISCOVERY_STARTED);
filter.addAction(ACTION_DISCOVERY_FINISHED);
filter.addAction(ACTION_FOUND);
appContext.registerReceiver(receiver, filter);
try { try {
if (adapter.startDiscovery()) { if (c != null) c.close();
long now = clock.currentTimeMillis(); } catch (IOException e) {
long end = now + MAX_DISCOVERY_MS; logException(LOG, WARNING, e);
while (now < end) {
Intent i = intents.poll(end - now, MILLISECONDS);
if (i == null) break;
String action = i.getAction();
if (ACTION_DISCOVERY_STARTED.equals(action)) {
LOG.info("Discovery started");
} else if (ACTION_DISCOVERY_FINISHED.equals(action)) {
LOG.info("Discovery finished");
break;
} else if (ACTION_FOUND.equals(action)) {
BluetoothDevice d = i.getParcelableExtra(EXTRA_DEVICE);
String address = d.getAddress();
if (LOG.isLoggable(INFO))
LOG.info("Discovered " + scrubMacAddress(address));
if (!addresses.contains(address))
addresses.add(address);
}
now = clock.currentTimeMillis();
}
} else {
LOG.info("Could not start discovery");
}
} catch (InterruptedException e) {
LOG.info("Interrupted while discovering devices");
Thread.currentThread().interrupt();
} finally {
LOG.info("Cancelling discovery");
adapter.cancelDiscovery();
appContext.unregisterReceiver(receiver);
} }
// Shuffle the addresses so we don't always try the same one first
shuffle(addresses);
return addresses;
} }
private class BluetoothStateReceiver extends BroadcastReceiver { private class BluetoothStateReceiver extends BroadcastReceiver {
@@ -281,18 +207,4 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
} }
} }
} }
private static class DiscoveryReceiver extends BroadcastReceiver {
private final BlockingQueue<Intent> intents;
private DiscoveryReceiver(BlockingQueue<Intent> intents) {
this.intents = intents;
}
@Override
public void onReceive(Context ctx, Intent intent) {
intents.add(intent);
}
}
} }

View File

@@ -11,7 +11,6 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.Clock;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -34,19 +33,17 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
private final Context appContext; private final Context appContext;
private final SecureRandom secureRandom; private final SecureRandom secureRandom;
private final EventBus eventBus; private final EventBus eventBus;
private final Clock clock;
private final BackoffFactory backoffFactory; private final BackoffFactory backoffFactory;
public AndroidBluetoothPluginFactory(Executor ioExecutor, public AndroidBluetoothPluginFactory(Executor ioExecutor,
AndroidExecutor androidExecutor, Context appContext, AndroidExecutor androidExecutor, Context appContext,
SecureRandom secureRandom, EventBus eventBus, Clock clock, SecureRandom secureRandom, EventBus eventBus,
BackoffFactory backoffFactory) { BackoffFactory backoffFactory) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.androidExecutor = androidExecutor; this.androidExecutor = androidExecutor;
this.appContext = appContext; this.appContext = appContext;
this.secureRandom = secureRandom; this.secureRandom = secureRandom;
this.eventBus = eventBus; this.eventBus = eventBus;
this.clock = clock;
this.backoffFactory = backoffFactory; this.backoffFactory = backoffFactory;
} }
@@ -68,7 +65,7 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
MAX_POLLING_INTERVAL, BACKOFF_BASE); MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin( AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
connectionLimiter, ioExecutor, androidExecutor, appContext, connectionLimiter, ioExecutor, androidExecutor, appContext,
secureRandom, clock, backoff, callback, MAX_LATENCY); secureRandom, backoff, callback, MAX_LATENCY);
eventBus.addListener(plugin); eventBus.addListener(plugin);
return plugin; return plugin;
} }

View File

@@ -32,19 +32,17 @@ 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);
@@ -68,8 +66,10 @@ 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) requireNonNull( ConnectivityManager connectivityManager = (ConnectivityManager)
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();

View File

@@ -6,9 +6,9 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.os.PowerManager; import android.os.PowerManager;
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.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
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;
@@ -25,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;
@NotNullByDefault @MethodsNotNullByDefault
@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
@@ -41,17 +41,17 @@ class AndroidTorPlugin extends TorPlugin {
Context appContext, NetworkManager networkManager, Context appContext, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory, LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider, Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, CircumventionProvider circumventionProvider, Backoff backoff,
BatteryManager batteryManager, Backoff backoff,
DuplexPluginCallback callback, String architecture, int maxLatency, DuplexPluginCallback callback, String architecture, int maxLatency,
int maxIdleTime) { int maxIdleTime) {
super(ioExecutor, networkManager, locationUtils, torSocketFactory, super(ioExecutor, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager, clock, resourceProvider, circumventionProvider, backoff,
backoff, callback, architecture, maxLatency, maxIdleTime, callback, architecture, maxLatency, maxIdleTime,
appContext.getDir("tor", MODE_PRIVATE)); appContext.getDir("tor", MODE_PRIVATE));
this.appContext = appContext; this.appContext = appContext;
PowerManager pm = (PowerManager) PowerManager pm = (PowerManager)
requireNonNull(appContext.getSystemService(POWER_SERVICE)); appContext.getSystemService(POWER_SERVICE);
assert pm != null;
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);
} }

View File

@@ -1,8 +1,8 @@
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.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -25,15 +25,12 @@ 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 =
getLogger(AndroidTorPluginFactory.class.getName()); Logger.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
@@ -51,7 +48,6 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
private final BackoffFactory backoffFactory; private final BackoffFactory backoffFactory;
private final ResourceProvider resourceProvider; private final ResourceProvider resourceProvider;
private final CircumventionProvider circumventionProvider; private final CircumventionProvider circumventionProvider;
private final BatteryManager batteryManager;
private final Clock clock; private final Clock clock;
public AndroidTorPluginFactory(Executor ioExecutor, public AndroidTorPluginFactory(Executor ioExecutor,
@@ -59,8 +55,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
NetworkManager networkManager, LocationUtils locationUtils, NetworkManager networkManager, LocationUtils locationUtils,
EventBus eventBus, SocketFactory torSocketFactory, EventBus eventBus, SocketFactory torSocketFactory,
BackoffFactory backoffFactory, ResourceProvider resourceProvider, BackoffFactory backoffFactory, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, CircumventionProvider circumventionProvider, Clock clock) {
BatteryManager batteryManager, Clock clock) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.scheduler = scheduler; this.scheduler = scheduler;
this.appContext = appContext; this.appContext = appContext;
@@ -71,7 +66,6 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
this.backoffFactory = backoffFactory; this.backoffFactory = backoffFactory;
this.resourceProvider = resourceProvider; this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider; this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.clock = clock; this.clock = clock;
} }
@@ -104,14 +98,14 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
return null; return null;
} }
// Use position-independent executable for SDK >= 16 // Use position-independent executable for SDK >= 16
if (SDK_INT >= 16) architecture += "_pie"; if (Build.VERSION.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);
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler, AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
appContext, networkManager, locationUtils, torSocketFactory, appContext, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager, clock, resourceProvider, circumventionProvider, backoff,
backoff, callback, architecture, MAX_LATENCY, MAX_IDLE_TIME); callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin); eventBus.addListener(plugin);
return plugin; return plugin;
} }

View File

@@ -0,0 +1,153 @@
package org.briarproject.bramble.plugin.tor;
import org.spongycastle.crypto.tls.Certificate;
import org.spongycastle.crypto.tls.CipherSuite;
import org.spongycastle.crypto.tls.DefaultTlsClient;
import org.spongycastle.crypto.tls.ServerOnlyTlsAuthentication;
import org.spongycastle.crypto.tls.TlsAuthentication;
import org.spongycastle.crypto.tls.TlsClientProtocol;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import static java.util.logging.Level.INFO;
public class TorProbe {
private static final Logger LOG =
Logger.getLogger(TorProbe.class.getName());
private static final int READ_TIMEOUT = 10 * 1000;
// https://trac.torproject.org/projects/tor/wiki/org/projects/Tor/TLSHistory
private static final int SSL3_RSA_FIPS_WITH_3DES_EDE_CBC_SHA = 0xfeff;
// https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt#n347
private static final int[] TOR_CIPHER_SUITES = new int[] {
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA,
CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_RSA_WITH_RC4_128_MD5,
CipherSuite.TLS_RSA_WITH_RC4_128_SHA,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSL3_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,
CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA
};
// https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt#n412
private static final byte[] VERSIONS_CELL = new byte[] {
0x00, 0x00, // Circuit ID: 0
0x07, // Command: Versions
0x00, 0x06, // Payload length: 6 bytes
0x00, 0x03, 0x00, 0x04, 0x00, 0x05 // Supported versions: 3, 4, 5
};
public List<Integer> probe(String address, int port) throws IOException {
if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + address + ":" + port);
Socket socket = new Socket(address, port);
LOG.info("Connected");
TlsClientProtocol client = new TlsClientProtocol(
socket.getInputStream(), socket.getOutputStream(),
new SecureRandom());
client.connect(new TorTlsClient());
LOG.info("TLS handshake succeeded");
socket.setSoTimeout(READ_TIMEOUT);
try {
// Send a versions cell
OutputStream out = client.getOutputStream();
out.write(VERSIONS_CELL);
out.flush();
LOG.info("Sent versions cell");
// Expect a versions cell in response
List<Integer> versions = new ArrayList<>();
DataInputStream in = new DataInputStream(client.getInputStream());
int circuitId = in.readUnsignedShort();
if (circuitId != 0)
throw new IOException("Unexpected circuit ID: " + circuitId);
int command = in.readUnsignedByte();
if (command != 7)
throw new IOException("Unexpected command: " + command);
int payloadLength = in.readUnsignedShort();
if (payloadLength == 0 || payloadLength % 2 != 0) {
throw new IOException("Invalid payload length: "
+ payloadLength);
}
for (int i = 0; i < payloadLength / 2; i++) {
int version = in.readUnsignedShort();
versions.add(version);
}
if (LOG.isLoggable(INFO))
LOG.info("Supported versions: " + versions);
return versions;
} finally {
client.close();
}
}
public static void main(String[] args) throws IOException {
if (args.length != 2) {
System.err.println("Usage: TorProbe <address> <port>");
System.exit(1);
}
String address = args[0];
int port = Integer.parseInt(args[1]);
new TorProbe().probe(address, port);
}
private static class TorTlsClient extends DefaultTlsClient {
@Override
public TlsAuthentication getAuthentication() {
return new ServerOnlyTlsAuthentication() {
@Override
public void notifyServerCertificate(Certificate cert)
throws IOException {
LOG.info("Received server certificate");
org.spongycastle.asn1.x509.Certificate[] chain =
cert.getCertificateList();
if (chain.length != 1)
throw new IOException("Certificate is not self-signed");
for (org.spongycastle.asn1.x509.Certificate c : chain) {
if (LOG.isLoggable(INFO)) {
LOG.info("Subject: " + c.getSubject());
LOG.info("Issuer: " + c.getIssuer());
}
}
}
};
}
@Override
public int[] getCipherSuites() {
return TOR_CIPHER_SUITES;
}
}
}

View File

@@ -15,13 +15,12 @@ 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 =
getLogger(AndroidLocationUtils.class.getName()); Logger.getLogger(AndroidLocationUtils.class.getName());
private final Context appContext; private final Context appContext;
@@ -60,14 +59,14 @@ class AndroidLocationUtils implements LocationUtils {
} }
private String getCountryFromPhoneNetwork() { private String getCountryFromPhoneNetwork() {
TelephonyManager tm = (TelephonyManager) Object o = appContext.getSystemService(TELEPHONY_SERVICE);
appContext.getSystemService(TELEPHONY_SERVICE); TelephonyManager tm = (TelephonyManager) o;
return tm == null ? "" : tm.getNetworkCountryIso(); return tm.getNetworkCountryIso();
} }
private String getCountryFromSimCard() { private String getCountryFromSimCard() {
TelephonyManager tm = (TelephonyManager) Object o = appContext.getSystemService(TELEPHONY_SERVICE);
appContext.getSystemService(TELEPHONY_SERVICE); TelephonyManager tm = (TelephonyManager) o;
return tm == null ? "" : tm.getSimCountryIso(); return tm.getSimCountryIso();
} }
} }

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.system; package org.briarproject.bramble.system;
import android.annotation.SuppressLint;
import android.app.Application; import android.app.Application;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
@@ -8,6 +7,7 @@ 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;
@@ -22,14 +22,11 @@ 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
@NotNullByDefault @NotNullByDefault
class AndroidSecureRandomProvider extends UnixSecureRandomProvider { class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
private static final int SEED_LENGTH = 32; private static final int SEED_LENGTH = 32;
@@ -40,27 +37,24 @@ class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
appContext = app.getApplicationContext(); appContext = app.getApplicationContext();
} }
@SuppressLint("HardwareIds")
@Override @Override
protected void writeToEntropyPool(DataOutputStream out) throws IOException { protected void writeToEntropyPool(DataOutputStream out) throws IOException {
super.writeToEntropyPool(out); super.writeToEntropyPool(out);
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 (FINGERPRINT != null) out.writeUTF(FINGERPRINT); if (Build.FINGERPRINT != null) out.writeUTF(Build.FINGERPRINT);
if (SERIAL != null) out.writeUTF(SERIAL); if (Build.SERIAL != null) out.writeUTF(Build.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);
Parcel parcel = Parcel.obtain(); Parcel parcel = Parcel.obtain();
WifiManager wm = (WifiManager) appContext.getApplicationContext() WifiManager wm =
.getSystemService(WIFI_SERVICE); (WifiManager) appContext.getSystemService(WIFI_SERVICE);
if (wm != null) { List<WifiConfiguration> configs = wm.getConfiguredNetworks();
List<WifiConfiguration> configs = wm.getConfiguredNetworks(); if (configs != null) {
if (configs != null) { for (WifiConfiguration config : configs)
for (WifiConfiguration config : configs) parcel.writeParcelable(config, 0);
parcel.writeParcelable(config, 0);
}
} }
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
if (bt != null) { if (bt != null) {
@@ -76,18 +70,20 @@ 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 (SDK_INT >= 16 && SDK_INT <= 18) applyOpenSslFix(); if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18)
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(SEED_LENGTH); byte[] seed = new LinuxSecureRandomSpi().engineGenerateSeed(
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")
.getMethod("RAND_seed", byte[].class) .getMethod("RAND_seed", byte[].class)
.invoke(null, (Object) seed); .invoke(null, seed);
// Mix the output of the Linux PRNG into the OpenSSL PRNG // Mix the output of the Linux PRNG into the OpenSSL PRNG
int bytesRead = (Integer) Class.forName( int bytesRead = (Integer) Class.forName(
"org.apache.harmony.xnet.provider.jsse.NativeCrypto") "org.apache.harmony.xnet.provider.jsse.NativeCrypto")

View File

@@ -3,35 +3,36 @@ 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 java.util.logging.Logger;
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 java.util.Arrays.asList;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
public class AndroidUtils { public class AndroidUtils {
private static final Logger LOG =
Logger.getLogger(AndroidUtils.class.getName());
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later // Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00"; private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
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 (Build.VERSION.SDK_INT >= 21) {
abis.addAll(asList(SUPPORTED_ABIS)); abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
} else { } else {
abis.add(CPU_ABI); abis.add(Build.CPU_ABI);
if (CPU_ABI2 != null) abis.add(CPU_ABI2); if (Build.CPU_ABI2 != null) abis.add(Build.CPU_ABI2);
} }
return abis; return abis;
} }
@@ -51,7 +52,7 @@ public class AndroidUtils {
} }
private static boolean isValidBluetoothAddress(String address) { private static boolean isValidBluetoothAddress(String address) {
return !isNullOrEmpty(address) return !StringUtils.isNullOrEmpty(address)
&& BluetoothAdapter.checkBluetoothAddress(address) && BluetoothAdapter.checkBluetoothAddress(address)
&& !address.equals(FAKE_BLUETOOTH_ADDRESS); && !address.equals(FAKE_BLUETOOTH_ADDRESS);
} }

View File

@@ -10,19 +10,17 @@ 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 =
getLogger(RenewableWakeLock.class.getName()); Logger.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
@@ -38,12 +36,10 @@ 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; private PowerManager.WakeLock wakeLock; // Locking: lock
@GuardedBy("lock")
@Nullable @Nullable
private ScheduledFuture future; private ScheduledFuture future; // Locking: lock
public RenewableWakeLock(PowerManager powerManager, public RenewableWakeLock(PowerManager powerManager,
ScheduledExecutorService scheduler, int levelAndFlags, String tag, ScheduledExecutorService scheduler, int levelAndFlags, String tag,

View File

@@ -31,21 +31,16 @@ dependencyVerification {
'com.android.tools:sdklib:26.2.1:sdklib-26.2.1.jar:248df7ad5eac4aeb6f96c394c76760de4b7b89ac056e54d0c21a739368b91b45', '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.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.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768', 'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1', 'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'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.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.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'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.guava:guava:23.0:guava-23.0.jar:7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596', '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.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',
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439', 'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0', 'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce', 'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4', 'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
@@ -68,9 +63,7 @@ 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.7:obfs4proxy-android-0.0.7.zip:abdfb5d889d848de9bf214f9276abbf454808a505b870819eccc9a9e985bf617',
'org.briarproject:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926', '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.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4', 'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
'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',

View File

@@ -7,13 +7,15 @@ apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
dependencies { dependencies {
implementation "com.google.dagger:dagger:2.19" implementation "com.google.dagger:dagger:2.0.2"
implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation 'com.google.code.findbugs:jsr305:3.0.2'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2" testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2" testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
signature 'org.codehaus.mojo.signature:java16:1.1@signature' signature 'org.codehaus.mojo.signature:java16:1.1@signature'
} }

View File

@@ -1,14 +1,13 @@
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.
*/ */
@@ -57,7 +56,8 @@ public class Bytes implements Comparable<Bytes> {
@Override @Override
public String toString() { public String toString() {
return getClass().getSimpleName() + "(" + toHexString(getBytes()) + ")"; return getClass().getSimpleName() +
"(" + StringUtils.toHexString(getBytes()) + ")";
} }
public static class BytesComparator implements Comparator<Bytes> { public static class BytesComparator implements Comparator<Bytes> {

View File

@@ -2,6 +2,7 @@ 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;
@@ -9,8 +10,6 @@ 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> {
@@ -97,6 +96,6 @@ public class Multiset<T> {
* is unmodifiable. * is unmodifiable.
*/ */
public Set<T> keySet() { public Set<T> keySet() {
return unmodifiableSet(map.keySet()); return Collections.unmodifiableSet(map.keySet());
} }
} }

View File

@@ -1,26 +0,0 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class Pair<A, B> {
private final A first;
private final B second;
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
public A getFirst() {
return first;
}
public B getSecond() {
return second;
}
}

View File

@@ -1,6 +0,0 @@
package org.briarproject.bramble.api.battery;
public interface BatteryManager {
boolean isCharging();
}

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.api.battery.event;
import org.briarproject.bramble.api.event.Event;
/**
* An event that is broadcast when the device starts or stops charging.
*/
public class BatteryEvent extends Event {
private final boolean charging;
public BatteryEvent(boolean charging) {
this.charging = charging;
}
public boolean isCharging() {
return charging;
}
}

View File

@@ -5,11 +5,10 @@ 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 {
@@ -24,7 +23,7 @@ public class BdfMessageContext {
} }
public BdfMessageContext(BdfDictionary dictionary) { public BdfMessageContext(BdfDictionary dictionary) {
this(dictionary, emptyList()); this(dictionary, Collections.emptyList());
} }
public BdfDictionary getDictionary() { public BdfDictionary getDictionary() {

View File

@@ -9,14 +9,13 @@ import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.InvalidMessageException; import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext; import org.briarproject.bramble.api.sync.MessageContext;
import org.briarproject.bramble.api.sync.validation.MessageValidator; import org.briarproject.bramble.api.sync.ValidationManager.MessageValidator;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import java.util.logging.Logger; 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
@@ -24,7 +23,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 =
getLogger(BdfMessageValidator.class.getName()); Logger.getLogger(BdfMessageValidator.class.getName());
protected final ClientHelper clientHelper; protected final ClientHelper clientHelper;
protected final MetadataEncoder metadataEncoder; protected final MetadataEncoder metadataEncoder;

View File

@@ -4,12 +4,8 @@ import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
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.util.StringUtils.toUtf8;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class Contact { public class Contact {
@@ -17,21 +13,13 @@ public class Contact {
private final ContactId id; private final ContactId id;
private final Author author; private final Author author;
private final AuthorId localAuthorId; private final AuthorId localAuthorId;
@Nullable
private final String alias;
private final boolean verified, active; private final boolean verified, active;
public Contact(ContactId id, Author author, AuthorId localAuthorId, public Contact(ContactId id, Author author, AuthorId localAuthorId,
@Nullable String alias, boolean verified, boolean active) { boolean verified, boolean active) {
if (alias != null) {
int aliasLength = toUtf8(alias).length;
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException();
}
this.id = id; this.id = id;
this.author = author; this.author = author;
this.localAuthorId = localAuthorId; this.localAuthorId = localAuthorId;
this.alias = alias;
this.verified = verified; this.verified = verified;
this.active = active; this.active = active;
} }
@@ -48,11 +36,6 @@ public class Contact {
return localAuthorId; return localAuthorId;
} }
@Nullable
public String getAlias() {
return alias;
}
public boolean isVerified() { public boolean isVerified() {
return verified; return verified;
} }

View File

@@ -5,16 +5,11 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection; import java.util.Collection;
import javax.annotation.Nullable;
import static org.briarproject.bramble.api.contact.PendingContact.PendingContactState.FAILED;
@NotNullByDefault @NotNullByDefault
public interface ContactManager { public interface ContactManager {
@@ -54,35 +49,6 @@ public interface ContactManager {
long timestamp, boolean alice, boolean verified, boolean active) long timestamp, boolean alice, boolean verified, boolean active)
throws DbException; throws DbException;
/**
* Returns the static link that needs to be sent to the contact to be added.
*/
String getRemoteContactLink();
/**
* Returns true if the given link is syntactically valid.
*/
boolean isValidRemoteContactLink(String link);
/**
* Requests a new contact to be added via the given {@code link}.
*
* @param link The link received from the contact we want to add.
* @param alias The alias the user has given this contact.
* @return A PendingContact representing the contact to be added.
*/
PendingContact addRemoteContactRequest(String link, String alias);
/**
* Returns a list of {@link PendingContact}s.
*/
Collection<PendingContact> getPendingContacts();
/**
* Removes a {@link PendingContact} that is in state {@link FAILED}.
*/
void removePendingContact(PendingContact pendingContact);
/** /**
* Returns the contact with the given ID. * Returns the contact with the given ID.
*/ */
@@ -127,18 +93,6 @@ public interface ContactManager {
void setContactActive(Transaction txn, ContactId c, boolean active) void setContactActive(Transaction txn, ContactId c, boolean active)
throws DbException; throws DbException;
/**
* Sets an alias name for the contact or unsets it if alias is null.
*/
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
throws DbException;
/**
* Sets an alias name for the contact or unsets it if alias is null.
*/
void setContactAlias(ContactId c, @Nullable String alias)
throws DbException;
/** /**
* Return true if a contact with this name and public key already exists * Return true if a contact with this name and public key already exists
*/ */
@@ -151,16 +105,6 @@ public interface ContactManager {
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId) boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException; throws DbException;
/**
* Returns the {@link AuthorInfo} for the given author.
*/
AuthorInfo getAuthorInfo(AuthorId a) throws DbException;
/**
* Returns the {@link AuthorInfo} for the given author.
*/
AuthorInfo getAuthorInfo(Transaction txn, AuthorId a) throws DbException;
interface ContactHook { interface ContactHook {
void addingContact(Transaction txn, Contact c) throws DbException; void addingContact(Transaction txn, Contact c) throws DbException;

View File

@@ -1,54 +0,0 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class PendingContact {
public enum PendingContactState {
WAITING_FOR_CONNECTION,
CONNECTED,
ADDING_CONTACT,
FAILED
}
private final PendingContactId id;
private final String alias;
private final PendingContactState state;
private final long timestamp;
public PendingContact(PendingContactId id, String alias,
PendingContactState state, long timestamp) {
this.id = id;
this.alias = alias;
this.state = state;
this.timestamp = timestamp;
}
public String getAlias() {
return alias;
}
public PendingContactState getState() {
return state;
}
public long getTimestamp() {
return timestamp;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof PendingContact &&
id.equals(((PendingContact) o).id);
}
}

View File

@@ -1,11 +0,0 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.UniqueId;
public class PendingContactId extends UniqueId {
public PendingContactId(byte[] id) {
super(id);
}
}

View File

@@ -1,34 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.PendingContact.PendingContactState;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a pending contact's state is changed.
*/
@Immutable
@NotNullByDefault
public class PendingContactStateChangedEvent extends Event {
private final PendingContactId id;
private final PendingContactState state;
public PendingContactStateChangedEvent(PendingContactId id,
PendingContactState state) {
this.id = id;
this.state = state;
}
public PendingContactId getId() {
return id;
}
public PendingContactState getPendingContactState() {
return state;
}
}

View File

@@ -4,6 +4,7 @@ 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;
@@ -23,9 +24,9 @@ public class BdfDictionary extends TreeMap<String, Object> {
* ); * );
* </pre> * </pre>
*/ */
public static BdfDictionary of(BdfEntry... entries) { public static BdfDictionary of(Entry<String, ?>... entries) {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
for (BdfEntry e : entries) d.put(e.getKey(), e.getValue()); for (Entry<String, ?> e : entries) d.put(e.getKey(), e.getValue());
return d; return d;
} }

View File

@@ -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(asList(items)); return new BdfList(Arrays.asList(items));
} }
public BdfList() { public BdfList() {
@@ -33,7 +33,6 @@ 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();
} }

View File

@@ -1,71 +0,0 @@
package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
import static org.briarproject.bramble.util.StringUtils.toHexString;
@NotNullByDefault
public class BdfStringUtils {
public static String toString(@Nullable Object o) throws FormatException {
return toString(o, 0);
}
private static String toString(@Nullable Object o, int indent)
throws FormatException {
if (o == null || o == NULL_VALUE) return "null";
if (o instanceof Boolean) return o.toString();
if (o instanceof Number) return o.toString();
if (o instanceof String) return "\"" + o + "\"";
if (o instanceof Bytes)
return "x" + toHexString(((Bytes) o).getBytes());
if (o instanceof byte[])
return "x" + toHexString((byte[]) o);
if (o instanceof List) {
List<?> list = (List) o;
StringBuilder sb = new StringBuilder();
sb.append("[\n");
int i = 0, size = list.size();
for (Object e : list) {
indent(sb, indent + 1);
sb.append(toString(e, indent + 1));
if (i++ < size - 1) sb.append(',');
sb.append('\n');
}
indent(sb, indent);
sb.append(']');
return sb.toString();
}
if (o instanceof Map) {
Map<?, ?> map = (Map) o;
StringBuilder sb = new StringBuilder();
sb.append("{\n");
int i = 0, size = map.size();
for (Entry e : map.entrySet()) {
indent(sb, indent + 1);
sb.append(toString(e.getKey(), indent + 1));
sb.append(": ");
sb.append(toString(e.getValue(), indent + 1));
if (i++ < size - 1) sb.append(',');
sb.append('\n');
}
indent(sb, indent);
sb.append('}');
return sb.toString();
}
throw new FormatException();
}
private static void indent(StringBuilder sb, int indent) {
for (int i = 0; i < indent; i++) sb.append('\t');
}
}

View File

@@ -19,7 +19,6 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.KeySet; import org.briarproject.bramble.api.transport.KeySet;
import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.api.transport.TransportKeys;
@@ -29,6 +28,8 @@ import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static org.briarproject.bramble.api.sync.ValidationManager.State;
/** /**
* Encapsulates the database implementation and exposes high-level operations * Encapsulates the database implementation and exposes high-level operations
* to other components. * to other components.
@@ -88,14 +89,6 @@ public interface DatabaseComponent {
<R, E extends Exception> R transactionWithResult(boolean readOnly, <R, E extends Exception> R transactionWithResult(boolean readOnly,
DbCallable<R, E> task) throws DbException, E; DbCallable<R, E> task) throws DbException, E;
/**
* Runs the given task within a transaction and returns the result of the
* task, which may be null.
*/
@Nullable
<R, E extends Exception> R transactionWithNullableResult(boolean readOnly,
NullableDbCallable<R, E> task) throws DbException, E;
/** /**
* Stores a contact associated with the given local and remote pseudonyms, * Stores a contact associated with the given local and remote pseudonyms,
* and returns an ID for the contact. * and returns an ID for the contact.
@@ -373,12 +366,12 @@ public interface DatabaseComponent {
/** /**
* Returns the IDs and states of all dependencies of the given message. * Returns the IDs and states of all dependencies of the given message.
* For missing dependencies and dependencies in other groups, the state * For missing dependencies and dependencies in other groups, the state
* {@link MessageState UNKNOWN} is returned. * {@link State UNKNOWN} is returned.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
Map<MessageId, MessageState> getMessageDependencies(Transaction txn, Map<MessageId, State> getMessageDependencies(Transaction txn, MessageId m)
MessageId m) throws DbException; throws DbException;
/** /**
* Returns the IDs and states of all dependents of the given message. * Returns the IDs and states of all dependents of the given message.
@@ -387,16 +380,15 @@ public interface DatabaseComponent {
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
Map<MessageId, MessageState> getMessageDependents(Transaction txn, Map<MessageId, State> getMessageDependents(Transaction txn, MessageId m)
MessageId m) throws DbException; throws DbException;
/** /**
* Gets the validation and delivery state of the given message. * Gets the validation and delivery state of the given message.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
MessageState getMessageState(Transaction txn, MessageId m) State getMessageState(Transaction txn, MessageId m) throws DbException;
throws DbException;
/** /**
* Returns the status of the given delivered message with respect to the * Returns the status of the given delivered message with respect to the
@@ -523,12 +515,6 @@ public interface DatabaseComponent {
void setContactActive(Transaction txn, ContactId c, boolean active) void setContactActive(Transaction txn, ContactId c, boolean active)
throws DbException; throws DbException;
/**
* Sets an alias name for the contact or unsets it if alias is null.
*/
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
throws DbException;
/** /**
* Sets the given group's visibility to the given contact. * Sets the given group's visibility to the given contact.
*/ */
@@ -543,7 +529,7 @@ public interface DatabaseComponent {
/** /**
* Sets the validation and delivery state of the given message. * Sets the validation and delivery state of the given message.
*/ */
void setMessageState(Transaction txn, MessageId m, MessageState state) void setMessageState(Transaction txn, MessageId m, State state)
throws DbException; throws DbException;
/** /**

View File

@@ -1,8 +1,5 @@
package org.briarproject.bramble.api.db; package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface DbCallable<R, E extends Exception> { public interface DbCallable<R, E extends Exception> {
R call(Transaction txn) throws DbException, E; R call(Transaction txn) throws DbException, E;

View File

@@ -1,8 +1,5 @@
package org.briarproject.bramble.api.db; package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface DbRunnable<E extends Exception> { public interface DbRunnable<E extends Exception> {
void run(Transaction txn) throws DbException, E; void run(Transaction txn) throws DbException, E;

View File

@@ -1,12 +0,0 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
public interface NullableDbCallable<R, E extends Exception> {
@Nullable
R call(Transaction txn) throws DbException, E;
}

View File

@@ -3,12 +3,11 @@ 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.
*/ */
@@ -54,7 +53,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 emptyList(); if (events == null) return Collections.emptyList();
return events; return events;
} }

View File

@@ -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.
@@ -16,6 +16,10 @@ import static org.briarproject.bramble.util.StringUtils.toUtf8;
@NotNullByDefault @NotNullByDefault
public class Author implements Nameable { public class Author implements Nameable {
public enum Status {
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
}
/** /**
* The current version of the author structure. * The current version of the author structure.
*/ */
@@ -28,7 +32,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 = toUtf8(name).length; int nameLength = StringUtils.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)

View File

@@ -1,56 +0,0 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class AuthorInfo {
public enum Status {
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES;
public boolean isContact() {
return this == UNVERIFIED || this == VERIFIED;
}
}
private final Status status;
@Nullable
private final String alias;
public AuthorInfo(Status status, @Nullable String alias) {
this.status = status;
this.alias = alias;
}
public AuthorInfo(Status status) {
this(status, null);
}
public Status getStatus() {
return status;
}
@Nullable
public String getAlias() {
return alias;
}
@Override
public int hashCode() {
int hashCode = status.ordinal();
if (alias != null) hashCode += alias.hashCode();
return hashCode;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof AuthorInfo)) return false;
AuthorInfo info = (AuthorInfo) o;
return status == info.status &&
(alias == null ? info.alias == null : alias.equals(info.alias));
}
}

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author.Status;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault @NotNullByDefault
@@ -36,4 +37,14 @@ public interface IdentityManager {
*/ */
LocalAuthor getLocalAuthor(Transaction txn) throws DbException; LocalAuthor getLocalAuthor(Transaction txn) throws DbException;
/**
* Returns the {@link Status} of the given author.
*/
Status getAuthorStatus(AuthorId a) throws DbException;
/**
* Returns the {@link Status} of the given author.
*/
Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException;
} }

View File

@@ -21,7 +21,7 @@ public interface KeyAgreementConstants {
/** /**
* The connection timeout in milliseconds. * The connection timeout in milliseconds.
*/ */
long CONNECTION_TIMEOUT = 60_000; long CONNECTION_TIMEOUT = 20 * 1000;
/** /**
* The transport identifier for Bluetooth. * The transport identifier for Bluetooth.

View File

@@ -1,15 +0,0 @@
package org.briarproject.bramble.api.nullsafety;
import javax.annotation.Nullable;
@NotNullByDefault
public class NullSafety {
/**
* Stand-in for `Objects.requireNonNull()`.
*/
public static <T> T requireNonNull(@Nullable T t) {
if (t == null) throw new NullPointerException();
return t;
}
}

View File

@@ -16,7 +16,6 @@ public interface TorConstants {
String PREF_TOR_NETWORK = "network2"; String PREF_TOR_NETWORK = "network2";
String PREF_TOR_PORT = "port"; String PREF_TOR_PORT = "port";
String PREF_TOR_MOBILE = "useMobileData"; String PREF_TOR_MOBILE = "useMobileData";
String PREF_TOR_ONLY_WHEN_CHARGING = "onlyWhenCharging";
int PREF_TOR_NETWORK_AUTOMATIC = 0; int PREF_TOR_NETWORK_AUTOMATIC = 0;
int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1; int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1;

View File

@@ -1,6 +1,6 @@
package org.briarproject.bramble.api.plugin; package org.briarproject.bramble.api.plugin;
import static org.briarproject.bramble.util.StringUtils.toUtf8; import org.briarproject.bramble.util.StringUtils;
/** /**
* 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 final int MAX_TRANSPORT_ID_LENGTH = 100; public static int MAX_TRANSPORT_ID_LENGTH = 100;
private final String id; private final String id;
public TransportId(String id) { public TransportId(String id) {
int length = toUtf8(id).length; int length = StringUtils.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;

View File

@@ -1,11 +1,10 @@
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.
@@ -17,12 +16,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 final int MAX_CLIENT_ID_LENGTH = 100; public static int MAX_CLIENT_ID_LENGTH = 100;
private final String id; private final String id;
public ClientId(String id) { public ClientId(String id) {
int length = toUtf8(id).length; int length = StringUtils.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;

View File

@@ -4,11 +4,10 @@ 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 {
@@ -23,7 +22,7 @@ public class MessageContext {
} }
public MessageContext(Metadata metadata) { public MessageContext(Metadata metadata) {
this(metadata, emptyList()); this(metadata, Collections.emptyList());
} }
public Metadata getMetadata() { public Metadata getMetadata() {

View File

@@ -0,0 +1,87 @@
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* Responsible for managing message validators and passing them messages to
* validate.
*/
@NotNullByDefault
public interface ValidationManager {
enum State {
UNKNOWN(0), INVALID(1), PENDING(2), DELIVERED(3);
private final int value;
State(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static State fromValue(int value) {
for (State s : values()) if (s.value == value) return s;
throw new IllegalArgumentException();
}
}
/**
* Registers the message validator for the given client. This method
* should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerMessageValidator(ClientId c, int majorVersion,
MessageValidator v);
/**
* Registers the incoming message hook for the given client. The hook will
* be called once for each incoming message that passes validation. This
* method should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerIncomingMessageHook(ClientId c, int majorVersion,
IncomingMessageHook hook);
interface MessageValidator {
/**
* Validates the given message and returns its metadata and
* dependencies.
*/
MessageContext validateMessage(Message m, Group g)
throws InvalidMessageException;
}
interface IncomingMessageHook {
/**
* Called once for each incoming message that passes validation.
*
* @return whether or not this message should be shared
* @throws DbException Should only be used for real database errors.
* If this is thrown, delivery will be attempted again at next startup,
* whereas if an InvalidMessageException is thrown,
* the message will be permanently invalidated.
* @throws InvalidMessageException for any non-database error
* that occurs while handling remotely created data.
* This includes errors that occur while handling locally created data
* in a context controlled by remotely created data
* (for example, parsing the metadata of a dependency
* of an incoming message).
* Throwing this will delete the incoming message and its metadata
* marking it as invalid in the database.
* Never rethrow DbException as InvalidMessageException!
*/
boolean incomingMessage(Transaction txn, Message m, Metadata meta)
throws DbException, InvalidMessageException;
}
}

View File

@@ -3,10 +3,11 @@ package org.briarproject.bramble.api.sync.event;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.validation.MessageState;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.sync.ValidationManager.State;
/** /**
* An event that is broadcast when a message state changed. * An event that is broadcast when a message state changed.
*/ */
@@ -16,10 +17,10 @@ public class MessageStateChangedEvent extends Event {
private final MessageId messageId; private final MessageId messageId;
private final boolean local; private final boolean local;
private final MessageState state; private final State state;
public MessageStateChangedEvent(MessageId messageId, boolean local, public MessageStateChangedEvent(MessageId messageId, boolean local,
MessageState state) { State state) {
this.messageId = messageId; this.messageId = messageId;
this.local = local; this.local = local;
this.state = state; this.state = state;
@@ -33,7 +34,7 @@ public class MessageStateChangedEvent extends Event {
return local; return local;
} }
public MessageState getState() { public State getState() {
return state; return state;
} }

View File

@@ -1,31 +0,0 @@
package org.briarproject.bramble.api.sync.validation;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
public interface IncomingMessageHook {
/**
* Called once for each incoming message that passes validation.
*
* @return whether or not this message should be shared
* @throws DbException Should only be used for real database errors.
* If this is thrown, delivery will be attempted again at next startup,
* whereas if an InvalidMessageException is thrown,
* the message will be permanently invalidated.
* @throws InvalidMessageException for any non-database error
* that occurs while handling remotely created data.
* This includes errors that occur while handling locally created data
* in a context controlled by remotely created data
* (for example, parsing the metadata of a dependency
* of an incoming message).
* Throwing this will delete the incoming message and its metadata
* marking it as invalid in the database.
* Never rethrow DbException as InvalidMessageException!
*/
boolean incomingMessage(Transaction txn, Message m, Metadata meta)
throws DbException, InvalidMessageException;
}

View File

@@ -1,21 +0,0 @@
package org.briarproject.bramble.api.sync.validation;
public enum MessageState {
UNKNOWN(0), INVALID(1), PENDING(2), DELIVERED(3);
private final int value;
MessageState(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static MessageState fromValue(int value) {
for (MessageState s : values()) if (s.value == value) return s;
throw new IllegalArgumentException();
}
}

View File

@@ -1,16 +0,0 @@
package org.briarproject.bramble.api.sync.validation;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext;
public interface MessageValidator {
/**
* Validates the given message and returns its metadata and
* dependencies.
*/
MessageContext validateMessage(Message m, Group g)
throws InvalidMessageException;
}

View File

@@ -1,31 +0,0 @@
package org.briarproject.bramble.api.sync.validation;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.ClientId;
/**
* Responsible for managing message validators and passing them messages to
* validate.
*/
@NotNullByDefault
public interface ValidationManager {
/**
* Registers the {@link MessageValidator} for the given client. This method
* should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerMessageValidator(ClientId c, int majorVersion,
MessageValidator v);
/**
* Registers the {@link IncomingMessageHook} for the given client. The hook
* will be called once for each incoming message that passes validation.
* This method should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerIncomingMessageHook(ClientId c, int majorVersion,
IncomingMessageHook hook);
}

View File

@@ -38,13 +38,6 @@ public interface ClientVersioningManager {
Visibility getClientVisibility(Transaction txn, ContactId contactId, Visibility getClientVisibility(Transaction txn, ContactId contactId,
ClientId clientId, int majorVersion) throws DbException; ClientId clientId, int majorVersion) throws DbException;
/**
* Returns the minor version of the given client that is supported by the
* given contact, or -1 if the contact does not support the client.
*/
int getClientMinorVersion(Transaction txn, ContactId contactId,
ClientId clientId, int majorVersion) throws DbException;
interface ClientVersioningHook { interface ClientVersioningHook {
void onClientVisibilityChanging(Transaction txn, Contact c, void onClientVisibilityChanging(Transaction txn, Contact c,

View File

@@ -8,21 +8,17 @@ import java.io.File;
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.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger; 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;
@NotNullByDefault @NotNullByDefault
public class IoUtils { public class IoUtils {
private static final Logger LOG = getLogger(IoUtils.class.getName()); private static final Logger LOG = Logger.getLogger(IoUtils.class.getName());
public static void deleteFileOrDir(File f) { public static void deleteFileOrDir(File f) {
if (f.isFile()) { if (f.isFile()) {
@@ -58,35 +54,16 @@ public class IoUtils {
out.flush(); out.flush();
out.close(); out.close();
} catch (IOException e) { } catch (IOException e) {
tryToClose(in, LOG, WARNING); tryToClose(in);
tryToClose(out, LOG, WARNING); tryToClose(out);
} }
} }
public static void tryToClose(@Nullable Closeable c, Logger logger, private static void tryToClose(@Nullable Closeable c) {
Level level) {
try { try {
if (c != null) c.close(); if (c != null) c.close();
} catch (IOException e) { } catch (IOException e) {
logException(logger, level, e); // We did our best
}
}
public static void tryToClose(@Nullable Socket s, Logger logger,
Level level) {
try {
if (s != null) s.close();
} catch (IOException e) {
logException(logger, level, e);
}
}
public static void tryToClose(@Nullable ServerSocket ss, Logger logger,
Level level) {
try {
if (ss != null) ss.close();
} catch (IOException e) {
logException(logger, level, e);
} }
} }

View File

@@ -10,6 +10,8 @@ public class OsUtils {
@Nullable @Nullable
private static final String os = System.getProperty("os.name"); private static final String os = System.getProperty("os.name");
@Nullable @Nullable
private static final String version = System.getProperty("os.version");
@Nullable
private static final String vendor = System.getProperty("java.vendor"); private static final String vendor = System.getProperty("java.vendor");
public static boolean isWindows() { public static boolean isWindows() {

View File

@@ -47,7 +47,7 @@ public class StringUtils {
try { try {
return s.getBytes("UTF-8"); return s.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new AssertionError(e); throw new RuntimeException(e);
} }
} }
@@ -63,7 +63,7 @@ public class StringUtils {
try { try {
return decoder.decode(buffer).toString(); return decoder.decode(buffer).toString();
} catch (CharacterCodingException e) { } catch (CharacterCodingException e) {
throw new AssertionError(e); throw new RuntimeException(e);
} }
} }

View File

@@ -7,15 +7,13 @@ 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 = toUtf8(s).length; int length = StringUtils.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();
} }
@@ -23,7 +21,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 && toUtf8(s).length != length) if (s != null && StringUtils.toUtf8(s).length != length)
throw new FormatException(); throw new FormatException();
} }

View File

@@ -8,7 +8,6 @@ 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;
@@ -20,15 +19,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(singletonMap("foo", NULL_VALUE), assertEquals(Collections.singletonMap("foo", NULL_VALUE),
new BdfDictionary(singletonMap("foo", NULL_VALUE))); new BdfDictionary(Collections.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(singletonMap("foo", NULL_VALUE), assertEquals(Collections.singletonMap("foo", NULL_VALUE),
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE))); BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)));
} }
@@ -68,7 +67,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
} }
@Test @Test
public void testKeySetIteratorIsOrderedByKeys() { public void testKeySetIteratorIsOrderedByKeys() throws Exception {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("a", 1); d.put("a", 1);
d.put("d", 4); d.put("d", 4);
@@ -87,7 +86,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
} }
@Test @Test
public void testValuesIteratorIsOrderedByKeys() { public void testValuesIteratorIsOrderedByKeys() throws Exception {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("a", 1); d.put("a", 1);
d.put("d", 4); d.put("d", 4);
@@ -106,7 +105,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
} }
@Test @Test
public void testEntrySetIteratorIsOrderedByKeys() { public void testEntrySetIteratorIsOrderedByKeys() throws Exception {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("a", 1); d.put("a", 1);
d.put("d", 4); d.put("d", 4);

View File

@@ -5,31 +5,26 @@ 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.Random; import java.util.Arrays;
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(emptyList(), new BdfList()); assertEquals(Collections.emptyList(), new BdfList());
assertEquals(asList(1, 2, NULL_VALUE), assertEquals(Arrays.asList(1, 2, NULL_VALUE),
new BdfList(asList(1, 2, NULL_VALUE))); new BdfList(Arrays.asList(1, 2, NULL_VALUE)));
} }
@Test @Test
public void testFactoryMethod() { public void testFactoryMethod() {
assertEquals(emptyList(), BdfList.of()); assertEquals(Collections.emptyList(), BdfList.of());
assertEquals(asList(1, 2, NULL_VALUE), assertEquals(Arrays.asList(1, 2, NULL_VALUE),
BdfList.of(1, 2, NULL_VALUE)); BdfList.of(1, 2, NULL_VALUE));
} }
@@ -69,21 +64,22 @@ public class BdfListTest extends BrambleTestCase {
} }
@Test @Test
public void testIndexOutOfBoundsReturnsDefaultValue() { @SuppressWarnings("ConstantConditions")
public void testIndexOutOfBoundsReturnsDefaultValue() throws Exception {
BdfList list = BdfList.of(1, 2, 3); BdfList list = BdfList.of(1, 2, 3);
boolean defaultBoolean = random.nextBoolean(); boolean defaultBoolean = true;
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 = random.nextLong(); Long defaultLong = 123L;
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 = random.nextDouble(); Double defaultDouble = 1.23;
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 = getRandomString(123); String defaultString = "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 = getRandomBytes(123); byte[] defaultBytes = new byte[] {1, 2, 3};
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);
@@ -99,17 +95,18 @@ public class BdfListTest extends BrambleTestCase {
} }
@Test @Test
public void testWrongTypeReturnsDefaultValue() { @SuppressWarnings("ConstantConditions")
public void testWrongTypeReturnsDefaultValue() throws Exception {
BdfList list = BdfList.of(1, 2, 3, true); BdfList list = BdfList.of(1, 2, 3, true);
boolean defaultBoolean = random.nextBoolean(); boolean defaultBoolean = true;
assertEquals(defaultBoolean, list.getBoolean(0, defaultBoolean)); assertEquals(defaultBoolean, list.getBoolean(0, defaultBoolean));
Long defaultLong = random.nextLong(); Long defaultLong = 123L;
assertEquals(defaultLong, list.getLong(3, defaultLong)); assertEquals(defaultLong, list.getLong(3, defaultLong));
Double defaultDouble = random.nextDouble(); Double defaultDouble = 1.23;
assertEquals(defaultDouble, list.getDouble(0, defaultDouble)); assertEquals(defaultDouble, list.getDouble(0, defaultDouble));
String defaultString = getRandomString(123); String defaultString = "123";
assertEquals(defaultString, list.getString(0, defaultString)); assertEquals(defaultString, list.getString(0, defaultString));
byte[] defaultBytes = getRandomBytes(123); byte[] defaultBytes = new byte[] {1, 2, 3};
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));

View File

@@ -1,42 +0,0 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.NONE;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
public class AuthorInfoTest extends BrambleTestCase {
@Test
public void testEquals() {
assertEquals(
new AuthorInfo(NONE),
new AuthorInfo(NONE, null)
);
assertEquals(
new AuthorInfo(NONE, "test"),
new AuthorInfo(NONE, "test")
);
assertNotEquals(
new AuthorInfo(NONE),
new AuthorInfo(VERIFIED)
);
assertNotEquals(
new AuthorInfo(NONE, "test"),
new AuthorInfo(NONE)
);
assertNotEquals(
new AuthorInfo(NONE),
new AuthorInfo(NONE, "test")
);
assertNotEquals(
new AuthorInfo(NONE, "a"),
new AuthorInfo(NONE, "b")
);
}
}

View File

@@ -12,10 +12,12 @@ 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;
@@ -23,7 +25,6 @@ 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;
@@ -32,7 +33,6 @@ 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,10 +48,8 @@ public class TestUtils {
} }
public static void deleteTestDirectory(File testDir) { public static void deleteTestDirectory(File testDir) {
deleteFileOrDir(testDir); IoUtils.deleteFileOrDir(testDir);
// Delete parent directory only if it's empty testDir.getParentFile().delete(); // Delete if empty
//noinspection ResultOfMethodCallIgnored
testDir.getParentFile().delete();
} }
public static byte[] getRandomBytes(int length) { public static byte[] getRandomBytes(int length) {
@@ -147,7 +145,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());
sort(sorted); Collections.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;

View File

@@ -2,7 +2,7 @@ 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.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7', 'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939', 'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a', 'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d', 'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',

View File

@@ -3,10 +3,10 @@ sourceCompatibility = 1.8
targetCompatibility = 1.8 targetCompatibility = 1.8
apply plugin: 'ru.vyarus.animalsniffer' apply plugin: 'ru.vyarus.animalsniffer'
apply plugin: 'net.ltgt.apt'
apply plugin: 'idea' apply plugin: 'idea'
apply plugin: 'witness' apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
apply from: '../dagger.gradle'
dependencies { dependencies {
implementation project(path: ':bramble-api', configuration: 'default') implementation project(path: ':bramble-api', configuration: 'default')
@@ -17,7 +17,7 @@ dependencies {
implementation 'org.whispersystems:curve25519-java:0.5.0' implementation 'org.whispersystems:curve25519-java:0.5.0'
implementation 'org.briarproject:jtorctl:0.3' implementation 'org.briarproject:jtorctl:0.3'
annotationProcessor 'com.google.dagger:dagger-compiler:2.19' apt 'com.google.dagger:dagger-compiler:2.0.2'
testImplementation project(path: ':bramble-api', configuration: 'testOutput') testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation 'org.hsqldb:hsqldb:2.3.5' // The last version that supports Java 1.6 testImplementation 'org.hsqldb:hsqldb:2.3.5' // The last version that supports Java 1.6
@@ -25,8 +25,10 @@ dependencies {
testImplementation "org.jmock:jmock:2.8.2" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2" testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2" testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.19' testApt 'com.google.dagger:dagger-compiler:2.0.2'
signature 'org.codehaus.mojo.signature:java16:1.1@signature' signature 'org.codehaus.mojo.signature:java16:1.1@signature'
} }

View File

@@ -8,7 +8,7 @@ import org.briarproject.bramble.lifecycle.LifecycleModule;
import org.briarproject.bramble.plugin.PluginModule; import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.properties.PropertiesModule; import org.briarproject.bramble.properties.PropertiesModule;
import org.briarproject.bramble.reporting.ReportingModule; import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.sync.validation.ValidationModule; import org.briarproject.bramble.sync.SyncModule;
import org.briarproject.bramble.system.SystemModule; import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.transport.TransportModule; import org.briarproject.bramble.transport.TransportModule;
import org.briarproject.bramble.versioning.VersioningModule; import org.briarproject.bramble.versioning.VersioningModule;
@@ -31,11 +31,11 @@ public interface BrambleCoreEagerSingletons {
void inject(ReportingModule.EagerSingletons init); void inject(ReportingModule.EagerSingletons init);
void inject(SyncModule.EagerSingletons init);
void inject(SystemModule.EagerSingletons init); void inject(SystemModule.EagerSingletons init);
void inject(TransportModule.EagerSingletons init); void inject(TransportModule.EagerSingletons init);
void inject(ValidationModule.EagerSingletons init);
void inject(VersioningModule.EagerSingletons init); void inject(VersioningModule.EagerSingletons init);
} }

View File

@@ -19,7 +19,6 @@ import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.settings.SettingsModule; import org.briarproject.bramble.settings.SettingsModule;
import org.briarproject.bramble.socks.SocksModule; import org.briarproject.bramble.socks.SocksModule;
import org.briarproject.bramble.sync.SyncModule; import org.briarproject.bramble.sync.SyncModule;
import org.briarproject.bramble.sync.validation.ValidationModule;
import org.briarproject.bramble.system.SystemModule; import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.transport.TransportModule; import org.briarproject.bramble.transport.TransportModule;
import org.briarproject.bramble.versioning.VersioningModule; import org.briarproject.bramble.versioning.VersioningModule;
@@ -48,7 +47,6 @@ import dagger.Module;
SyncModule.class, SyncModule.class,
SystemModule.class, SystemModule.class,
TransportModule.class, TransportModule.class,
ValidationModule.class,
VersioningModule.class VersioningModule.class
}) })
public class BrambleCoreModule { public class BrambleCoreModule {
@@ -62,9 +60,9 @@ public class BrambleCoreModule {
c.inject(new PluginModule.EagerSingletons()); c.inject(new PluginModule.EagerSingletons());
c.inject(new PropertiesModule.EagerSingletons()); c.inject(new PropertiesModule.EagerSingletons());
c.inject(new ReportingModule.EagerSingletons()); c.inject(new ReportingModule.EagerSingletons());
c.inject(new SyncModule.EagerSingletons());
c.inject(new SystemModule.EagerSingletons()); c.inject(new SystemModule.EagerSingletons());
c.inject(new TransportModule.EagerSingletons()); c.inject(new TransportModule.EagerSingletons());
c.inject(new ValidationModule.EagerSingletons());
c.inject(new VersioningModule.EagerSingletons()); c.inject(new VersioningModule.EagerSingletons());
} }
} }

View File

@@ -10,7 +10,6 @@ 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;
/** /**
@@ -43,7 +42,7 @@ public class PoliteExecutor implements Executor {
int maxConcurrentTasks) { int maxConcurrentTasks) {
this.delegate = delegate; this.delegate = delegate;
this.maxConcurrentTasks = maxConcurrentTasks; this.maxConcurrentTasks = maxConcurrentTasks;
log = getLogger(tag); log = Logger.getLogger(tag);
} }
@Override @Override

View File

@@ -9,7 +9,6 @@ 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
@@ -23,7 +22,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 = getLogger(tag); log = Logger.getLogger(tag);
} }
@Override @Override

View File

@@ -6,7 +6,9 @@ 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.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
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;
@@ -17,21 +19,19 @@ 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;
@NotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault
class AccountManagerImpl implements AccountManager { class AccountManagerImpl implements AccountManager {
private static final Logger LOG = private static final Logger LOG =
getLogger(AccountManagerImpl.class.getName()); Logger.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;
} }
@GuardedBy("stateChangeLock") // Locking: 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;
} }
@GuardedBy("stateChangeLock") // Locking: 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 {
} }
} }
@GuardedBy("stateChangeLock") // Locking: stateChangeLock
boolean storeEncryptedDatabaseKey(String hex) { protected 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 {
} }
} }
@GuardedBy("stateChangeLock") // Locking: 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 {
} }
} }
@GuardedBy("stateChangeLock") // Locking: 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");
deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory()); IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
deleteFileOrDir(databaseConfig.getDatabaseDirectory()); IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
databaseKey = null; databaseKey = null;
} }
} }
@@ -197,7 +197,7 @@ class AccountManagerImpl implements AccountManager {
} }
} }
@GuardedBy("stateChangeLock") // Locking: stateChangeLock
@Nullable @Nullable
private SecretKey loadAndDecryptDatabaseKey(String password) { private SecretKey loadAndDecryptDatabaseKey(String password) {
String hex = loadEncryptedDatabaseKey(); String hex = loadEncryptedDatabaseKey();

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.battery;
import org.briarproject.bramble.api.battery.BatteryManager;
import dagger.Module;
import dagger.Provides;
/**
* Provides a default implementation of {@link BatteryManager} for systems
* without batteries.
*/
@Module
public class DefaultBatteryManagerModule {
@Provides
BatteryManager provideBatteryManager() {
return () -> false;
}
}

View File

@@ -82,7 +82,13 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public void addLocalMessage(Message m, BdfDictionary metadata, public void addLocalMessage(Message m, BdfDictionary metadata,
boolean shared) throws DbException, FormatException { boolean shared) throws DbException, FormatException {
db.transaction(false, txn -> addLocalMessage(txn, m, metadata, shared)); Transaction txn = db.startTransaction(false);
try {
addLocalMessage(txn, m, metadata, shared);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -107,7 +113,15 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public Message getMessage(MessageId m) throws DbException { public Message getMessage(MessageId m) throws DbException {
return db.transactionWithResult(true, txn -> getMessage(txn, m)); Message message;
Transaction txn = db.startTransaction(true);
try {
message = getMessage(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return message;
} }
@Override @Override
@@ -118,7 +132,15 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfList getMessageAsList(MessageId m) throws DbException, public BdfList getMessageAsList(MessageId m) throws DbException,
FormatException { FormatException {
return db.transactionWithResult(true, txn -> getMessageAsList(txn, m)); BdfList list;
Transaction txn = db.startTransaction(true);
try {
list = getMessageAsList(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return list;
} }
@Override @Override
@@ -130,8 +152,15 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfDictionary getGroupMetadataAsDictionary(GroupId g) public BdfDictionary getGroupMetadataAsDictionary(GroupId g)
throws DbException, FormatException { throws DbException, FormatException {
return db.transactionWithResult(true, txn -> BdfDictionary dictionary;
getGroupMetadataAsDictionary(txn, g)); Transaction txn = db.startTransaction(true);
try {
dictionary = getGroupMetadataAsDictionary(txn, g);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return dictionary;
} }
@Override @Override
@@ -144,8 +173,15 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfDictionary getMessageMetadataAsDictionary(MessageId m) public BdfDictionary getMessageMetadataAsDictionary(MessageId m)
throws DbException, FormatException { throws DbException, FormatException {
return db.transactionWithResult(true, txn -> BdfDictionary dictionary;
getMessageMetadataAsDictionary(txn, m)); Transaction txn = db.startTransaction(true);
try {
dictionary = getMessageMetadataAsDictionary(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return dictionary;
} }
@Override @Override
@@ -158,8 +194,15 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary( public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
GroupId g) throws DbException, FormatException { GroupId g) throws DbException, FormatException {
return db.transactionWithResult(true, txn -> Map<MessageId, BdfDictionary> map;
getMessageMetadataAsDictionary(txn, g)); Transaction txn = db.startTransaction(true);
try {
map = getMessageMetadataAsDictionary(txn, g);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return map;
} }
@Override @Override
@@ -176,8 +219,15 @@ class ClientHelperImpl implements ClientHelper {
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary( public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
GroupId g, BdfDictionary query) throws DbException, GroupId g, BdfDictionary query) throws DbException,
FormatException { FormatException {
return db.transactionWithResult(true, txn -> Map<MessageId, BdfDictionary> map;
getMessageMetadataAsDictionary(txn, g, query)); Transaction txn = db.startTransaction(true);
try {
map = getMessageMetadataAsDictionary(txn, g, query);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return map;
} }
@Override @Override
@@ -195,7 +245,13 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public void mergeGroupMetadata(GroupId g, BdfDictionary metadata) public void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
throws DbException, FormatException { throws DbException, FormatException {
db.transaction(false, txn -> mergeGroupMetadata(txn, g, metadata)); Transaction txn = db.startTransaction(false);
try {
mergeGroupMetadata(txn, g, metadata);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -207,7 +263,13 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public void mergeMessageMetadata(MessageId m, BdfDictionary metadata) public void mergeMessageMetadata(MessageId m, BdfDictionary metadata)
throws DbException, FormatException { throws DbException, FormatException {
db.transaction(false, txn -> mergeMessageMetadata(txn, m, metadata)); Transaction txn = db.startTransaction(false);
try {
mergeMessageMetadata(txn, m, metadata);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override

View File

@@ -13,6 +13,7 @@ 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.db.Transaction;
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;
@@ -43,7 +44,6 @@ 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;
@@ -55,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 =
getLogger(ContactExchangeTaskImpl.class.getName()); Logger.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";
@@ -158,8 +158,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
streamWriterFactory.createContactExchangeStreamWriter(out, streamWriterFactory.createContactExchangeStreamWriter(out,
alice ? aliceHeaderKey : bobHeaderKey); alice ? aliceHeaderKey : bobHeaderKey);
RecordWriter recordWriter = RecordWriter recordWriter =
recordWriterFactory recordWriterFactory.createRecordWriter(streamWriter.getOutputStream());
.createRecordWriter(streamWriter.getOutputStream());
// Derive the nonces to be signed // Derive the nonces to be signed
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret, byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
@@ -191,7 +190,6 @@ 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");
@@ -289,14 +287,19 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
private ContactId addContact(Author remoteAuthor, long timestamp, private ContactId addContact(Author remoteAuthor, long timestamp,
Map<TransportId, TransportProperties> remoteProperties) Map<TransportId, TransportProperties> remoteProperties)
throws DbException { throws DbException {
return db.transactionWithResult(false, txn -> { ContactId contactId;
ContactId contactId = contactManager.addContact(txn, remoteAuthor, Transaction txn = db.startTransaction(false);
try {
contactId = contactManager.addContact(txn, remoteAuthor,
localAuthor.getId(), masterSecret, timestamp, alice, localAuthor.getId(), masterSecret, timestamp, alice,
true, true); true, true);
transportPropertyManager.addRemoteProperties(txn, contactId, transportPropertyManager.addRemoteProperties(txn, contactId,
remoteProperties); remoteProperties);
return contactId; db.commitTransaction(txn);
}); } finally {
db.endTransaction(txn);
}
return contactId;
} }
private void tryToClose(DuplexTransportConnection conn) { private void tryToClose(DuplexTransportConnection conn) {

View File

@@ -3,8 +3,6 @@ package org.briarproject.bramble.contact;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
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.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
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;
@@ -12,53 +10,29 @@ import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.identity.IdentityManager;
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.transport.KeyManager; import org.briarproject.bramble.api.transport.KeyManager;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Pattern;
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.emptyList;
import static org.briarproject.bramble.api.contact.PendingContact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNVERIFIED;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
@ThreadSafe @ThreadSafe
@NotNullByDefault @NotNullByDefault
class ContactManagerImpl implements ContactManager { class ContactManagerImpl implements ContactManager {
private static final int LINK_LENGTH = 64;
private static final String REMOTE_CONTACT_LINK =
"briar://" + getRandomBase32String(LINK_LENGTH);
private static final Pattern LINK_REGEX =
Pattern.compile("(briar://)?([a-z2-7]{" + LINK_LENGTH + "})");
private final DatabaseComponent db; private final DatabaseComponent db;
private final KeyManager keyManager; private final KeyManager keyManager;
private final IdentityManager identityManager;
private final List<ContactHook> hooks; private final List<ContactHook> hooks;
@Inject @Inject
ContactManagerImpl(DatabaseComponent db, KeyManager keyManager, ContactManagerImpl(DatabaseComponent db, KeyManager keyManager) {
IdentityManager identityManager) {
this.db = db; this.db = db;
this.keyManager = keyManager; this.keyManager = keyManager;
this.identityManager = identityManager;
hooks = new CopyOnWriteArrayList<>(); hooks = new CopyOnWriteArrayList<>();
} }
@@ -91,63 +65,42 @@ class ContactManagerImpl implements ContactManager {
public ContactId addContact(Author remote, AuthorId local, SecretKey master, public ContactId addContact(Author remote, AuthorId local, SecretKey master,
long timestamp, boolean alice, boolean verified, boolean active) long timestamp, boolean alice, boolean verified, boolean active)
throws DbException { throws DbException {
return db.transactionWithResult(false, txn -> ContactId c;
addContact(txn, remote, local, master, timestamp, alice, Transaction txn = db.startTransaction(false);
verified, active)); try {
} c = addContact(txn, remote, local, master, timestamp, alice,
verified, active);
@Override db.commitTransaction(txn);
public String getRemoteContactLink() { } finally {
// TODO replace with real implementation db.endTransaction(txn);
return REMOTE_CONTACT_LINK;
}
@SuppressWarnings("SameParameterValue")
private static String getRandomBase32String(int length) {
Random random = new Random();
char[] c = new char[length];
for (int i = 0; i < length; i++) {
int character = random.nextInt(32);
if (character < 26) c[i] = (char) ('a' + character);
else c[i] = (char) ('2' + (character - 26));
} }
return new String(c); return c;
}
@Override
public boolean isValidRemoteContactLink(String link) {
return LINK_REGEX.matcher(link).matches();
}
@Override
public PendingContact addRemoteContactRequest(String link, String alias) {
// TODO replace with real implementation
PendingContactId id = new PendingContactId(link.getBytes());
return new PendingContact(id, alias, WAITING_FOR_CONNECTION,
System.currentTimeMillis());
}
@Override
public Collection<PendingContact> getPendingContacts() {
// TODO replace with real implementation
return emptyList();
}
@Override
public void removePendingContact(PendingContact pendingContact) {
// TODO replace with real implementation
} }
@Override @Override
public Contact getContact(ContactId c) throws DbException { public Contact getContact(ContactId c) throws DbException {
return db.transactionWithResult(true, txn -> db.getContact(txn, c)); Contact contact;
Transaction txn = db.startTransaction(true);
try {
contact = db.getContact(txn, c);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return contact;
} }
@Override @Override
public Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId) public Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException { throws DbException {
return db.transactionWithResult(true, txn -> Transaction txn = db.startTransaction(true);
getContact(txn, remoteAuthorId, localAuthorId)); try {
Contact c = getContact(txn, remoteAuthorId, localAuthorId);
db.commitTransaction(txn);
return c;
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -165,8 +118,14 @@ class ContactManagerImpl implements ContactManager {
@Override @Override
public Collection<Contact> getActiveContacts() throws DbException { public Collection<Contact> getActiveContacts() throws DbException {
Collection<Contact> contacts = Collection<Contact> contacts;
db.transactionWithResult(true, db::getContacts); Transaction txn = db.startTransaction(true);
try {
contacts = db.getContacts(txn);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
List<Contact> active = new ArrayList<>(contacts.size()); List<Contact> active = new ArrayList<>(contacts.size());
for (Contact c : contacts) if (c.isActive()) active.add(c); for (Contact c : contacts) if (c.isActive()) active.add(c);
return active; return active;
@@ -174,7 +133,13 @@ class ContactManagerImpl implements ContactManager {
@Override @Override
public void removeContact(ContactId c) throws DbException { public void removeContact(ContactId c) throws DbException {
db.transaction(false, txn -> removeContact(txn, c)); Transaction txn = db.startTransaction(false);
try {
removeContact(txn, c);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
} }
@Override @Override
@@ -183,23 +148,6 @@ class ContactManagerImpl implements ContactManager {
db.setContactActive(txn, c, active); db.setContactActive(txn, c, active);
} }
@Override
public void setContactAlias(Transaction txn, ContactId c,
@Nullable String alias) throws DbException {
if (alias != null) {
int aliasLength = toUtf8(alias).length;
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException();
}
db.setContactAlias(txn, c, alias);
}
@Override
public void setContactAlias(ContactId c, @Nullable String alias)
throws DbException {
db.transaction(false, txn -> setContactAlias(txn, c, alias));
}
@Override @Override
public boolean contactExists(Transaction txn, AuthorId remoteAuthorId, public boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
AuthorId localAuthorId) throws DbException { AuthorId localAuthorId) throws DbException {
@@ -209,8 +157,15 @@ class ContactManagerImpl implements ContactManager {
@Override @Override
public boolean contactExists(AuthorId remoteAuthorId, public boolean contactExists(AuthorId remoteAuthorId,
AuthorId localAuthorId) throws DbException { AuthorId localAuthorId) throws DbException {
return db.transactionWithResult(true, txn -> boolean exists;
contactExists(txn, remoteAuthorId, localAuthorId)); Transaction txn = db.startTransaction(true);
try {
exists = contactExists(txn, remoteAuthorId, localAuthorId);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return exists;
} }
@Override @Override
@@ -221,23 +176,4 @@ class ContactManagerImpl implements ContactManager {
db.removeContact(txn, c); db.removeContact(txn, c);
} }
@Override
public AuthorInfo getAuthorInfo(AuthorId a) throws DbException {
return db.transactionWithResult(true, txn -> getAuthorInfo(txn, a));
}
@Override
public AuthorInfo getAuthorInfo(Transaction txn, AuthorId authorId)
throws DbException {
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
if (localAuthor.getId().equals(authorId))
return new AuthorInfo(OURSELVES);
Collection<Contact> contacts = db.getContactsByAuthorId(txn, authorId);
if (contacts.isEmpty()) return new AuthorInfo(UNKNOWN);
if (contacts.size() > 1) throw new AssertionError();
Contact c = contacts.iterator().next();
if (c.isVerified()) return new AuthorInfo(VERIFIED, c.getAlias());
else return new AuthorInfo(UNVERIFIED, c.getAlias());
}
} }

View File

@@ -2,20 +2,18 @@ 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 = toHexString(b); String wrapped = StringUtils.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, i, end); s.append(wrapped.substring(i, end));
s.append("\r\n"); s.append("\r\n");
} }
return s.toString(); return s.toString();
@@ -23,7 +21,7 @@ class AsciiArmour {
static byte[] unwrap(String s) throws FormatException { static byte[] unwrap(String s) throws FormatException {
try { try {
return fromHexString(s.replaceAll("[^0-9a-fA-F]", "")); return StringUtils.fromHexString(s.replaceAll("[^0-9a-fA-F]", ""));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new FormatException(); throw new FormatException();
} }

View File

@@ -12,6 +12,8 @@ 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;
@@ -28,21 +30,16 @@ 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 =
getLogger(CryptoComponentImpl.class.getName()); Logger.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
@@ -191,7 +188,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);
arraycopy(inputs, 0, hashInputs, 1, inputs.length); System.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);
@@ -219,26 +216,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 = toUtf8(label); byte[] labelBytes = StringUtils.toUtf8(label);
byte[] length = new byte[INT_32_BYTES]; byte[] length = new byte[INT_32_BYTES];
writeUint32(labelBytes.length, length, 0); ByteUtils.writeUint32(labelBytes.length, length, 0);
signature.update(length); signature.update(length);
signature.update(labelBytes); signature.update(labelBytes);
writeUint32(toSign.length, length, 0); ByteUtils.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 = toUtf8(label); byte[] labelBytes = StringUtils.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];
writeUint32(labelBytes.length, length, 0); ByteUtils.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) {
writeUint32(input.length, length, 0); ByteUtils.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);
} }
@@ -249,14 +246,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 = toUtf8(label); byte[] labelBytes = StringUtils.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];
writeUint32(labelBytes.length, length, 0); ByteUtils.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) {
writeUint32(input.length, length, 0); ByteUtils.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);
} }
@@ -300,13 +297,13 @@ class CryptoComponentImpl implements CryptoComponent {
output[outputOff] = PBKDF_FORMAT_SCRYPT; output[outputOff] = PBKDF_FORMAT_SCRYPT;
outputOff++; outputOff++;
// Salt // Salt
arraycopy(salt, 0, output, outputOff, salt.length); System.arraycopy(salt, 0, output, outputOff, salt.length);
outputOff += salt.length; outputOff += salt.length;
// Cost parameter // Cost parameter
writeUint32(cost, output, outputOff); ByteUtils.writeUint32(cost, output, outputOff);
outputOff += INT_32_BYTES; outputOff += INT_32_BYTES;
// IV // IV
arraycopy(iv, 0, output, outputOff, iv.length); System.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 {
@@ -336,16 +333,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];
arraycopy(input, inputOff, salt, 0, salt.length); System.arraycopy(input, inputOff, salt, 0, salt.length);
inputOff += salt.length; inputOff += salt.length;
// Cost parameter // Cost parameter
long cost = readUint32(input, inputOff); long cost = ByteUtils.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];
arraycopy(input, inputOff, iv, 0, iv.length); System.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);

View File

@@ -7,8 +7,6 @@ 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 {
@@ -28,7 +26,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];
arraycopy(b, 0, clamped, 0, 32); System.arraycopy(b, 0, clamped, 0, 32);
clamped[0] &= 248; clamped[0] &= 248;
clamped[31] &= 127; clamped[31] &= 127;
clamped[31] |= 64; clamped[31] |= 64;

View File

@@ -1,15 +1,13 @@
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 {
@@ -18,7 +16,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();
writeUint64(frameNumber, dest, 0); ByteUtils.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;
} }
@@ -31,8 +29,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();
writeUint16(payloadLength, dest, 0); ByteUtils.writeUint16(payloadLength, dest, 0);
writeUint16(paddingLength, dest, INT_16_BYTES); ByteUtils.writeUint16(paddingLength, dest, INT_16_BYTES);
if (finalFrame) dest[0] |= 0x80; if (finalFrame) dest[0] |= 0x80;
} }
@@ -45,12 +43,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 readUint16(header, 0) & 0x7FFF; return ByteUtils.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 readUint16(header, INT_16_BYTES); return ByteUtils.readUint16(header, INT_16_BYTES);
} }
} }

View File

@@ -8,7 +8,6 @@ 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 {
@@ -25,7 +24,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];
arraycopy(hash, 0, commitment, 0, COMMIT_LENGTH); System.arraycopy(hash, 0, commitment, 0, COMMIT_LENGTH);
return commitment; return commitment;
} }

View File

@@ -5,6 +5,7 @@ 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;
@@ -44,9 +45,6 @@ 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 {
@@ -159,7 +157,6 @@ 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();
@@ -213,11 +210,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(toHexString(keyPair.getPublic().getEncoded())); out.print(StringUtils.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(toHexString(keyPair.getPrivate().getEncoded())); out.print(StringUtils.toHexString(keyPair.getPrivate().getEncoded()));
out.flush(); out.flush();
out.close(); out.close();
} }
@@ -226,7 +223,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 = fromHexString(readFully(in).trim()); byte[] keyBytes = StringUtils.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);
@@ -239,7 +236,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 = fromHexString(readFully(in).trim()); byte[] keyBytes = StringUtils.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));

View File

@@ -2,6 +2,7 @@ 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;
@@ -9,14 +10,13 @@ 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 = getLogger(ScryptKdf.class.getName()); private static final Logger LOG =
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 = toUtf8(password); byte[] passwordBytes = StringUtils.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);

View File

@@ -16,8 +16,6 @@ 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;
@@ -30,7 +28,8 @@ import static org.briarproject.bramble.util.LogUtils.now;
@NotNullByDefault @NotNullByDefault
class Sec1KeyParser implements KeyParser { class Sec1KeyParser implements KeyParser {
private static final Logger LOG = getLogger(Sec1KeyParser.class.getName()); private static final Logger LOG =
Logger.getLogger(Sec1KeyParser.class.getName());
private final ECDomainParameters params; private final ECDomainParameters params;
private final BigInteger modulus; private final BigInteger modulus;
@@ -57,12 +56,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];
arraycopy(encodedKey, 1, xBytes, 0, bytesPerInt); System.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];
arraycopy(encodedKey, 1 + bytesPerInt, yBytes, 0, bytesPerInt); System.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)

View File

@@ -2,8 +2,6 @@ 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 {
@@ -12,10 +10,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;
arraycopy(src, 0, dest, destOff + padding, src.length); System.arraycopy(src, 0, dest, destOff + padding, src.length);
} else { } else {
int srcOff = src.length - destLen; int srcOff = src.length - destLen;
arraycopy(src, srcOff, dest, destOff, destLen); System.arraycopy(src, srcOff, dest, destOff, destLen);
} }
} }
} }

View File

@@ -4,6 +4,7 @@ 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;
@@ -13,7 +14,6 @@ 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,8 +26,6 @@ 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
@@ -132,7 +130,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];
arraycopy(streamHeaderCiphertext, 0, streamHeaderNonce, 0, System.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 {
@@ -147,16 +145,17 @@ class StreamDecrypterImpl implements StreamDecrypter {
throw new FormatException(); throw new FormatException();
} }
// Check the protocol version // Check the protocol version
int receivedProtocolVersion = readUint16(streamHeaderPlaintext, 0); int receivedProtocolVersion =
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 = readUint64(streamHeaderPlaintext, long receivedStreamNumber = ByteUtils.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];
arraycopy(streamHeaderPlaintext, INT_16_BYTES + INT_64_BYTES, System.arraycopy(streamHeaderPlaintext, INT_16_BYTES + INT_64_BYTES,
frameKeyBytes, 0, SecretKey.LENGTH); frameKeyBytes, 0, SecretKey.LENGTH);
frameKey = new SecretKey(frameKeyBytes); frameKey = new SecretKey(frameKeyBytes);
} }

View File

@@ -3,6 +3,7 @@ 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;
@@ -11,7 +12,6 @@ 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,8 +24,6 @@ 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
@@ -90,7 +88,7 @@ class StreamEncrypterImpl implements StreamEncrypter {
throw new RuntimeException(badCipher); throw new RuntimeException(badCipher);
} }
// Combine the payload and padding // Combine the payload and padding
arraycopy(payload, 0, framePlaintext, 0, payloadLength); System.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
@@ -120,12 +118,13 @@ 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];
writeUint16(PROTOCOL_VERSION, streamHeaderPlaintext, 0); ByteUtils.writeUint16(PROTOCOL_VERSION, streamHeaderPlaintext, 0);
writeUint64(streamNumber, streamHeaderPlaintext, INT_16_BYTES); ByteUtils.writeUint64(streamNumber, streamHeaderPlaintext,
arraycopy(frameKey.getBytes(), 0, streamHeaderPlaintext, INT_16_BYTES);
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];
arraycopy(streamHeaderNonce, 0, streamHeaderCiphertext, 0, System.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 {

View File

@@ -7,12 +7,13 @@ 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;
@@ -23,9 +24,6 @@ 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 {
@@ -93,21 +91,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];
writeUint64(rotationPeriod, period, 0); ByteUtils.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 = toUtf8(t.getString()); byte[] id = StringUtils.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 = toUtf8(t.getString()); byte[] id = StringUtils.toUtf8(t.getString());
return crypto.deriveKey(label, master, id); return crypto.deriveKey(label, master, id);
} }
@@ -127,14 +125,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];
writeUint16(protocolVersion, protocolVersionBytes, 0); ByteUtils.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];
writeUint64(streamNumber, streamNumberBytes, 0); ByteUtils.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
arraycopy(mac, 0, tag, 0, TAG_LENGTH); System.arraycopy(mac, 0, tag, 0, TAG_LENGTH);
} }
} }

View File

@@ -29,7 +29,6 @@ import static org.briarproject.bramble.data.Types.STRING_16;
import static org.briarproject.bramble.data.Types.STRING_32; import static org.briarproject.bramble.data.Types.STRING_32;
import static org.briarproject.bramble.data.Types.STRING_8; import static org.briarproject.bramble.data.Types.STRING_8;
import static org.briarproject.bramble.data.Types.TRUE; import static org.briarproject.bramble.data.Types.TRUE;
import static org.briarproject.bramble.util.StringUtils.fromUtf8;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
@@ -254,7 +253,7 @@ class BdfReaderImpl implements BdfReader {
if (length < 0 || length > maxBufferSize) throw new FormatException(); if (length < 0 || length > maxBufferSize) throw new FormatException();
if (length == 0) return ""; if (length == 0) return "";
readIntoBuffer(length); readIntoBuffer(length);
return fromUtf8(buf, 0, length); return new String(buf, 0, length, "UTF-8");
} }
private int readStringLength() throws IOException { private int readStringLength() throws IOException {

View File

@@ -22,7 +22,7 @@ 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.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.sync.ValidationManager.State;
import org.briarproject.bramble.api.transport.KeySet; import org.briarproject.bramble.api.transport.KeySet;
import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.api.transport.TransportKeys;
@@ -106,7 +106,7 @@ interface Database<T> {
* @param sender the contact from whom the message was received, or null * @param sender the contact from whom the message was received, or null
* if the message was created locally. * if the message was created locally.
*/ */
void addMessage(T txn, Message m, MessageState state, boolean shared, void addMessage(T txn, Message m, State state, boolean shared,
@Nullable ContactId sender) throws DbException; @Nullable ContactId sender) throws DbException;
/** /**
@@ -114,7 +114,7 @@ interface Database<T> {
* in the given state. * in the given state.
*/ */
void addMessageDependency(T txn, Message dependent, MessageId dependency, void addMessageDependency(T txn, Message dependent, MessageId dependency,
MessageState dependentState) throws DbException; State dependentState) throws DbException;
/** /**
* Records that a message has been offered by the given contact. * Records that a message has been offered by the given contact.
@@ -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(); long getFreeSpace() throws DbException;
/** /**
* Returns the group with the given ID. * Returns the group with the given ID.
@@ -310,11 +310,11 @@ interface Database<T> {
/** /**
* Returns the IDs and states of all dependencies of the given message. * Returns the IDs and states of all dependencies of the given message.
* For missing dependencies and dependencies in other groups, the state * For missing dependencies and dependencies in other groups, the state
* {@link MessageState UNKNOWN} is returned. * {@link State UNKNOWN} is returned.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
Map<MessageId, MessageState> getMessageDependencies(T txn, MessageId m) Map<MessageId, State> getMessageDependencies(T txn, MessageId m)
throws DbException; throws DbException;
/** /**
@@ -324,7 +324,7 @@ interface Database<T> {
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
Map<MessageId, MessageState> getMessageDependents(T txn, MessageId m) Map<MessageId, State> getMessageDependents(T txn, MessageId m)
throws DbException; throws DbException;
/** /**
@@ -383,7 +383,7 @@ interface Database<T> {
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
MessageState getMessageState(T txn, MessageId m) throws DbException; State getMessageState(T txn, MessageId m) throws DbException;
/** /**
* Returns the status of all delivered messages in the given group with * Returns the status of all delivered messages in the given group with
@@ -616,12 +616,6 @@ interface Database<T> {
void setContactActive(T txn, ContactId c, boolean active) void setContactActive(T txn, ContactId c, boolean active)
throws DbException; throws DbException;
/**
* Sets an alias name for a contact.
*/
void setContactAlias(T txn, ContactId c, @Nullable String alias)
throws DbException;
/** /**
* Sets the given group's visibility to the given contact to either * Sets the given group's visibility to the given contact to either
* {@link Visibility VISIBLE} or {@link Visibility SHARED}. * {@link Visibility VISIBLE} or {@link Visibility SHARED}.
@@ -637,8 +631,7 @@ interface Database<T> {
/** /**
* Sets the validation and delivery state of the given message. * Sets the validation and delivery state of the given message.
*/ */
void setMessageState(T txn, MessageId m, MessageState state) void setMessageState(T txn, MessageId m, State state) throws DbException;
throws DbException;
/** /**
* Sets the reordering window for the given key set and transport in the * Sets the reordering window for the given key set and transport in the

View File

@@ -19,7 +19,6 @@ import org.briarproject.bramble.api.db.NoSuchGroupException;
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException; import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
import org.briarproject.bramble.api.db.NoSuchMessageException; import org.briarproject.bramble.api.db.NoSuchMessageException;
import org.briarproject.bramble.api.db.NoSuchTransportException; import org.briarproject.bramble.api.db.NoSuchTransportException;
import org.briarproject.bramble.api.db.NullableDbCallable;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
@@ -43,6 +42,7 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.ValidationManager.State;
import org.briarproject.bramble.api.sync.event.GroupAddedEvent; import org.briarproject.bramble.api.sync.event.GroupAddedEvent;
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent; import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent; import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent;
@@ -54,13 +54,13 @@ import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent; import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
import org.briarproject.bramble.api.sync.event.MessagesSentEvent; import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.KeySet; import org.briarproject.bramble.api.transport.KeySet;
import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeys; 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;
@@ -71,13 +71,11 @@ 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.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN; import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES; import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
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;
@@ -88,7 +86,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 =
getLogger(DatabaseComponentImpl.class.getName()); Logger.getLogger(DatabaseComponentImpl.class.getName());
private final Database<T> db; private final Database<T> db;
private final Class<T> txnClass; private final Class<T> txnClass;
@@ -195,20 +193,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
} }
@Override
public <R, E extends Exception> R transactionWithNullableResult(
boolean readOnly, NullableDbCallable<R, E> task)
throws DbException, E {
Transaction txn = startTransaction(readOnly);
try {
R result = task.call(txn);
commitTransaction(txn);
return result;
} finally {
endTransaction(txn);
}
}
private T unbox(Transaction transaction) { private T unbox(Transaction transaction) {
if (transaction.isCommitted()) throw new IllegalStateException(); if (transaction.isCommitted()) throw new IllegalStateException();
return txnClass.cast(transaction.unbox()); return txnClass.cast(transaction.unbox());
@@ -580,7 +564,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
@Override @Override
public MessageState getMessageState(Transaction transaction, MessageId m) public State getMessageState(Transaction transaction, MessageId m)
throws DbException { throws DbException {
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsMessage(txn, m)) if (!db.containsMessage(txn, m))
@@ -620,8 +604,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
@Override @Override
public Map<MessageId, MessageState> getMessageDependencies( public Map<MessageId, State> getMessageDependencies(Transaction transaction,
Transaction transaction, MessageId m) throws DbException { MessageId m) throws DbException {
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsMessage(txn, m)) if (!db.containsMessage(txn, m))
throw new NoSuchMessageException(); throw new NoSuchMessageException();
@@ -629,8 +613,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
@Override @Override
public Map<MessageId, MessageState> getMessageDependents( public Map<MessageId, State> getMessageDependents(Transaction transaction,
Transaction transaction, MessageId m) throws DbException { MessageId m) throws DbException {
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsMessage(txn, m)) if (!db.containsMessage(txn, m))
throw new NoSuchMessageException(); throw new NoSuchMessageException();
@@ -875,16 +859,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
transaction.attach(new ContactStatusChangedEvent(c, active)); transaction.attach(new ContactStatusChangedEvent(c, active));
} }
@Override
public void setContactAlias(Transaction transaction, ContactId c,
@Nullable String alias) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
db.setContactAlias(txn, c, alias);
}
@Override @Override
public void setGroupVisibility(Transaction transaction, ContactId c, public void setGroupVisibility(Transaction transaction, ContactId c,
GroupId g, Visibility v) throws DbException { GroupId g, Visibility v) throws DbException {
@@ -899,7 +873,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 = singletonList(c); List<ContactId> affected = Collections.singletonList(c);
transaction.attach(new GroupVisibilityUpdatedEvent(affected)); transaction.attach(new GroupVisibilityUpdatedEvent(affected));
} }
@@ -919,7 +893,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Override @Override
public void setMessageState(Transaction transaction, MessageId m, public void setMessageState(Transaction transaction, MessageId m,
MessageState state) throws DbException { State state) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException(); if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsMessage(txn, m)) if (!db.containsMessage(txn, m))
@@ -936,10 +910,10 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsMessage(txn, dependent.getId())) if (!db.containsMessage(txn, dependent.getId()))
throw new NoSuchMessageException(); throw new NoSuchMessageException();
MessageState dependentState = State dependentState = db.getMessageState(txn, dependent.getId());
db.getMessageState(txn, dependent.getId());
for (MessageId dependency : dependencies) { for (MessageId dependency : dependencies) {
db.addMessageDependency(txn, dependent, dependency, dependentState); db.addMessageDependency(txn, dependent, dependency,
dependentState);
} }
} }

View File

@@ -1,34 +0,0 @@
package org.briarproject.bramble.db;
class DatabaseTypes {
private final String hashType, secretType, binaryType;
private final String counterType, stringType;
public DatabaseTypes(String hashType, String secretType, String binaryType,
String counterType, String stringType) {
this.hashType = hashType;
this.secretType = secretType;
this.binaryType = binaryType;
this.counterType = counterType;
this.stringType = stringType;
}
/**
* Replaces database type placeholders in a statement with the actual types.
* These placeholders are currently supported:
* <li> _HASH
* <li> _SECRET
* <li> _BINARY
* <li> _COUNTER
* <li> _STRING
*/
String replaceTypes(String s) {
s = s.replaceAll("_HASH", hashType);
s = s.replaceAll("_SECRET", secretType);
s = s.replaceAll("_BINARY", binaryType);
s = s.replaceAll("_COUNTER", counterType);
s = s.replaceAll("_STRING", stringType);
return s;
}
}

View File

@@ -7,6 +7,7 @@ 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;
@@ -14,31 +15,21 @@ import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
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.util.StringUtils.toHexString;
/** /**
* Contains all the H2-specific code for the database. * Contains all the H2-specific code for the database.
*/ */
@NotNullByDefault @NotNullByDefault
class H2Database extends JdbcDatabase { class H2Database extends JdbcDatabase {
private static final Logger LOG = getLogger(H2Database.class.getName());
private static final String HASH_TYPE = "BINARY(32)"; private static final String HASH_TYPE = "BINARY(32)";
private static final String SECRET_TYPE = "BINARY(32)"; private static final String SECRET_TYPE = "BINARY(32)";
private static final String BINARY_TYPE = "BINARY"; private static final String BINARY_TYPE = "BINARY";
private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT"; private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT";
private static final String STRING_TYPE = "VARCHAR"; private static final String STRING_TYPE = "VARCHAR";
private static final DatabaseTypes dbTypes = new DatabaseTypes(HASH_TYPE,
SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE);
private final DatabaseConfig config; private final DatabaseConfig config;
private final String url; private final String url;
@@ -49,7 +40,8 @@ class H2Database extends JdbcDatabase {
@Inject @Inject
H2Database(DatabaseConfig config, MessageFactory messageFactory, H2Database(DatabaseConfig config, MessageFactory messageFactory,
Clock clock) { Clock clock) {
super(dbTypes, messageFactory, clock); super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
messageFactory, clock);
this.config = config; this.config = config;
File dir = config.getDatabaseDirectory(); File dir = config.getDatabaseDirectory();
String path = new File(dir, "db").getAbsolutePath(); String path = new File(dir, "db").getAbsolutePath();
@@ -107,7 +99,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 = toHexString(key.getBytes()); String hex = StringUtils.toHexString(key.getBytes());
props.put("password", hex + " password"); props.put("password", hex + " password");
return DriverManager.getConnection(getUrl(), props); return DriverManager.getConnection(getUrl(), props);
} }
@@ -128,8 +120,8 @@ class H2Database extends JdbcDatabase {
s.close(); s.close();
c.close(); c.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s);
tryToClose(c, LOG, WARNING); tryToClose(c);
throw new DbException(e); throw new DbException(e);
} }
} }

View File

@@ -7,39 +7,29 @@ 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;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
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.util.StringUtils.toHexString;
/** /**
* Contains all the HSQLDB-specific code for the database. * Contains all the HSQLDB-specific code for the database.
*/ */
@NotNullByDefault @NotNullByDefault
class HyperSqlDatabase extends JdbcDatabase { class HyperSqlDatabase extends JdbcDatabase {
private static final Logger LOG =
getLogger(HyperSqlDatabase.class.getName());
private static final String HASH_TYPE = "BINARY(32)"; private static final String HASH_TYPE = "BINARY(32)";
private static final String SECRET_TYPE = "BINARY(32)"; private static final String SECRET_TYPE = "BINARY(32)";
private static final String BINARY_TYPE = "BINARY"; private static final String BINARY_TYPE = "BINARY";
private static final String COUNTER_TYPE = private static final String COUNTER_TYPE =
"INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY(START WITH 1)"; "INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY(START WITH 1)";
private static final String STRING_TYPE = "VARCHAR"; private static final String STRING_TYPE = "VARCHAR";
private static final DatabaseTypes dbTypes = new DatabaseTypes(HASH_TYPE,
SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE);
private final DatabaseConfig config; private final DatabaseConfig config;
private final String url; private final String url;
@@ -50,7 +40,8 @@ class HyperSqlDatabase extends JdbcDatabase {
@Inject @Inject
HyperSqlDatabase(DatabaseConfig config, MessageFactory messageFactory, HyperSqlDatabase(DatabaseConfig config, MessageFactory messageFactory,
Clock clock) { Clock clock) {
super(dbTypes, messageFactory, clock); super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
messageFactory, clock);
this.config = config; this.config = config;
File dir = config.getDatabaseDirectory(); File dir = config.getDatabaseDirectory();
String path = new File(dir, "db").getAbsolutePath(); String path = new File(dir, "db").getAbsolutePath();
@@ -80,14 +71,14 @@ class HyperSqlDatabase extends JdbcDatabase {
s.close(); s.close();
c.close(); c.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s);
tryToClose(c, LOG, WARNING); tryToClose(c);
throw new DbException(e); throw new DbException(e);
} }
} }
@Override @Override
public long getFreeSpace() { public long getFreeSpace() throws DbException {
File dir = config.getDatabaseDirectory(); File dir = config.getDatabaseDirectory();
long maxSize = config.getMaxSize(); long maxSize = config.getMaxSize();
long free = dir.getFreeSpace(); long free = dir.getFreeSpace();
@@ -114,7 +105,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 = toHexString(key.getBytes()); String hex = StringUtils.toHexString(key.getBytes());
return DriverManager.getConnection(url + ";crypt_key=" + hex); return DriverManager.getConnection(url + ";crypt_key=" + hex);
} }
@@ -130,8 +121,8 @@ class HyperSqlDatabase extends JdbcDatabase {
s.close(); s.close();
c.close(); c.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s);
tryToClose(c, LOG, WARNING); tryToClose(c);
throw new DbException(e); throw new DbException(e);
} }
} }

View File

@@ -1,42 +0,0 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
class JdbcUtils {
static void tryToClose(@Nullable ResultSet rs, Logger logger, Level level) {
try {
if (rs != null) rs.close();
} catch (SQLException e) {
logException(logger, level, e);
}
}
static void tryToClose(@Nullable Statement s, Logger logger, Level level) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(logger, level, e);
}
}
static void tryToClose(@Nullable Connection c, Logger logger, Level level) {
try {
if (c != null) c.close();
} catch (SQLException e) {
logException(logger, level, e);
}
}
}

View File

@@ -7,13 +7,15 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.logging.Logger; import java.util.logging.Logger;
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.db.JdbcUtils.tryToClose;
class Migration38_39 implements Migration<Connection> { class Migration38_39 implements Migration<Connection> {
private static final Logger LOG = getLogger(Migration38_39.class.getName()); private static final Logger LOG =
Logger.getLogger(Migration38_39.class.getName());
@Override @Override
public int getStartVersion() { public int getStartVersion() {
@@ -38,8 +40,16 @@ class Migration38_39 implements Migration<Connection> {
+ " ALTER COLUMN contactId" + " ALTER COLUMN contactId"
+ " SET NOT NULL"); + " SET NOT NULL");
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s);
throw new DbException(e); throw new DbException(e);
} }
} }
private void tryToClose(@Nullable Statement s) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
} }

View File

@@ -7,13 +7,15 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.logging.Logger; import java.util.logging.Logger;
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.db.JdbcUtils.tryToClose;
class Migration39_40 implements Migration<Connection> { class Migration39_40 implements Migration<Connection> {
private static final Logger LOG = getLogger(Migration39_40.class.getName()); private static final Logger LOG =
Logger.getLogger(Migration39_40.class.getName());
@Override @Override
public int getStartVersion() { public int getStartVersion() {
@@ -37,8 +39,16 @@ class Migration39_40 implements Migration<Connection> {
+ " ALTER COLUMN eta" + " ALTER COLUMN eta"
+ " SET NOT NULL"); + " SET NOT NULL");
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s);
throw new DbException(e); throw new DbException(e);
} }
} }
private void tryToClose(@Nullable Statement s) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
} }

View File

@@ -1,46 +0,0 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DbException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration40_41 implements Migration<Connection> {
private static final Logger LOG = getLogger(Migration40_41.class.getName());
private final DatabaseTypes dbTypes;
Migration40_41(DatabaseTypes databaseTypes) {
this.dbTypes = databaseTypes;
}
@Override
public int getStartVersion() {
return 40;
}
@Override
public int getEndVersion() {
return 41;
}
@Override
public void migrate(Connection txn) throws DbException {
Statement s = null;
try {
s = txn.createStatement();
s.execute("ALTER TABLE contacts"
+ dbTypes.replaceTypes(" ADD alias _STRING"));
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
}

View File

@@ -7,6 +7,8 @@ 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;
@@ -14,8 +16,6 @@ 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];
writeUint32(formatVersion, formatVersionBytes, 0); ByteUtils.writeUint32(formatVersion, formatVersionBytes, 0);
return new AuthorId(crypto.hash(LABEL, formatVersionBytes, return new AuthorId(crypto.hash(LABEL, formatVersionBytes,
toUtf8(name), publicKey)); StringUtils.toUtf8(name), publicKey));
} }
} }

Some files were not shown because too many files have changed in this diff Show More