mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Compare commits
1 Commits
contact-re
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
779d873a70 |
@@ -3,7 +3,7 @@
|
||||
<module name="briar-headless" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<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="METHOD_NAME" value="" />
|
||||
<option name="TEST_OBJECT" value="package" />
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import com.android.build.gradle.tasks.MergeResources
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'witness'
|
||||
apply from: 'witness.gradle'
|
||||
@@ -11,8 +9,8 @@ android {
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 26
|
||||
versionCode 10106
|
||||
versionName "1.1.6"
|
||||
versionCode 10103
|
||||
versionName "1.1.3"
|
||||
consumerProguardFiles 'proguard-rules.txt'
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
@@ -30,10 +28,9 @@ configurations {
|
||||
|
||||
dependencies {
|
||||
implementation project(path: ':bramble-core', configuration: 'default')
|
||||
tor 'org.briarproject:tor-android:0.3.5.8@zip'
|
||||
tor 'org.briarproject:obfs4proxy-android:0.0.9@zip'
|
||||
tor 'org.briarproject:tor-android:0.3.4.8@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'
|
||||
|
||||
@@ -42,29 +39,13 @@ dependencies {
|
||||
testImplementation "org.jmock:jmock:2.8.2"
|
||||
testImplementation "org.jmock:jmock-junit4: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'
|
||||
|
||||
task cleanTorBinaries {
|
||||
doLast {
|
||||
delete fileTree(torBinariesDir) { include '*.zip' }
|
||||
project.afterEvaluate {
|
||||
copy {
|
||||
from configurations.tor.collect { zipTree(it) }
|
||||
into 'src/main/res/raw'
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.briarproject.bramble;
|
||||
|
||||
import org.briarproject.bramble.battery.AndroidBatteryModule;
|
||||
import org.briarproject.bramble.network.AndroidNetworkModule;
|
||||
import org.briarproject.bramble.plugin.tor.CircumventionModule;
|
||||
import org.briarproject.bramble.system.AndroidSystemModule;
|
||||
@@ -8,15 +7,10 @@ import org.briarproject.bramble.system.AndroidSystemModule;
|
||||
import dagger.Module;
|
||||
|
||||
@Module(includes = {
|
||||
AndroidBatteryModule.class,
|
||||
AndroidNetworkModule.class,
|
||||
AndroidSystemModule.class,
|
||||
CircumventionModule.class
|
||||
})
|
||||
public class BrambleAndroidModule {
|
||||
|
||||
public static void initEagerSingletons(BrambleAndroidEagerSingletons c) {
|
||||
c.inject(new AndroidBatteryModule.EagerSingletons());
|
||||
c.inject(new AndroidNetworkModule.EagerSingletons());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,15 +12,11 @@ import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.util.IoUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
|
||||
class AndroidAccountManager extends AccountManagerImpl
|
||||
implements AccountManager {
|
||||
|
||||
@@ -93,42 +89,20 @@ class AndroidAccountManager extends AccountManagerImpl
|
||||
LOG.warning("Could not clear shared preferences");
|
||||
}
|
||||
// Delete files, except lib and shared_prefs directories
|
||||
Set<File> files = new HashSet<>();
|
||||
File dataDir = new File(appContext.getApplicationInfo().dataDir);
|
||||
@Nullable
|
||||
File[] fileArray = dataDir.listFiles();
|
||||
if (fileArray == null) {
|
||||
File[] children = dataDir.listFiles();
|
||||
if (children == null) {
|
||||
LOG.warning("Could not list files in app data dir");
|
||||
} else {
|
||||
for (File file : fileArray) {
|
||||
String name = file.getName();
|
||||
for (File child : children) {
|
||||
String name = child.getName();
|
||||
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
||||
files.add(file);
|
||||
IoUtils.deleteFileOrDir(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
files.add(appContext.getFilesDir());
|
||||
files.add(appContext.getCacheDir());
|
||||
addIfNotNull(files, appContext.getExternalCacheDir());
|
||||
if (SDK_INT >= 19) {
|
||||
for (File file : appContext.getExternalCacheDirs()) {
|
||||
addIfNotNull(files, file);
|
||||
}
|
||||
}
|
||||
if (SDK_INT >= 21) {
|
||||
for (File file : appContext.getExternalMediaDirs()) {
|
||||
addIfNotNull(files, file);
|
||||
}
|
||||
}
|
||||
for (File file : files) {
|
||||
IoUtils.deleteFileOrDir(file);
|
||||
}
|
||||
// Recreate the cache dir as some OpenGL drivers expect it to exist
|
||||
if (!new File(dataDir, "cache").mkdirs())
|
||||
if (!new File(dataDir, "cache").mkdir())
|
||||
LOG.warning("Could not recreate cache dir");
|
||||
}
|
||||
|
||||
private void addIfNotNull(Set<File> files, @Nullable File file) {
|
||||
if (file != null) files.add(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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package org.briarproject.bramble.network;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.network.NetworkManager;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
@@ -12,11 +11,6 @@ import dagger.Provides;
|
||||
@Module
|
||||
public class AndroidNetworkModule {
|
||||
|
||||
public static class EagerSingletons {
|
||||
@Inject
|
||||
NetworkManager networkManager;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,
|
||||
|
||||
@@ -16,27 +16,18 @@ import org.briarproject.bramble.api.plugin.PluginException;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||
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.IoUtils;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
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_STATE_CHANGED;
|
||||
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
|
||||
@@ -46,12 +37,8 @@ import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERA
|
||||
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
|
||||
import static android.bluetooth.BluetoothAdapter.STATE_OFF;
|
||||
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.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
@@ -60,11 +47,8 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AndroidBluetoothPlugin.class.getName());
|
||||
|
||||
private static final int MAX_DISCOVERY_MS = 10_000;
|
||||
|
||||
private final AndroidExecutor androidExecutor;
|
||||
private final Context appContext;
|
||||
private final Clock clock;
|
||||
|
||||
private volatile boolean wasEnabledByUs = false;
|
||||
private volatile BluetoothStateReceiver receiver = null;
|
||||
@@ -74,13 +58,12 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
||||
|
||||
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
|
||||
Executor ioExecutor, AndroidExecutor androidExecutor,
|
||||
Context appContext, SecureRandom secureRandom, Clock clock,
|
||||
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
||||
Context appContext, SecureRandom secureRandom, Backoff backoff,
|
||||
DuplexPluginCallback callback, int maxLatency) {
|
||||
super(connectionLimiter, ioExecutor, secureRandom, backoff, callback,
|
||||
maxLatency);
|
||||
this.androidExecutor = androidExecutor;
|
||||
this.appContext = appContext;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -160,7 +143,11 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
||||
|
||||
@Override
|
||||
void tryToClose(@Nullable BluetoothServerSocket ss) {
|
||||
IoUtils.tryToClose(ss, LOG, WARNING);
|
||||
try {
|
||||
if (ss != null) ss.close();
|
||||
} catch (IOException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -190,77 +177,17 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
||||
s.connect();
|
||||
return wrapSocket(s);
|
||||
} catch (IOException e) {
|
||||
IoUtils.tryToClose(s, LOG, WARNING);
|
||||
tryToClose(s);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@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);
|
||||
private void tryToClose(@Nullable Closeable c) {
|
||||
try {
|
||||
if (adapter.startDiscovery()) {
|
||||
long now = clock.currentTimeMillis();
|
||||
long end = now + MAX_DISCOVERY_MS;
|
||||
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);
|
||||
if (c != null) c.close();
|
||||
} catch (IOException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
// Shuffle the addresses so we don't always try the same one first
|
||||
Collections.shuffle(addresses);
|
||||
return addresses;
|
||||
}
|
||||
|
||||
private class BluetoothStateReceiver extends BroadcastReceiver {
|
||||
@@ -280,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.DuplexPluginFactory;
|
||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -34,19 +33,17 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
|
||||
private final Context appContext;
|
||||
private final SecureRandom secureRandom;
|
||||
private final EventBus eventBus;
|
||||
private final Clock clock;
|
||||
private final BackoffFactory backoffFactory;
|
||||
|
||||
public AndroidBluetoothPluginFactory(Executor ioExecutor,
|
||||
AndroidExecutor androidExecutor, Context appContext,
|
||||
SecureRandom secureRandom, EventBus eventBus, Clock clock,
|
||||
SecureRandom secureRandom, EventBus eventBus,
|
||||
BackoffFactory backoffFactory) {
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.androidExecutor = androidExecutor;
|
||||
this.appContext = appContext;
|
||||
this.secureRandom = secureRandom;
|
||||
this.eventBus = eventBus;
|
||||
this.clock = clock;
|
||||
this.backoffFactory = backoffFactory;
|
||||
}
|
||||
|
||||
@@ -68,7 +65,7 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
|
||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
|
||||
connectionLimiter, ioExecutor, androidExecutor, appContext,
|
||||
secureRandom, clock, backoff, callback, MAX_LATENCY);
|
||||
secureRandom, backoff, callback, MAX_LATENCY);
|
||||
eventBus.addListener(plugin);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.PowerManager;
|
||||
|
||||
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||
import org.briarproject.bramble.api.network.NetworkManager;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
@@ -32,6 +31,9 @@ import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
@ParametersNotNullByDefault
|
||||
class AndroidTorPlugin extends TorPlugin {
|
||||
|
||||
// This tag may prevent Huawei's power manager from killing us
|
||||
private static final String WAKE_LOCK_TAG = "LocationManagerService";
|
||||
|
||||
private final Context appContext;
|
||||
private final RenewableWakeLock wakeLock;
|
||||
|
||||
@@ -39,20 +41,19 @@ class AndroidTorPlugin extends TorPlugin {
|
||||
Context appContext, NetworkManager networkManager,
|
||||
LocationUtils locationUtils, SocketFactory torSocketFactory,
|
||||
Clock clock, ResourceProvider resourceProvider,
|
||||
CircumventionProvider circumventionProvider,
|
||||
BatteryManager batteryManager, Backoff backoff,
|
||||
CircumventionProvider circumventionProvider, Backoff backoff,
|
||||
DuplexPluginCallback callback, String architecture, int maxLatency,
|
||||
int maxIdleTime) {
|
||||
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
|
||||
clock, resourceProvider, circumventionProvider, batteryManager,
|
||||
backoff, callback, architecture, maxLatency, maxIdleTime,
|
||||
clock, resourceProvider, circumventionProvider, backoff,
|
||||
callback, architecture, maxLatency, maxIdleTime,
|
||||
appContext.getDir("tor", MODE_PRIVATE));
|
||||
this.appContext = appContext;
|
||||
PowerManager pm = (PowerManager)
|
||||
appContext.getSystemService(POWER_SERVICE);
|
||||
if (pm == null) throw new AssertionError();
|
||||
assert pm != null;
|
||||
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
|
||||
getWakeLockTag(), 1, MINUTES);
|
||||
WAKE_LOCK_TAG, 1, MINUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,17 +85,4 @@ class AndroidTorPlugin extends TorPlugin {
|
||||
super.stop();
|
||||
wakeLock.release();
|
||||
}
|
||||
|
||||
private String getWakeLockTag() {
|
||||
PackageManager pm = appContext.getPackageManager();
|
||||
for (PackageInfo info : pm.getInstalledPackages(0)) {
|
||||
String name = info.packageName.toLowerCase();
|
||||
if (name.startsWith("com.huawei.powergenie")) {
|
||||
return "LocationManagerService";
|
||||
} else if (name.startsWith("com.evenwell.powermonitor")) {
|
||||
return "AudioIn";
|
||||
}
|
||||
}
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.briarproject.bramble.plugin.tor;
|
||||
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.network.NetworkManager;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
@@ -49,7 +48,6 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
||||
private final BackoffFactory backoffFactory;
|
||||
private final ResourceProvider resourceProvider;
|
||||
private final CircumventionProvider circumventionProvider;
|
||||
private final BatteryManager batteryManager;
|
||||
private final Clock clock;
|
||||
|
||||
public AndroidTorPluginFactory(Executor ioExecutor,
|
||||
@@ -57,8 +55,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
||||
NetworkManager networkManager, LocationUtils locationUtils,
|
||||
EventBus eventBus, SocketFactory torSocketFactory,
|
||||
BackoffFactory backoffFactory, ResourceProvider resourceProvider,
|
||||
CircumventionProvider circumventionProvider,
|
||||
BatteryManager batteryManager, Clock clock) {
|
||||
CircumventionProvider circumventionProvider, Clock clock) {
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.scheduler = scheduler;
|
||||
this.appContext = appContext;
|
||||
@@ -69,7 +66,6 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
||||
this.backoffFactory = backoffFactory;
|
||||
this.resourceProvider = resourceProvider;
|
||||
this.circumventionProvider = circumventionProvider;
|
||||
this.batteryManager = batteryManager;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@@ -108,8 +104,8 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
|
||||
appContext, networkManager, locationUtils, torSocketFactory,
|
||||
clock, resourceProvider, circumventionProvider, batteryManager,
|
||||
backoff, callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
||||
clock, resourceProvider, circumventionProvider, backoff,
|
||||
callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
||||
eventBus.addListener(plugin);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.briarproject.bramble.system;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Application;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
@@ -27,7 +26,7 @@ import static android.provider.Settings.Secure.ANDROID_ID;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
|
||||
class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
|
||||
|
||||
private static final int SEED_LENGTH = 32;
|
||||
|
||||
@@ -38,7 +37,6 @@ class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
|
||||
appContext = app.getApplicationContext();
|
||||
}
|
||||
|
||||
@SuppressLint("HardwareIds")
|
||||
@Override
|
||||
protected void writeToEntropyPool(DataOutputStream out) throws IOException {
|
||||
super.writeToEntropyPool(out);
|
||||
@@ -51,14 +49,12 @@ class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
|
||||
String id = Settings.Secure.getString(contentResolver, ANDROID_ID);
|
||||
if (id != null) out.writeUTF(id);
|
||||
Parcel parcel = Parcel.obtain();
|
||||
WifiManager wm = (WifiManager) appContext.getApplicationContext()
|
||||
.getSystemService(WIFI_SERVICE);
|
||||
if (wm != null) {
|
||||
List<WifiConfiguration> configs = wm.getConfiguredNetworks();
|
||||
if (configs != null) {
|
||||
for (WifiConfiguration config : configs)
|
||||
parcel.writeParcelable(config, 0);
|
||||
}
|
||||
WifiManager wm =
|
||||
(WifiManager) appContext.getSystemService(WIFI_SERVICE);
|
||||
List<WifiConfiguration> configs = wm.getConfiguredNetworks();
|
||||
if (configs != null) {
|
||||
for (WifiConfiguration config : configs)
|
||||
parcel.writeParcelable(config, 0);
|
||||
}
|
||||
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
|
||||
if (bt != null) {
|
||||
@@ -81,13 +77,13 @@ class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
|
||||
|
||||
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
||||
private void applyOpenSslFix() {
|
||||
byte[] seed = new UnixSecureRandomSpi().engineGenerateSeed(
|
||||
byte[] seed = new LinuxSecureRandomSpi().engineGenerateSeed(
|
||||
SEED_LENGTH);
|
||||
try {
|
||||
// Seed the OpenSSL PRNG
|
||||
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||
.getMethod("RAND_seed", byte[].class)
|
||||
.invoke(null, (Object) seed);
|
||||
.invoke(null, seed);
|
||||
// Mix the output of the Linux PRNG into the OpenSSL PRNG
|
||||
int bytesRead = (Integer) Class.forName(
|
||||
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package org.briarproject.bramble.system;
|
||||
|
||||
import org.briarproject.bramble.api.event.EventExecutor;
|
||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||
import org.briarproject.bramble.api.system.LocationUtils;
|
||||
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||
import org.briarproject.bramble.api.system.SecureRandomProvider;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
@@ -35,13 +32,6 @@ public class AndroidSystemModule {
|
||||
return androidExecutor;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@EventExecutor
|
||||
Executor provideEventExecutor(AndroidExecutor androidExecutor) {
|
||||
return androidExecutor::runOnUiThread;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
ResourceProvider provideResourceProvider(AndroidResourceProvider provider) {
|
||||
|
||||
@@ -11,12 +11,15 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
|
||||
public class AndroidUtils {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AndroidUtils.class.getName());
|
||||
|
||||
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
|
||||
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
|
||||
|
||||
@@ -25,7 +28,7 @@ public class AndroidUtils {
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Collection<String> getSupportedArchitectures() {
|
||||
List<String> abis = new ArrayList<>();
|
||||
if (SDK_INT >= 21) {
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
|
||||
} else {
|
||||
abis.add(Build.CPU_ABI);
|
||||
|
||||
@@ -112,8 +112,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
||||
// Other directories should be deleted
|
||||
File potatoDir = new File(testDir, ".potato");
|
||||
File potatoFile = new File(potatoDir, "file");
|
||||
File filesDir = new File(testDir, "filesDir");
|
||||
File externalCacheDir = new File(testDir, "externalCacheDir");
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(prefs).edit();
|
||||
@@ -130,12 +128,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
||||
will(returnValue(true));
|
||||
oneOf(app).getApplicationInfo();
|
||||
will(returnValue(applicationInfo));
|
||||
oneOf(app).getFilesDir();
|
||||
will(returnValue(filesDir));
|
||||
oneOf(app).getCacheDir();
|
||||
will(returnValue(cacheDir));
|
||||
oneOf(app).getExternalCacheDir();
|
||||
will(returnValue(externalCacheDir));
|
||||
}});
|
||||
|
||||
assertTrue(dbDir.mkdirs());
|
||||
@@ -148,8 +140,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
||||
assertTrue(cacheFile.createNewFile());
|
||||
assertTrue(potatoDir.mkdirs());
|
||||
assertTrue(potatoFile.createNewFile());
|
||||
assertTrue(filesDir.mkdirs());
|
||||
assertTrue(externalCacheDir.mkdirs());
|
||||
|
||||
accountManager.deleteAccount();
|
||||
|
||||
@@ -163,8 +153,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
||||
assertFalse(cacheFile.exists());
|
||||
assertFalse(potatoDir.exists());
|
||||
assertFalse(potatoFile.exists());
|
||||
assertFalse(filesDir.exists());
|
||||
assertFalse(externalCacheDir.exists());
|
||||
}
|
||||
|
||||
@After
|
||||
|
||||
@@ -1,49 +1,46 @@
|
||||
dependencyVerification {
|
||||
verify = [
|
||||
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
||||
'com.android.tools.analytics-library:protos:26.3.2:protos-26.3.2.jar:50238fb4298b297217b184b9cd93c14f83536fcee829eb0ca850bdb5b53251f0',
|
||||
'com.android.tools.analytics-library:shared:26.3.2:shared-26.3.2.jar:ddd80dcf21905018b7c0583ba72b7282f446084d4952422609a09fbf8237ef71',
|
||||
'com.android.tools.analytics-library:tracker:26.3.2:tracker-26.3.2.jar:28c575d2d1af003e96d7b375a668ee10b2673a2dd0f6438750aa8c3b42e7d0ad',
|
||||
'com.android.tools.build:apksig:3.3.2:apksig-3.3.2.jar:84c4aaa20127c6c1fe6bdd334b3f5df71f54ad080be9029c8a10f43b6a908acd',
|
||||
'com.android.tools.build:apkzlib:3.3.2:apkzlib-3.3.2.jar:d34e523278e5dff565eba3ef3c089d515b2b5cc7b47dc77e2f3465e5e47176ac',
|
||||
'com.android.tools.build:builder-model:3.3.2:builder-model-3.3.2.jar:055e3db0ecee9e06b9f024034999a29cd92cb1885207b37542126bd8bcc57f46',
|
||||
'com.android.tools.build:builder-test-api:3.3.2:builder-test-api-3.3.2.jar:0b2e4cd7615bbcad14a3c91fe45ae26693508d06e40ba06c5968b8bc24416618',
|
||||
'com.android.tools.build:builder:3.3.2:builder-3.3.2.jar:65649704da7aef0487235fd326f0f2e99ed5cf958e80f204496e6e08a42bd9f5',
|
||||
'com.android.tools.build:gradle-api:3.3.2:gradle-api-3.3.2.jar:3cbd47e41bb70330dd72ec2c9fe51e6173554b484a03829b5a2de9e00841e040',
|
||||
'com.android.tools.build:manifest-merger:26.3.2:manifest-merger-26.3.2.jar:05c4a6d8b02fb9f08744876477d0a68547c03a8a9069b1f086684fa04af97c33',
|
||||
'com.android.tools.ddms:ddmlib:26.3.2:ddmlib-26.3.2.jar:d248da8a563d6e46d2c7ebbf371a4877e00510f4ca763c0bb272d5a281bf8b85',
|
||||
'com.android.tools.external.com-intellij:intellij-core:26.3.2:intellij-core-26.3.2.jar:6c5ecc968230e9f4dcd0fef28885379feace1f0cd8130de6f61d649c86139bf3',
|
||||
'com.android.tools.external.com-intellij:kotlin-compiler:26.3.2:kotlin-compiler-26.3.2.jar:1007d9b07ccb49cd8eaf30fda10ed4681d4714f2f9ab2ecda39b4e539cc51bbe',
|
||||
'com.android.tools.external.org-jetbrains:uast:26.3.2:uast-26.3.2.jar:5d1833e562ea4f38a89708dfde695f0a162cbd39d003d3dde818c3fdc2b05317',
|
||||
'com.android.tools.layoutlib:layoutlib-api:26.3.2:layoutlib-api-26.3.2.jar:d7e61e874ab95f5c350dd38b6a95b5c9dbe0083a02001884264cdb390cb255b8',
|
||||
'com.android.tools.lint:lint-api:26.3.2:lint-api-26.3.2.jar:5867dfd7fb4a4e161a816a5d29d045f9b542d34594c00a1efec46fb4cd0e1033',
|
||||
'com.android.tools.lint:lint-checks:26.3.2:lint-checks-26.3.2.jar:4b163b9c93790d2771e92ba8de58a0d9e0671ffcf2ccef3cf496efd442e27517',
|
||||
'com.android.tools.lint:lint-gradle-api:26.3.2:lint-gradle-api-26.3.2.jar:54cb282e0c054f9bed3f51302ce08b003c8ab7961dfd5a4f6de26c23cc23062f',
|
||||
'com.android.tools.lint:lint-gradle:26.3.2:lint-gradle-26.3.2.jar:bb139615f4ce97d42cc394b9389b49b76a6eb85be6785a5d272991543b519013',
|
||||
'com.android.tools.lint:lint:26.3.2:lint-26.3.2.jar:ef7b369f8a56a92ccb0f4c1c357666b9339e4a711a9d84747d446441746cfe4e',
|
||||
'com.android.tools:annotations:26.3.2:annotations-26.3.2.jar:5bcce8e98b6a2f5ccf13ebcefd8f734e0b35f8b19e456575665631442ce1f7a1',
|
||||
'com.android.tools:common:26.3.2:common-26.3.2.jar:d9f8e7f0669e9a701568e3db6a87c89cf12d8fa6811c9991e969f950215ecfac',
|
||||
'com.android.tools:dvlib:26.3.2:dvlib-26.3.2.jar:d84aad56161c7773579303d69714ded6897c64c6ddfd7d456e453231e4dfe811',
|
||||
'com.android.tools:repository:26.3.2:repository-26.3.2.jar:da611eeb06e9ab8750d25b9e2901e10db8e5ec6304eb4c8b7103d39e0921ea40',
|
||||
'com.android.tools:sdk-common:26.3.2:sdk-common-26.3.2.jar:82823a3bf25e64fac33a286490f0cf5ac50c2cdb3c540149b030896bb44bf96c',
|
||||
'com.android.tools:sdklib:26.3.2:sdklib-26.3.2.jar:424d15492af67321900963238646d27495ab60de2a5b19e6a416963bc5d6932b',
|
||||
'com.android.tools.analytics-library:protos:26.2.0:protos-26.2.0.jar:306784ac579be37f64f110204ea3fad8568e09e10817bb574bac0fc71b6402c5',
|
||||
'com.android.tools.analytics-library:shared:26.2.0:shared-26.2.0.jar:10782c593b7edcaf63cf79f7179c4652fee1c01298e0d81d888eea5ea1c320d4',
|
||||
'com.android.tools.analytics-library:tracker:26.2.0:tracker-26.2.0.jar:74e3cf587bcd6f5f14a6cddb8123c6940baf9947582f5356c25dd852c4726564',
|
||||
'com.android.tools.build:aapt2:3.2.0-4818971:aapt2-3.2.0-4818971-linux.jar:0d86e045e9eb009ab8add53cf0e5c0f48674e8c8a4edd3b19fc978ea38508bb1',
|
||||
'com.android.tools.build:apksig:3.2.0:apksig-3.2.0.jar:d393b14a2f85a4052645fa0b59e111b46dea0fd59a934bec6cf1e997a0640e30',
|
||||
'com.android.tools.build:apkzlib:3.2.0:apkzlib-3.2.0.jar:d8a3404d63a1037207bc2eb472209c606f8143d201f484da9dacd04ffa538c31',
|
||||
'com.android.tools.build:builder-model:3.2.0:builder-model-3.2.0.jar:7deb28465f2303fdc9df58ba83d080193edefe1624784d3ce9e0a0949ae05a49',
|
||||
'com.android.tools.build:builder-test-api:3.2.0:builder-test-api-3.2.0.jar:b7c6676da0793240f16874c4008f12ed3ed1bc56a4a73f5e760044024ac9a02a',
|
||||
'com.android.tools.build:builder:3.2.0:builder-3.2.0.jar:191df45703f615a02db16ce5ce78489f1ec91f9b83e677bec5de29de765e326d',
|
||||
'com.android.tools.build:gradle-api:3.2.0:gradle-api-3.2.0.jar:5645c5ee4138b1354b24bed43e005964296a5f1ef48b6772ed9800159dcc2830',
|
||||
'com.android.tools.build:manifest-merger:26.2.0:manifest-merger-26.2.0.jar:b821830bf067852688673cae01fb571c04da094985a3894878070b50f0587edf',
|
||||
'com.android.tools.ddms:ddmlib:26.2.0:ddmlib-26.2.0.jar:ff9b6951698a6ec005b25e5e3b5f7fe960f566131ba8fcdf713392e10cc2dd50',
|
||||
'com.android.tools.external.com-intellij:intellij-core:26.2.0:intellij-core-26.2.0.jar:03724f5aff30c8fff3d0b0c05e71f8dc21f246952fe1f3b5916bfb594e337bad',
|
||||
'com.android.tools.external.com-intellij:kotlin-compiler:26.2.0:kotlin-compiler-26.2.0.jar:2f82e0c2687afe7c4941bdf6702d9a16d71d030a7ddb384a04a0537a361f4bb1',
|
||||
'com.android.tools.external.org-jetbrains:uast:26.2.0:uast-26.2.0.jar:a439cafcddb2963620fd737005e3ce0560313362ede37e6c6eac5f10ff19eb94',
|
||||
'com.android.tools.layoutlib:layoutlib-api:26.2.0:layoutlib-api-26.2.0.jar:5987488847729bad6a1e72cd5dcc46b68b61d8f05ef60858b87ed1d3b9bacc58',
|
||||
'com.android.tools.lint:lint-api:26.2.0:lint-api-26.2.0.jar:aa4dc0399b6ae602286b9b106c661b50f6a8e1143c5949d3e7fd93c4a4d1513d',
|
||||
'com.android.tools.lint:lint-checks:26.2.0:lint-checks-26.2.0.jar:c8c8dfdbd5c97a371e239b6000f4c6929bce315c2b13e690aaf34e3fcb045520',
|
||||
'com.android.tools.lint:lint-gradle-api:26.2.0:lint-gradle-api-26.2.0.jar:befc1ad242e5e89e8977b2f799c465fee1b096ac645eba659acab832980599cd',
|
||||
'com.android.tools.lint:lint-gradle:26.2.0:lint-gradle-26.2.0.jar:332d257f20537020fd268468f678ccfbcc0be494fa50526b63c532836dc7c5dd',
|
||||
'com.android.tools.lint:lint-kotlin:26.2.0:lint-kotlin-26.2.0.jar:c149e09434aa24a6f7161dbd4b09f08c46f018cb0ee1ee2d1a32bf3b5015e081',
|
||||
'com.android.tools.lint:lint:26.2.0:lint-26.2.0.jar:4df411ea5ef106780073c6e953ab591a55d52e94c9b1cd2f99970a124eca405e',
|
||||
'com.android.tools:annotations:26.2.0:annotations-26.2.0.jar:af775f75168acbadb2ff61d6955e4fbeca9b1bd9f7a40b54ab7a489e30af45bb',
|
||||
'com.android.tools:common:26.2.0:common-26.2.0.jar:3e60e91bc7c7a634bbfae3522c5e0b49e8a268a2d69904bed4bd55833f8bb0c9',
|
||||
'com.android.tools:dvlib:26.2.0:dvlib-26.2.0.jar:c4d8fac5b8432e3676256ece4e25c3e55e8ef2da4298fb060cc6086d7e2235fc',
|
||||
'com.android.tools:repository:26.2.0:repository-26.2.0.jar:9c9e320195e7e6d9bbdf9b5b0ed1d7e4da3625ad344902cb47b32c9ef8306d82',
|
||||
'com.android.tools:sdk-common:26.2.0:sdk-common-26.2.0.jar:1e32745633177b28419041d9bd182bb99b51d1a7ad3f9b1c8b5292ed799656cd',
|
||||
'com.android.tools:sdklib:26.2.0:sdklib-26.2.0.jar:08e2715f9abd3870df8e311f77ff6f3dae61193c1f6a2de78bf2e49c6ba4725a',
|
||||
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
|
||||
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
||||
'com.google.code.gson:gson:2.8.0:gson-2.8.0.jar:c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825',
|
||||
'com.google.dagger:dagger-compiler:2.19:dagger-compiler-2.19.jar:27a4b202a2de908182edb261f8c0a264e08e5e4733d7514bc7fbf0d31da5c0fc',
|
||||
'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768',
|
||||
'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1',
|
||||
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
|
||||
'com.google.errorprone:error_prone_annotations:2.1.3:error_prone_annotations-2.1.3.jar:03d0329547c13da9e17c634d1049ea2ead093925e290567e1a364fd6b1fc7ff8',
|
||||
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
||||
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
|
||||
'com.google.guava:guava:25.0-jre:guava-25.0-jre.jar:3fd4341776428c7e0e5c18a7c10de129475b69ab9d30aeafbb5c277bb6074fa9',
|
||||
'com.google.guava:guava:26.0-jre:guava-26.0-jre.jar:a0e9cabad665bc20bcd2b01f108e5fc03f756e13aea80abaadb9f407033bea2c',
|
||||
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
|
||||
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
|
||||
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
|
||||
'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b',
|
||||
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
|
||||
'com.google.guava:guava:23.0:guava-23.0.jar:7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596',
|
||||
'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.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.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
|
||||
'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.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
|
||||
@@ -66,22 +63,18 @@ dependencyVerification {
|
||||
'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:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
|
||||
'org.briarproject:obfs4proxy-android:0.0.9:obfs4proxy-android-0.0.9.zip:9b7e9181535ea8d8bbe8ae6338e08cf4c5fc1e357a779393e0ce49586d459ae0',
|
||||
'org.briarproject:tor-android:0.3.5.8:tor-android-0.3.5.8.zip:42a13a6f185be1a62f42e3f30ce66a3c099ac5ec890a65e7593111b65b44a54a',
|
||||
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
|
||||
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
|
||||
'org.codehaus.groovy:groovy-all:2.4.15:groovy-all-2.4.15.jar:51d6c4e71782e85674239189499854359d380fb75e1a703756e3aaa5b98a5af0',
|
||||
'org.briarproject:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926',
|
||||
'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.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
|
||||
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
|
||||
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
|
||||
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
||||
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
||||
'org.jetbrains.kotlin:kotlin-reflect:1.3.21:kotlin-reflect-1.3.21.jar:a3065c822633191e0a3e3ee12a29bec234fc4b2864a6bb87ef48cce3e9e0c26a',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.21:kotlin-stdlib-common-1.3.21.jar:cea61f7b611895e64f58569a9757fc0ab0d582f107211e1930e0ce2a0add52a7',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21:kotlin-stdlib-jdk7-1.3.21.jar:a87875604fd42140da6938ae4d35ee61081f4482536efc6d2615b8b626a198af',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.21:kotlin-stdlib-jdk8-1.3.21.jar:5823ed66ac122a1c55442ebca5a209a843ccd87f562edc31a787f3d2e47f74d4',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib:1.3.21:kotlin-stdlib-1.3.21.jar:38ba2370d9f06f50433e06b2ca775b94473c2e2785f410926079ab793c72b034',
|
||||
'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0:kotlin-stdlib-jre7-1.2.0.jar:c7a20fb951d437797afe8980aff6c1e5a03f310c661ba58ba1d4fa90cb0f2926',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0:kotlin-stdlib-jre8-1.2.0.jar:633524eee6ef1941f7cb1dab7ee3927b0a221ceee9047aeb5515f4cbb990c82a',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib:1.2.0:kotlin-stdlib-1.2.0.jar:05cfd9f5ac0b41910703a8925f7211a495909b27a2ffdd1c5106f1689aeafcd4',
|
||||
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
|
||||
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
|
||||
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
||||
|
||||
@@ -7,13 +7,15 @@ apply plugin: 'witness'
|
||||
apply from: 'witness.gradle'
|
||||
|
||||
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'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation "org.jmock:jmock:2.8.2"
|
||||
testImplementation "org.jmock:jmock-junit4: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'
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package org.briarproject.bramble.api.battery;
|
||||
|
||||
public interface BatteryManager {
|
||||
|
||||
boolean isCharging();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ 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;
|
||||
import org.briarproject.bramble.api.sync.validation.MessageValidator;
|
||||
import org.briarproject.bramble.api.sync.ValidationManager.MessageValidator;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -18,10 +18,11 @@ public interface ContactGroupFactory {
|
||||
* Creates a group for the given client to share with the given contact.
|
||||
*/
|
||||
Group createContactGroup(ClientId clientId, int majorVersion,
|
||||
Contact contact, AuthorId local);
|
||||
Contact contact);
|
||||
|
||||
/**
|
||||
* Creates a group for the given client to share between the given authors.
|
||||
* Creates a group for the given client to share between the given authors
|
||||
* identified by their AuthorIds.
|
||||
*/
|
||||
Group createContactGroup(ClientId clientId, int majorVersion,
|
||||
AuthorId authorId1, AuthorId authorId2);
|
||||
|
||||
@@ -1,43 +1,27 @@
|
||||
package org.briarproject.bramble.api.contact;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
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_PUBLIC_KEY_LENGTH;
|
||||
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class Contact {
|
||||
|
||||
private final ContactId id;
|
||||
private final Author author;
|
||||
@Nullable
|
||||
private final String alias;
|
||||
@Nullable
|
||||
private final byte[] handshakePublicKey;
|
||||
private final boolean verified;
|
||||
private final AuthorId localAuthorId;
|
||||
private final boolean verified, active;
|
||||
|
||||
public Contact(ContactId id, Author author, @Nullable String alias,
|
||||
@Nullable byte[] handshakePublicKey, boolean verified) {
|
||||
if (alias != null) {
|
||||
int aliasLength = toUtf8(alias).length;
|
||||
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (handshakePublicKey != null && (handshakePublicKey.length == 0 ||
|
||||
handshakePublicKey.length > MAX_PUBLIC_KEY_LENGTH)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
public Contact(ContactId id, Author author, AuthorId localAuthorId,
|
||||
boolean verified, boolean active) {
|
||||
this.id = id;
|
||||
this.author = author;
|
||||
this.alias = alias;
|
||||
this.handshakePublicKey = handshakePublicKey;
|
||||
this.localAuthorId = localAuthorId;
|
||||
this.verified = verified;
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public ContactId getId() {
|
||||
@@ -48,20 +32,18 @@ public class Contact {
|
||||
return author;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public byte[] getHandshakePublicKey() {
|
||||
return handshakePublicKey;
|
||||
public AuthorId getLocalAuthorId() {
|
||||
return localAuthorId;
|
||||
}
|
||||
|
||||
public boolean isVerified() {
|
||||
return verified;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.briarproject.bramble.api.contact;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface ContactExchangeListener {
|
||||
|
||||
void contactExchangeSucceeded(Author remoteAuthor);
|
||||
|
||||
/**
|
||||
* The exchange failed because the contact already exists.
|
||||
*/
|
||||
void duplicateContact(Author remoteAuthor);
|
||||
|
||||
/**
|
||||
* A general failure.
|
||||
*/
|
||||
void contactExchangeFailed();
|
||||
}
|
||||
@@ -18,30 +18,31 @@ public interface ContactExchangeTask {
|
||||
byte PROTOCOL_VERSION = 1;
|
||||
|
||||
/**
|
||||
* Label for deriving Alice's header key from the master key.
|
||||
* Label for deriving Alice's header key from the master secret.
|
||||
*/
|
||||
String ALICE_KEY_LABEL =
|
||||
"org.briarproject.bramble.contact/ALICE_HEADER_KEY";
|
||||
|
||||
/**
|
||||
* Label for deriving Bob's header key from the master key.
|
||||
* Label for deriving Bob's header key from the master secret.
|
||||
*/
|
||||
String BOB_KEY_LABEL = "org.briarproject.bramble.contact/BOB_HEADER_KEY";
|
||||
|
||||
/**
|
||||
* Label for deriving Alice's key binding nonce from the master key.
|
||||
* Label for deriving Alice's key binding nonce from the master secret.
|
||||
*/
|
||||
String ALICE_NONCE_LABEL = "org.briarproject.bramble.contact/ALICE_NONCE";
|
||||
|
||||
/**
|
||||
* Label for deriving Bob's key binding nonce from the master key.
|
||||
* Label for deriving Bob's key binding nonce from the master secret.
|
||||
*/
|
||||
String BOB_NONCE_LABEL = "org.briarproject.bramble.contact/BOB_NONCE";
|
||||
|
||||
/**
|
||||
* Exchanges contact information with a remote peer.
|
||||
*/
|
||||
void startExchange(LocalAuthor localAuthor, SecretKey masterKey,
|
||||
void startExchange(ContactExchangeListener listener,
|
||||
LocalAuthor localAuthor, SecretKey masterSecret,
|
||||
DuplexTransportConnection conn, TransportId transportId,
|
||||
boolean alice);
|
||||
}
|
||||
|
||||
@@ -5,14 +5,11 @@ 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.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.AuthorInfo;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface ContactManager {
|
||||
|
||||
@@ -24,80 +21,61 @@ public interface ContactManager {
|
||||
void registerContactHook(ContactHook hook);
|
||||
|
||||
/**
|
||||
* Stores a contact with the given pseudonym, derives and stores transport
|
||||
* keys for each transport, and returns an ID for the contact.
|
||||
* Stores a contact associated with the given local and remote pseudonyms,
|
||||
* derives and stores transport keys for each transport, and returns an ID
|
||||
* for the contact.
|
||||
*
|
||||
* @param alice true if the local party is Alice
|
||||
*/
|
||||
ContactId addContact(Transaction txn, Author a, SecretKey rootKey,
|
||||
ContactId addContact(Transaction txn, Author remote, AuthorId local,
|
||||
SecretKey master, long timestamp, boolean alice, boolean verified,
|
||||
boolean active) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a contact associated with the given local and remote pseudonyms
|
||||
* and returns an ID for the contact.
|
||||
*/
|
||||
ContactId addContact(Transaction txn, Author remote, AuthorId local,
|
||||
boolean verified, boolean active) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a contact associated with the given local and remote pseudonyms,
|
||||
* derives and stores transport keys for each transport, and returns an ID
|
||||
* for the contact.
|
||||
*
|
||||
* @param alice true if the local party is Alice
|
||||
*/
|
||||
ContactId addContact(Author remote, AuthorId local, SecretKey master,
|
||||
long timestamp, boolean alice, boolean verified, boolean active)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a contact with the given pseudonym and returns an ID for the
|
||||
* contact.
|
||||
*/
|
||||
ContactId addContact(Transaction txn, Author a, boolean verified)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a contact with the given pseudonym, derives and stores transport
|
||||
* keys for each transport, and returns an ID for the contact.
|
||||
*
|
||||
* @param alice true if the local party is Alice
|
||||
*/
|
||||
ContactId addContact(Author a, SecretKey rootKey, long timestamp,
|
||||
boolean alice, boolean verified, boolean active) 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 PendingContactState FAILED}.
|
||||
*/
|
||||
void removePendingContact(PendingContact pendingContact);
|
||||
|
||||
/**
|
||||
* Returns the contact with the given ID.
|
||||
*/
|
||||
Contact getContact(ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the contact with the given ID.
|
||||
* Returns the contact with the given remoteAuthorId
|
||||
* that was added by the LocalAuthor with the given localAuthorId
|
||||
*
|
||||
* @throws org.briarproject.bramble.api.db.NoSuchContactException
|
||||
*/
|
||||
Contact getContact(AuthorId a) throws DbException;
|
||||
Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the contact with the given ID.
|
||||
* Returns the contact with the given remoteAuthorId
|
||||
* that was added by the LocalAuthor with the given localAuthorId
|
||||
*
|
||||
* @throws org.briarproject.bramble.api.db.NoSuchContactException
|
||||
*/
|
||||
Contact getContact(Transaction txn, AuthorId a) throws DbException;
|
||||
Contact getContact(Transaction txn, AuthorId remoteAuthorId,
|
||||
AuthorId localAuthorId) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all active contacts.
|
||||
*/
|
||||
Collection<Contact> getContacts() throws DbException;
|
||||
Collection<Contact> getActiveContacts() throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a contact and all associated state.
|
||||
@@ -110,37 +88,23 @@ public interface ContactManager {
|
||||
void removeContact(Transaction txn, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Sets an alias name for the contact or unsets it if alias is null.
|
||||
* Marks a contact as active or inactive.
|
||||
*/
|
||||
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
|
||||
void setContactActive(Transaction txn, ContactId c, boolean active)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets an alias name for the contact or unsets it if alias is null.
|
||||
* Return true if a contact with this name and public key already exists
|
||||
*/
|
||||
void setContactAlias(ContactId c, @Nullable String alias)
|
||||
boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
|
||||
AuthorId localAuthorId) throws DbException;
|
||||
|
||||
/**
|
||||
* Return true if a contact with this name and public key already exists
|
||||
*/
|
||||
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if a contact with this pseudonym already exists.
|
||||
*/
|
||||
boolean contactExists(Transaction txn, AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if a contact with this pseudonym already exists.
|
||||
*/
|
||||
boolean contactExists(AuthorId a) 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 {
|
||||
|
||||
void addingContact(Transaction txn, Contact c) throws DbException;
|
||||
|
||||
@@ -1,56 +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 {
|
||||
|
||||
private final PendingContactId id;
|
||||
private final byte[] publicKey;
|
||||
private final String alias;
|
||||
private final PendingContactState state;
|
||||
private final long timestamp;
|
||||
|
||||
public PendingContact(PendingContactId id, byte[] publicKey,
|
||||
String alias, PendingContactState state, long timestamp) {
|
||||
this.id = id;
|
||||
this.publicKey = publicKey;
|
||||
this.alias = alias;
|
||||
this.state = state;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public PendingContactId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public byte[] getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package org.briarproject.bramble.api.contact;
|
||||
|
||||
import org.briarproject.bramble.api.UniqueId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for a byte array that uniquely identifies a
|
||||
* {@link PendingContact}.
|
||||
*/
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
public class PendingContactId extends UniqueId {
|
||||
|
||||
public PendingContactId(byte[] id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof PendingContactId && super.equals(o);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package org.briarproject.bramble.api.contact;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public enum PendingContactState {
|
||||
|
||||
WAITING_FOR_CONNECTION(0),
|
||||
CONNECTED(1),
|
||||
ADDING_CONTACT(2),
|
||||
FAILED(3);
|
||||
|
||||
private final int value;
|
||||
|
||||
PendingContactState(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static PendingContactState fromValue(int value) {
|
||||
for (PendingContactState s : values()) if (s.value == value) return s;
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
@@ -14,12 +14,18 @@ import javax.annotation.concurrent.Immutable;
|
||||
public class ContactAddedEvent extends Event {
|
||||
|
||||
private final ContactId contactId;
|
||||
private final boolean active;
|
||||
|
||||
public ContactAddedEvent(ContactId contactId) {
|
||||
public ContactAddedEvent(ContactId contactId, boolean active) {
|
||||
this.contactId = contactId;
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package org.briarproject.bramble.api.contact.event;
|
||||
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@NotNullByDefault
|
||||
public class ContactExchangeFailedEvent extends Event {
|
||||
|
||||
@Nullable
|
||||
private final Author duplicateRemoteAuthor;
|
||||
|
||||
public ContactExchangeFailedEvent(@Nullable Author duplicateRemoteAuthor) {
|
||||
this.duplicateRemoteAuthor = duplicateRemoteAuthor;
|
||||
}
|
||||
|
||||
public ContactExchangeFailedEvent() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Author getDuplicateRemoteAuthor() {
|
||||
return duplicateRemoteAuthor;
|
||||
}
|
||||
|
||||
public boolean wasDuplicateContact() {
|
||||
return duplicateRemoteAuthor != null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package org.briarproject.bramble.api.contact.event;
|
||||
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
public class ContactExchangeSucceededEvent extends Event {
|
||||
|
||||
private final Author remoteAuthor;
|
||||
|
||||
public ContactExchangeSucceededEvent(Author remoteAuthor) {
|
||||
this.remoteAuthor = remoteAuthor;
|
||||
}
|
||||
|
||||
public Author getRemoteAuthor() {
|
||||
return remoteAuthor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.briarproject.bramble.api.contact.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
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 contact is marked active or inactive.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class ContactStatusChangedEvent extends Event {
|
||||
|
||||
private final ContactId contactId;
|
||||
private final boolean active;
|
||||
|
||||
public ContactStatusChangedEvent(ContactId contactId, boolean active) {
|
||||
this.contactId = contactId;
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package org.briarproject.bramble.api.contact.event;
|
||||
|
||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||
import org.briarproject.bramble.api.contact.PendingContactState;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package org.briarproject.bramble.api.crypto;
|
||||
|
||||
/**
|
||||
* Crypto operations for the key agreement protocol - see
|
||||
* https://code.briarproject.org/briar/briar-spec/blob/master/protocols/BQP.md
|
||||
* https://code.briarproject.org/akwizgran/briar-spec/blob/master/protocols/BQP.md
|
||||
*/
|
||||
public interface KeyAgreementCrypto {
|
||||
|
||||
|
||||
@@ -1,45 +1,29 @@
|
||||
package org.briarproject.bramble.api.crypto;
|
||||
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.transport.HandshakeKeys;
|
||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||
|
||||
/**
|
||||
* Crypto operations for the transport security protocol - see
|
||||
* https://code.briarproject.org/briar/briar-spec/blob/master/protocols/BTP.md
|
||||
* https://code.briarproject.org/akwizgran/briar-spec/blob/master/protocols/BTP.md
|
||||
*/
|
||||
public interface TransportCrypto {
|
||||
|
||||
/**
|
||||
* Derives initial transport keys for the given transport in the given
|
||||
* time period from the given root key.
|
||||
* rotation period from the given master secret.
|
||||
*
|
||||
* @param alice whether the keys are for use by Alice or Bob.
|
||||
* @param active whether the keys are usable for outgoing streams.
|
||||
*/
|
||||
TransportKeys deriveTransportKeys(TransportId t, SecretKey rootKey,
|
||||
long timePeriod, boolean alice, boolean active);
|
||||
TransportKeys deriveTransportKeys(TransportId t, SecretKey master,
|
||||
long rotationPeriod, boolean alice, boolean active);
|
||||
|
||||
/**
|
||||
* Rotates the given transport keys to the given time period. If the keys
|
||||
* are for the given period or any later period they are not rotated.
|
||||
* Rotates the given transport keys to the given rotation period. If the
|
||||
* keys are for the given period or any later period they are not rotated.
|
||||
*/
|
||||
TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod);
|
||||
|
||||
/**
|
||||
* Derives handshake keys for the given transport in the given time period
|
||||
* from the given root key.
|
||||
*
|
||||
* @param alice whether the keys are for use by Alice or Bob.
|
||||
*/
|
||||
HandshakeKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey,
|
||||
long timePeriod, boolean alice);
|
||||
|
||||
/**
|
||||
* Updates the given handshake keys to the given time period. If the keys
|
||||
* are for the given period or any later period they are not updated.
|
||||
*/
|
||||
HandshakeKeys updateHandshakeKeys(HandshakeKeys k, long timePeriod);
|
||||
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
|
||||
|
||||
/**
|
||||
* Encodes the pseudo-random tag that is used to recognise a stream.
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package org.briarproject.bramble.api.db;
|
||||
|
||||
import org.briarproject.bramble.api.event.EventExecutor;
|
||||
|
||||
/**
|
||||
* An action that's taken when a {@link Transaction} is committed.
|
||||
*/
|
||||
public interface CommitAction {
|
||||
|
||||
void accept(Visitor visitor);
|
||||
|
||||
interface Visitor {
|
||||
|
||||
@EventExecutor
|
||||
void visit(EventAction a);
|
||||
|
||||
@EventExecutor
|
||||
void visit(TaskAction a);
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package org.briarproject.bramble.api.db;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
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.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
@@ -21,12 +19,8 @@ import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||
import org.briarproject.bramble.api.sync.Offer;
|
||||
import org.briarproject.bramble.api.sync.Request;
|
||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||
import org.briarproject.bramble.api.transport.HandshakeKeySet;
|
||||
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
|
||||
import org.briarproject.bramble.api.transport.HandshakeKeys;
|
||||
import org.briarproject.bramble.api.transport.TransportKeySet;
|
||||
import org.briarproject.bramble.api.transport.TransportKeySetId;
|
||||
import org.briarproject.bramble.api.transport.KeySet;
|
||||
import org.briarproject.bramble.api.transport.KeySetId;
|
||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -34,6 +28,8 @@ import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State;
|
||||
|
||||
/**
|
||||
* Encapsulates the database implementation and exposes high-level operations
|
||||
* to other components.
|
||||
@@ -94,39 +90,17 @@ public interface DatabaseComponent {
|
||||
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.
|
||||
* Stores a contact associated with the given local and remote pseudonyms,
|
||||
* and returns an ID for the contact.
|
||||
*/
|
||||
@Nullable
|
||||
<R, E extends Exception> R transactionWithNullableResult(boolean readOnly,
|
||||
NullableDbCallable<R, E> task) throws DbException, E;
|
||||
|
||||
/**
|
||||
* Stores a contact with the given pseudonym and returns an ID for the
|
||||
* contact.
|
||||
*/
|
||||
ContactId addContact(Transaction txn, Author a, boolean verified)
|
||||
throws DbException;
|
||||
ContactId addContact(Transaction txn, Author remote, AuthorId local,
|
||||
boolean verified, boolean active) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a group.
|
||||
*/
|
||||
void addGroup(Transaction txn, Group g) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores the given handshake keys for the given contact and returns a
|
||||
* key set ID.
|
||||
*/
|
||||
HandshakeKeySetId addHandshakeKeys(Transaction txn, ContactId c,
|
||||
HandshakeKeys k) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores the given handshake keys for the given pending contact and
|
||||
* returns a key set ID.
|
||||
*/
|
||||
HandshakeKeySetId addHandshakeKeys(Transaction txn, PendingContactId p,
|
||||
HandshakeKeys k) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a local pseudonym.
|
||||
*/
|
||||
@@ -138,12 +112,6 @@ public interface DatabaseComponent {
|
||||
void addLocalMessage(Transaction txn, Message m, Metadata meta,
|
||||
boolean shared) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a pending contact.
|
||||
*/
|
||||
void addPendingContact(Transaction txn, PendingContact p)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a transport.
|
||||
*/
|
||||
@@ -154,39 +122,27 @@ public interface DatabaseComponent {
|
||||
* Stores the given transport keys for the given contact and returns a
|
||||
* key set ID.
|
||||
*/
|
||||
TransportKeySetId addTransportKeys(Transaction txn, ContactId c,
|
||||
KeySetId addTransportKeys(Transaction txn, ContactId c,
|
||||
TransportKeys k) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given contact.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
* Returns true if the database contains the given contact for the given
|
||||
* local pseudonym.
|
||||
*/
|
||||
boolean containsContact(Transaction txn, AuthorId a) throws DbException;
|
||||
boolean containsContact(Transaction txn, AuthorId remote, AuthorId local)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given group.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
boolean containsGroup(Transaction txn, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given local author.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
boolean containsLocalAuthor(Transaction txn, AuthorId local)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given pending contact.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
boolean containsPendingContact(Transaction txn, PendingContactId p)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Deletes the message with the given ID. Unlike
|
||||
* {@link #removeMessage(Transaction, MessageId)}, the message ID,
|
||||
@@ -252,13 +208,6 @@ public interface DatabaseComponent {
|
||||
*/
|
||||
Contact getContact(Transaction txn, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the contact with the given author ID.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Contact getContact(Transaction txn, AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all contacts.
|
||||
* <p/>
|
||||
@@ -266,6 +215,22 @@ public interface DatabaseComponent {
|
||||
*/
|
||||
Collection<Contact> getContacts(Transaction txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns a possibly empty collection of contacts with the given author ID.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Collection<Contact> getContactsByAuthorId(Transaction txn, AuthorId remote)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all contacts associated with the given local pseudonym.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Collection<ContactId> getContacts(Transaction txn, AuthorId a)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the group with the given ID.
|
||||
* <p/>
|
||||
@@ -297,14 +262,6 @@ public interface DatabaseComponent {
|
||||
Visibility getGroupVisibility(Transaction txn, ContactId c, GroupId g)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all handshake keys for the given transport.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Collection<HandshakeKeySet> getHandshakeKeys(Transaction txn, TransportId t)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the local pseudonym with the given ID.
|
||||
* <p/>
|
||||
@@ -409,12 +366,12 @@ public interface DatabaseComponent {
|
||||
/**
|
||||
* Returns the IDs and states of all dependencies of the given message.
|
||||
* For missing dependencies and dependencies in other groups, the state
|
||||
* {@link MessageState UNKNOWN} is returned.
|
||||
* {@link State UNKNOWN} is returned.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Map<MessageId, MessageState> getMessageDependencies(Transaction txn,
|
||||
MessageId m) throws DbException;
|
||||
Map<MessageId, State> getMessageDependencies(Transaction txn, MessageId m)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the IDs and states of all dependents of the given message.
|
||||
@@ -423,16 +380,15 @@ public interface DatabaseComponent {
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Map<MessageId, MessageState> getMessageDependents(Transaction txn,
|
||||
MessageId m) throws DbException;
|
||||
Map<MessageId, State> getMessageDependents(Transaction txn, MessageId m)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Gets the validation and delivery state of the given message.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
MessageState getMessageState(Transaction txn, MessageId m)
|
||||
throws DbException;
|
||||
State getMessageState(Transaction txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the status of the given delivered message with respect to the
|
||||
@@ -453,14 +409,6 @@ public interface DatabaseComponent {
|
||||
*/
|
||||
long getNextSendTime(Transaction txn, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all pending contacts.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Collection<PendingContact> getPendingContacts(Transaction txn)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all settings in the given namespace.
|
||||
* <p/>
|
||||
@@ -473,20 +421,14 @@ public interface DatabaseComponent {
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Collection<TransportKeySet> getTransportKeys(Transaction txn, TransportId t)
|
||||
Collection<KeySet> getTransportKeys(Transaction txn, TransportId t)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Increments the outgoing stream counter for the given handshake keys.
|
||||
*/
|
||||
void incrementStreamCounter(Transaction txn, TransportId t,
|
||||
HandshakeKeySetId k) throws DbException;
|
||||
|
||||
/**
|
||||
* Increments the outgoing stream counter for the given transport keys.
|
||||
*/
|
||||
void incrementStreamCounter(Transaction txn, TransportId t,
|
||||
TransportKeySetId k) throws DbException;
|
||||
void incrementStreamCounter(Transaction txn, TransportId t, KeySetId k)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Merges the given metadata with the existing metadata for the given
|
||||
@@ -541,12 +483,6 @@ public interface DatabaseComponent {
|
||||
*/
|
||||
void removeGroup(Transaction txn, Group g) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes the given handshake keys from the database.
|
||||
*/
|
||||
void removeHandshakeKeys(Transaction txn, TransportId t,
|
||||
HandshakeKeySetId k) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a local pseudonym (and all associated state) from the database.
|
||||
*/
|
||||
@@ -557,12 +493,6 @@ public interface DatabaseComponent {
|
||||
*/
|
||||
void removeMessage(Transaction txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a pending contact (and all associated state) from the database.
|
||||
*/
|
||||
void removePendingContact(Transaction txn, PendingContactId p)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a transport (and all associated state) from the database.
|
||||
*/
|
||||
@@ -571,8 +501,8 @@ public interface DatabaseComponent {
|
||||
/**
|
||||
* Removes the given transport keys from the database.
|
||||
*/
|
||||
void removeTransportKeys(Transaction txn, TransportId t,
|
||||
TransportKeySetId k) throws DbException;
|
||||
void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Marks the given contact as verified.
|
||||
@@ -580,9 +510,9 @@ public interface DatabaseComponent {
|
||||
void setContactVerified(Transaction txn, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Sets an alias name for the contact or unsets it if alias is null.
|
||||
* Marks the given contact as active or inactive.
|
||||
*/
|
||||
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
|
||||
void setContactActive(Transaction txn, ContactId c, boolean active)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
@@ -599,7 +529,7 @@ public interface DatabaseComponent {
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
@@ -609,36 +539,21 @@ public interface DatabaseComponent {
|
||||
Collection<MessageId> dependencies) throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the reordering window for the given transport key set in the given
|
||||
* time period.
|
||||
* Sets the reordering window for the given key set and transport in the
|
||||
* given rotation period.
|
||||
*/
|
||||
void setReorderingWindow(Transaction txn, TransportKeySetId k,
|
||||
TransportId t, long timePeriod, long base, byte[] bitmap)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the reordering window for the given handshake key set in the given
|
||||
* time period.
|
||||
*/
|
||||
void setReorderingWindow(Transaction txn, HandshakeKeySetId k,
|
||||
TransportId t, long timePeriod, long base, byte[] bitmap)
|
||||
throws DbException;
|
||||
void setReorderingWindow(Transaction txn, KeySetId k, TransportId t,
|
||||
long rotationPeriod, long base, byte[] bitmap) throws DbException;
|
||||
|
||||
/**
|
||||
* Marks the given transport keys as usable for outgoing streams.
|
||||
*/
|
||||
void setTransportKeysActive(Transaction txn, TransportId t,
|
||||
TransportKeySetId k) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores the given handshake keys, deleting any keys they have replaced.
|
||||
*/
|
||||
void updateHandshakeKeys(Transaction txn, Collection<HandshakeKeySet> keys)
|
||||
void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Stores the given transport keys, deleting any keys they have replaced.
|
||||
*/
|
||||
void updateTransportKeys(Transaction txn, Collection<TransportKeySet> keys)
|
||||
void updateTransportKeys(Transaction txn, Collection<KeySet> keys)
|
||||
throws DbException;
|
||||
}
|
||||
|
||||
@@ -10,4 +10,6 @@ public interface DatabaseConfig {
|
||||
File getDatabaseDirectory();
|
||||
|
||||
File getDatabaseKeyDirectory();
|
||||
|
||||
long getMaxSize();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package org.briarproject.bramble.api.db;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface DbCallable<R, E extends Exception> {
|
||||
|
||||
R call(Transaction txn) throws DbException, E;
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package org.briarproject.bramble.api.db;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface DbRunnable<E extends Exception> {
|
||||
|
||||
void run(Transaction txn) throws DbException, E;
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.briarproject.bramble.api.db;
|
||||
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
|
||||
/**
|
||||
* A {@link CommitAction} that broadcasts an event.
|
||||
*/
|
||||
public class EventAction implements CommitAction {
|
||||
|
||||
private final Event event;
|
||||
|
||||
EventAction(Event event) {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
public Event getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package org.briarproject.bramble.api.db;
|
||||
|
||||
/**
|
||||
* Thrown when a database operation is attempted for a pending contact that is
|
||||
* not in the database. This exception may occur due to concurrent updates and
|
||||
* does not indicate a database error.
|
||||
*/
|
||||
public class NoSuchPendingContactException extends DbException {
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package org.briarproject.bramble.api.db;
|
||||
|
||||
/**
|
||||
* Thrown when a duplicate pending contact is added to the database. This
|
||||
* exception may occur due to concurrent updates and does not indicate a
|
||||
* database error.
|
||||
*/
|
||||
public class PendingContactExistsException extends DbException {
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.briarproject.bramble.api.db;
|
||||
|
||||
import org.briarproject.bramble.api.event.EventExecutor;
|
||||
|
||||
/**
|
||||
* A {@link CommitAction} that submits a task to the {@link EventExecutor}.
|
||||
*/
|
||||
public class TaskAction implements CommitAction {
|
||||
|
||||
private final Runnable task;
|
||||
|
||||
TaskAction(Runnable task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
public Runnable getTask() {
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
package org.briarproject.bramble.api.db;
|
||||
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.event.EventExecutor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.concurrent.NotThreadSafe;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
/**
|
||||
* A wrapper around a database transaction. Transactions are not thread-safe.
|
||||
*/
|
||||
@@ -19,7 +17,7 @@ public class Transaction {
|
||||
private final Object txn;
|
||||
private final boolean readOnly;
|
||||
|
||||
private List<CommitAction> actions = null;
|
||||
private List<Event> events = null;
|
||||
private boolean committed = false;
|
||||
|
||||
public Transaction(Object txn, boolean readOnly) {
|
||||
@@ -44,27 +42,19 @@ public class Transaction {
|
||||
|
||||
/**
|
||||
* Attaches an event to be broadcast when the transaction has been
|
||||
* committed. The event will be broadcast on the {@link EventExecutor}.
|
||||
* committed.
|
||||
*/
|
||||
public void attach(Event e) {
|
||||
if (actions == null) actions = new ArrayList<>();
|
||||
actions.add(new EventAction(e));
|
||||
if (events == null) events = new ArrayList<>();
|
||||
events.add(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a task to be executed when the transaction has been
|
||||
* committed. The task will be run on the {@link EventExecutor}.
|
||||
* Returns any events attached to the transaction.
|
||||
*/
|
||||
public void attach(Runnable r) {
|
||||
if (actions == null) actions = new ArrayList<>();
|
||||
actions.add(new TaskAction(r));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any actions attached to the transaction.
|
||||
*/
|
||||
public List<CommitAction> getActions() {
|
||||
return actions == null ? emptyList() : actions;
|
||||
public List<Event> getEvents() {
|
||||
if (events == null) return Collections.emptyList();
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,8 +16,7 @@ public interface EventBus {
|
||||
void removeListener(EventListener l);
|
||||
|
||||
/**
|
||||
* Asynchronously notifies all listeners of an event. Listeners are
|
||||
* notified on the {@link EventExecutor}.
|
||||
* Notifies all listeners of an event.
|
||||
*/
|
||||
void broadcast(Event e);
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package org.briarproject.bramble.api.event;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* Annotation for injecting the executor for broadcasting events and running
|
||||
* tasks that need to run in a defined order with respect to events. Also used
|
||||
* for annotating methods that should run on the event executor.
|
||||
* <p>
|
||||
* The contract of this executor is that tasks are run in the order they're
|
||||
* submitted, tasks are not run concurrently, and submitting a task will never
|
||||
* block. Tasks must not block. Tasks submitted during shutdown are discarded.
|
||||
*/
|
||||
@Qualifier
|
||||
@Target({FIELD, METHOD, PARAMETER})
|
||||
@Retention(RUNTIME)
|
||||
public @interface EventExecutor {
|
||||
}
|
||||
@@ -12,6 +12,5 @@ public interface EventListener {
|
||||
* Called when an event is broadcast. Implementations of this method must
|
||||
* not block.
|
||||
*/
|
||||
@EventExecutor
|
||||
void eventOccurred(Event e);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_K
|
||||
@NotNullByDefault
|
||||
public class Author implements Nameable {
|
||||
|
||||
public enum Status {
|
||||
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
|
||||
}
|
||||
|
||||
/**
|
||||
* The current version of the author structure.
|
||||
*/
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.api.identity;
|
||||
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author.Status;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
@@ -36,4 +37,14 @@ public interface IdentityManager {
|
||||
*/
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
@@ -2,11 +2,8 @@ package org.briarproject.bramble.api.identity;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||
|
||||
/**
|
||||
* A pseudonym for the local user.
|
||||
*/
|
||||
@@ -15,8 +12,6 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_K
|
||||
public class LocalAuthor extends Author {
|
||||
|
||||
private final byte[] privateKey;
|
||||
@Nullable
|
||||
private final byte[] handshakePublicKey, handshakePrivateKey;
|
||||
private final long created;
|
||||
|
||||
public LocalAuthor(AuthorId id, int formatVersion, String name,
|
||||
@@ -24,22 +19,6 @@ public class LocalAuthor extends Author {
|
||||
super(id, formatVersion, name, publicKey);
|
||||
this.privateKey = privateKey;
|
||||
this.created = created;
|
||||
handshakePublicKey = null;
|
||||
handshakePrivateKey = null;
|
||||
}
|
||||
|
||||
public LocalAuthor(AuthorId id, int formatVersion, String name,
|
||||
byte[] publicKey, byte[] privateKey, byte[] handshakePublicKey,
|
||||
byte[] handshakePrivateKey, long created) {
|
||||
super(id, formatVersion, name, publicKey);
|
||||
if (handshakePublicKey.length == 0 ||
|
||||
handshakePublicKey.length > MAX_PUBLIC_KEY_LENGTH) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.privateKey = privateKey;
|
||||
this.handshakePublicKey = handshakePublicKey;
|
||||
this.handshakePrivateKey = handshakePrivateKey;
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,22 +28,6 @@ public class LocalAuthor extends Author {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key used for handshaking, or null if no key exists.
|
||||
*/
|
||||
@Nullable
|
||||
public byte[] getHandshakePublicKey() {
|
||||
return handshakePublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the private key used for handshaking, or null if no key exists.
|
||||
*/
|
||||
@Nullable
|
||||
public byte[] getHandshakePrivateKey() {
|
||||
return handshakePrivateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time the pseudonym was created, in milliseconds since the
|
||||
* Unix epoch.
|
||||
|
||||
@@ -21,7 +21,7 @@ public interface KeyAgreementConstants {
|
||||
/**
|
||||
* The connection timeout in milliseconds.
|
||||
*/
|
||||
long CONNECTION_TIMEOUT = 60_000;
|
||||
long CONNECTION_TIMEOUT = 20 * 1000;
|
||||
|
||||
/**
|
||||
* The transport identifier for Bluetooth.
|
||||
@@ -40,8 +40,8 @@ public interface KeyAgreementConstants {
|
||||
"org.briarproject.bramble.keyagreement/SHARED_SECRET";
|
||||
|
||||
/**
|
||||
* Label for deriving the master key.
|
||||
* Label for deriving the master secret.
|
||||
*/
|
||||
String MASTER_KEY_LABEL =
|
||||
String MASTER_SECRET_LABEL =
|
||||
"org.briarproject.bramble.keyagreement/MASTER_SECRET";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@ public interface TorConstants {
|
||||
String PREF_TOR_NETWORK = "network2";
|
||||
String PREF_TOR_PORT = "port";
|
||||
String PREF_TOR_MOBILE = "useMobileData";
|
||||
String PREF_TOR_ONLY_WHEN_CHARGING = "onlyWhenCharging";
|
||||
|
||||
int PREF_TOR_NETWORK_AUTOMATIC = 0;
|
||||
int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,11 @@ package org.briarproject.bramble.api.sync.event;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State;
|
||||
|
||||
/**
|
||||
* 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 boolean local;
|
||||
private final MessageState state;
|
||||
private final State state;
|
||||
|
||||
public MessageStateChangedEvent(MessageId messageId, boolean local,
|
||||
MessageState state) {
|
||||
State state) {
|
||||
this.messageId = messageId;
|
||||
this.local = local;
|
||||
this.state = state;
|
||||
@@ -33,7 +34,7 @@ public class MessageStateChangedEvent extends Event {
|
||||
return local;
|
||||
}
|
||||
|
||||
public MessageState getState() {
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package org.briarproject.bramble.api.transport;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* Abstract superclass for {@link TransportKeys} and {@link HandshakeKeys}.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public abstract class AbstractTransportKeys {
|
||||
|
||||
private final TransportId transportId;
|
||||
private final IncomingKeys inPrev, inCurr, inNext;
|
||||
private final OutgoingKeys outCurr;
|
||||
|
||||
AbstractTransportKeys(TransportId transportId, IncomingKeys inPrev,
|
||||
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) {
|
||||
if (inPrev.getTimePeriod() != outCurr.getTimePeriod() - 1)
|
||||
throw new IllegalArgumentException();
|
||||
if (inCurr.getTimePeriod() != outCurr.getTimePeriod())
|
||||
throw new IllegalArgumentException();
|
||||
if (inNext.getTimePeriod() != outCurr.getTimePeriod() + 1)
|
||||
throw new IllegalArgumentException();
|
||||
this.transportId = transportId;
|
||||
this.inPrev = inPrev;
|
||||
this.inCurr = inCurr;
|
||||
this.inNext = inNext;
|
||||
this.outCurr = outCurr;
|
||||
}
|
||||
|
||||
public TransportId getTransportId() {
|
||||
return transportId;
|
||||
}
|
||||
|
||||
public IncomingKeys getPreviousIncomingKeys() {
|
||||
return inPrev;
|
||||
}
|
||||
|
||||
public IncomingKeys getCurrentIncomingKeys() {
|
||||
return inCurr;
|
||||
}
|
||||
|
||||
public IncomingKeys getNextIncomingKeys() {
|
||||
return inNext;
|
||||
}
|
||||
|
||||
public OutgoingKeys getCurrentOutgoingKeys() {
|
||||
return outCurr;
|
||||
}
|
||||
|
||||
public long getTimePeriod() {
|
||||
return outCurr.getTimePeriod();
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package org.briarproject.bramble.api.transport;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A set of keys for handshaking with a given contact or pending contact over a
|
||||
* given transport. Unlike a {@link TransportKeySet} these keys do not provide
|
||||
* forward secrecy.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class HandshakeKeySet {
|
||||
|
||||
private final HandshakeKeySetId keySetId;
|
||||
@Nullable
|
||||
private final ContactId contactId;
|
||||
@Nullable
|
||||
private final PendingContactId pendingContactId;
|
||||
private final HandshakeKeys keys;
|
||||
|
||||
public HandshakeKeySet(HandshakeKeySetId keySetId, ContactId contactId,
|
||||
HandshakeKeys keys) {
|
||||
this.keySetId = keySetId;
|
||||
this.contactId = contactId;
|
||||
this.keys = keys;
|
||||
pendingContactId = null;
|
||||
}
|
||||
|
||||
public HandshakeKeySet(HandshakeKeySetId keySetId,
|
||||
PendingContactId pendingContactId, HandshakeKeys keys) {
|
||||
this.keySetId = keySetId;
|
||||
this.pendingContactId = pendingContactId;
|
||||
this.keys = keys;
|
||||
contactId = null;
|
||||
}
|
||||
|
||||
public HandshakeKeySetId getKeySetId() {
|
||||
return keySetId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PendingContactId getPendingContactId() {
|
||||
return pendingContactId;
|
||||
}
|
||||
|
||||
public HandshakeKeys getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return keySetId.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof HandshakeKeySet &&
|
||||
keySetId.equals(((HandshakeKeySet) o).keySetId);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package org.briarproject.bramble.api.transport;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for an integer that uniquely identifies a
|
||||
* {@link HandshakeKeySet set of handshake keys} within the scope of the local
|
||||
* device.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class HandshakeKeySetId {
|
||||
|
||||
private final int id;
|
||||
|
||||
public HandshakeKeySetId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getInt() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof HandshakeKeySetId &&
|
||||
id == ((HandshakeKeySetId) o).id;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package org.briarproject.bramble.api.transport;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* Keys for handshaking with a given contact or pending contact over a given
|
||||
* transport. Unlike {@link TransportKeys} these keys do not provide forward
|
||||
* secrecy.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class HandshakeKeys extends AbstractTransportKeys {
|
||||
|
||||
private final SecretKey rootKey;
|
||||
private final boolean alice;
|
||||
|
||||
public HandshakeKeys(TransportId transportId, IncomingKeys inPrev,
|
||||
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr,
|
||||
SecretKey rootKey, boolean alice) {
|
||||
super(transportId, inPrev, inCurr, inNext, outCurr);
|
||||
this.rootKey = rootKey;
|
||||
this.alice = alice;
|
||||
}
|
||||
|
||||
public SecretKey getRootKey() {
|
||||
return rootKey;
|
||||
}
|
||||
|
||||
public boolean isAlice() {
|
||||
return alice;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,30 @@
|
||||
package org.briarproject.bramble.api.transport;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
|
||||
|
||||
/**
|
||||
* Contains transport keys for receiving streams from a given contact over a
|
||||
* given transport in a given time period.
|
||||
* given transport in a given rotation period.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class IncomingKeys {
|
||||
|
||||
private final SecretKey tagKey, headerKey;
|
||||
private final long timePeriod, windowBase;
|
||||
private final long rotationPeriod, windowBase;
|
||||
private final byte[] windowBitmap;
|
||||
|
||||
public IncomingKeys(SecretKey tagKey, SecretKey headerKey,
|
||||
long timePeriod) {
|
||||
this(tagKey, headerKey, timePeriod, 0,
|
||||
long rotationPeriod) {
|
||||
this(tagKey, headerKey, rotationPeriod, 0,
|
||||
new byte[REORDERING_WINDOW_SIZE / 8]);
|
||||
}
|
||||
|
||||
public IncomingKeys(SecretKey tagKey, SecretKey headerKey,
|
||||
long timePeriod, long windowBase, byte[] windowBitmap) {
|
||||
long rotationPeriod, long windowBase, byte[] windowBitmap) {
|
||||
this.tagKey = tagKey;
|
||||
this.headerKey = headerKey;
|
||||
this.timePeriod = timePeriod;
|
||||
this.rotationPeriod = rotationPeriod;
|
||||
this.windowBase = windowBase;
|
||||
this.windowBitmap = windowBitmap;
|
||||
}
|
||||
@@ -42,8 +37,8 @@ public class IncomingKeys {
|
||||
return headerKey;
|
||||
}
|
||||
|
||||
public long getTimePeriod() {
|
||||
return timePeriod;
|
||||
public long getRotationPeriod() {
|
||||
return rotationPeriod;
|
||||
}
|
||||
|
||||
public long getWindowBase() {
|
||||
|
||||
@@ -27,14 +27,14 @@ public interface KeyManager {
|
||||
* @param alice true if the local party is Alice
|
||||
* @param active whether the derived keys can be used for outgoing streams
|
||||
*/
|
||||
Map<TransportId, TransportKeySetId> addContact(Transaction txn, ContactId c,
|
||||
SecretKey rootKey, long timestamp, boolean alice, boolean active)
|
||||
Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
|
||||
SecretKey master, long timestamp, boolean alice, boolean active)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Marks the given transport keys as usable for outgoing streams.
|
||||
*/
|
||||
void activateKeys(Transaction txn, Map<TransportId, TransportKeySetId> keys)
|
||||
void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.briarproject.bramble.api.transport;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A set of transport keys for communicating with a contact.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class KeySet {
|
||||
|
||||
private final KeySetId keySetId;
|
||||
private final ContactId contactId;
|
||||
private final TransportKeys transportKeys;
|
||||
|
||||
public KeySet(KeySetId keySetId, ContactId contactId,
|
||||
TransportKeys transportKeys) {
|
||||
this.keySetId = keySetId;
|
||||
this.contactId = contactId;
|
||||
this.transportKeys = transportKeys;
|
||||
}
|
||||
|
||||
public KeySetId getKeySetId() {
|
||||
return keySetId;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public TransportKeys getTransportKeys() {
|
||||
return transportKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return keySetId.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof KeySet && keySetId.equals(((KeySet) o).keySetId);
|
||||
}
|
||||
}
|
||||
@@ -5,19 +5,18 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for an integer that uniquely identifies a
|
||||
* {@link TransportKeySet set of transport keys} within the scope of the local
|
||||
* device.
|
||||
* Type-safe wrapper for an integer that uniquely identifies a set of transport
|
||||
* keys within the scope of the local device.
|
||||
* <p/>
|
||||
* Key sets created on a given device must have increasing identifiers.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class TransportKeySetId {
|
||||
public class KeySetId {
|
||||
|
||||
private final int id;
|
||||
|
||||
public TransportKeySetId(int id) {
|
||||
public KeySetId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@@ -32,7 +31,6 @@ public class TransportKeySetId {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof TransportKeySetId &&
|
||||
id == ((TransportKeySetId) o).id;
|
||||
return o instanceof KeySetId && id == ((KeySetId) o).id;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,27 @@
|
||||
package org.briarproject.bramble.api.transport;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* Contains transport keys for sending streams to a given contact over a given
|
||||
* transport in a given time period.
|
||||
* transport in a given rotation period.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class OutgoingKeys {
|
||||
|
||||
private final SecretKey tagKey, headerKey;
|
||||
private final long timePeriod, streamCounter;
|
||||
private final long rotationPeriod, streamCounter;
|
||||
private final boolean active;
|
||||
|
||||
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
|
||||
long timePeriod, boolean active) {
|
||||
this(tagKey, headerKey, timePeriod, 0, active);
|
||||
long rotationPeriod, boolean active) {
|
||||
this(tagKey, headerKey, rotationPeriod, 0, active);
|
||||
}
|
||||
|
||||
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
|
||||
long timePeriod, long streamCounter, boolean active) {
|
||||
long rotationPeriod, long streamCounter, boolean active) {
|
||||
this.tagKey = tagKey;
|
||||
this.headerKey = headerKey;
|
||||
this.timePeriod = timePeriod;
|
||||
this.rotationPeriod = rotationPeriod;
|
||||
this.streamCounter = streamCounter;
|
||||
this.active = active;
|
||||
}
|
||||
@@ -39,8 +34,8 @@ public class OutgoingKeys {
|
||||
return headerKey;
|
||||
}
|
||||
|
||||
public long getTimePeriod() {
|
||||
return timePeriod;
|
||||
public long getRotationPeriod() {
|
||||
return rotationPeriod;
|
||||
}
|
||||
|
||||
public long getStreamCounter() {
|
||||
|
||||
@@ -2,13 +2,8 @@ package org.briarproject.bramble.api.transport;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class StreamContext {
|
||||
|
||||
private final ContactId contactId;
|
||||
|
||||
@@ -82,58 +82,30 @@ public interface TransportConstants {
|
||||
int REORDERING_WINDOW_SIZE = 32;
|
||||
|
||||
/**
|
||||
* Label for deriving Alice's initial tag key from the root key in
|
||||
* rotation mode.
|
||||
* Label for deriving Alice's initial tag key from the master secret.
|
||||
*/
|
||||
String ALICE_TAG_LABEL = "org.briarproject.bramble.transport/ALICE_TAG_KEY";
|
||||
|
||||
/**
|
||||
* Label for deriving Bob's initial tag key from the root key in rotation
|
||||
* mode.
|
||||
* Label for deriving Bob's initial tag key from the master secret.
|
||||
*/
|
||||
String BOB_TAG_LABEL = "org.briarproject.bramble.transport/BOB_TAG_KEY";
|
||||
|
||||
/**
|
||||
* Label for deriving Alice's initial header key from the root key in
|
||||
* rotation mode.
|
||||
* Label for deriving Alice's initial header key from the master secret.
|
||||
*/
|
||||
String ALICE_HEADER_LABEL =
|
||||
"org.briarproject.bramble.transport/ALICE_HEADER_KEY";
|
||||
|
||||
/**
|
||||
* Label for deriving Bob's initial header key from the root key in
|
||||
* rotation mode.
|
||||
* Label for deriving Bob's initial header key from the master secret.
|
||||
*/
|
||||
String BOB_HEADER_LABEL =
|
||||
"org.briarproject.bramble.transport/BOB_HEADER_KEY";
|
||||
|
||||
/**
|
||||
* Label for deriving the next period's key in rotation mode.
|
||||
* Label for deriving the next period's key in key rotation.
|
||||
*/
|
||||
String ROTATE_LABEL = "org.briarproject.bramble.transport/ROTATE";
|
||||
|
||||
/**
|
||||
* Label for deriving Alice's tag key from the root key in handshake mode.
|
||||
*/
|
||||
String ALICE_HANDSHAKE_TAG_LABEL =
|
||||
"org.briarproject.bramble.transport/ALICE_HANDSHAKE_TAG_KEY";
|
||||
|
||||
/**
|
||||
* Label for deriving Bob's tag key from the root key in handshake mode.
|
||||
*/
|
||||
String BOB_HANDSHAKE_TAG_LABEL =
|
||||
"org.briarproject.bramble.transport/BOB_HANDSHAKE_TAG_KEY";
|
||||
|
||||
/**
|
||||
* Label for deriving Alice's header key from the root key in handshake
|
||||
* mode.
|
||||
*/
|
||||
String ALICE_HANDSHAKE_HEADER_LABEL =
|
||||
"org.briarproject.bramble.transport/ALICE_HANDSHAKE_HEADER_KEY";
|
||||
|
||||
/**
|
||||
* Label for deriving Bob's header key from the root key in handshake mode.
|
||||
*/
|
||||
String BOB_HANDSHAKE_HEADER_LABEL =
|
||||
"org.briarproject.bramble.transport/BOB_HANDSHAKE_HEADER_KEY";
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
package org.briarproject.bramble.api.transport;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* A set of keys for communicating with a given contact over a given transport.
|
||||
* Unlike a {@link HandshakeKeySet} these keys provide forward secrecy.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class TransportKeySet {
|
||||
|
||||
private final TransportKeySetId keySetId;
|
||||
private final ContactId contactId;
|
||||
private final TransportKeys keys;
|
||||
|
||||
public TransportKeySet(TransportKeySetId keySetId, ContactId contactId,
|
||||
TransportKeys keys) {
|
||||
this.keySetId = keySetId;
|
||||
this.contactId = contactId;
|
||||
this.keys = keys;
|
||||
}
|
||||
|
||||
public TransportKeySetId getKeySetId() {
|
||||
return keySetId;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public TransportKeys getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return keySetId.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof TransportKeySet &&
|
||||
keySetId.equals(((TransportKeySet) o).keySetId);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,52 @@
|
||||
package org.briarproject.bramble.api.transport;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* Keys for communicating with a given contact over a given transport. Unlike
|
||||
* {@link HandshakeKeys} these keys provide forward secrecy.
|
||||
* Keys for communicating with a given contact over a given transport.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class TransportKeys extends AbstractTransportKeys {
|
||||
public class TransportKeys {
|
||||
|
||||
private final TransportId transportId;
|
||||
private final IncomingKeys inPrev, inCurr, inNext;
|
||||
private final OutgoingKeys outCurr;
|
||||
|
||||
public TransportKeys(TransportId transportId, IncomingKeys inPrev,
|
||||
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) {
|
||||
super(transportId, inPrev, inCurr, inNext, outCurr);
|
||||
if (inPrev.getRotationPeriod() != inCurr.getRotationPeriod() - 1)
|
||||
throw new IllegalArgumentException();
|
||||
if (inNext.getRotationPeriod() != inCurr.getRotationPeriod() + 1)
|
||||
throw new IllegalArgumentException();
|
||||
if (outCurr.getRotationPeriod() != inCurr.getRotationPeriod())
|
||||
throw new IllegalArgumentException();
|
||||
this.transportId = transportId;
|
||||
this.inPrev = inPrev;
|
||||
this.inCurr = inCurr;
|
||||
this.inNext = inNext;
|
||||
this.outCurr = outCurr;
|
||||
}
|
||||
|
||||
public TransportId getTransportId() {
|
||||
return transportId;
|
||||
}
|
||||
|
||||
public IncomingKeys getPreviousIncomingKeys() {
|
||||
return inPrev;
|
||||
}
|
||||
|
||||
public IncomingKeys getCurrentIncomingKeys() {
|
||||
return inCurr;
|
||||
}
|
||||
|
||||
public IncomingKeys getNextIncomingKeys() {
|
||||
return inNext;
|
||||
}
|
||||
|
||||
public OutgoingKeys getCurrentOutgoingKeys() {
|
||||
return outCurr;
|
||||
}
|
||||
|
||||
public long getRotationPeriod() {
|
||||
return outCurr.getRotationPeriod();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,13 +38,6 @@ public interface ClientVersioningManager {
|
||||
Visibility getClientVisibility(Transaction txn, ContactId contactId,
|
||||
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 {
|
||||
|
||||
void onClientVisibilityChanging(Transaction txn, Contact c,
|
||||
|
||||
@@ -8,15 +8,12 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
@NotNullByDefault
|
||||
public class IoUtils {
|
||||
@@ -57,35 +54,16 @@ public class IoUtils {
|
||||
out.flush();
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
tryToClose(in, LOG, WARNING);
|
||||
tryToClose(out, LOG, WARNING);
|
||||
tryToClose(in);
|
||||
tryToClose(out);
|
||||
}
|
||||
}
|
||||
|
||||
public static void tryToClose(@Nullable Closeable c, Logger logger,
|
||||
Level level) {
|
||||
private static void tryToClose(@Nullable Closeable c) {
|
||||
try {
|
||||
if (c != null) c.close();
|
||||
} catch (IOException e) {
|
||||
logException(logger, level, e);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
// We did our best
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ public class OsUtils {
|
||||
@Nullable
|
||||
private static final String os = System.getProperty("os.name");
|
||||
@Nullable
|
||||
private static final String version = System.getProperty("os.version");
|
||||
@Nullable
|
||||
private static final String vendor = System.getProperty("java.vendor");
|
||||
|
||||
public static boolean isWindows() {
|
||||
|
||||
@@ -47,7 +47,7 @@ public class StringUtils {
|
||||
try {
|
||||
return s.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new AssertionError(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class StringUtils {
|
||||
try {
|
||||
return decoder.decode(buffer).toString();
|
||||
} catch (CharacterCodingException e) {
|
||||
throw new AssertionError(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
package org.briarproject.bramble.test;
|
||||
|
||||
import org.briarproject.bramble.api.UniqueId;
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
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.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
@@ -29,7 +25,6 @@ import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
|
||||
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_PUBLIC_KEY_LENGTH;
|
||||
@@ -46,7 +41,6 @@ public class TestUtils {
|
||||
new AtomicInteger((int) (Math.random() * 1000 * 1000));
|
||||
private static final Random random = new Random();
|
||||
private static final long timestamp = System.currentTimeMillis();
|
||||
private static final AtomicInteger nextContactId = new AtomicInteger(1);
|
||||
|
||||
public static File getTestDirectory() {
|
||||
int name = nextTestDir.getAndIncrement();
|
||||
@@ -146,35 +140,6 @@ public class TestUtils {
|
||||
return new Message(id, groupId, timestamp, body);
|
||||
}
|
||||
|
||||
public static PendingContact getPendingContact() {
|
||||
return getPendingContact(1 + random.nextInt(MAX_AUTHOR_NAME_LENGTH));
|
||||
}
|
||||
|
||||
public static PendingContact getPendingContact(int nameLength) {
|
||||
PendingContactId id = new PendingContactId(getRandomId());
|
||||
byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
|
||||
String alias = getRandomString(nameLength);
|
||||
return new PendingContact(id, publicKey, alias, WAITING_FOR_CONNECTION,
|
||||
timestamp);
|
||||
}
|
||||
|
||||
public static ContactId getContactId() {
|
||||
return new ContactId(nextContactId.getAndIncrement());
|
||||
}
|
||||
|
||||
public static Contact getContact() {
|
||||
return getContact(getAuthor(), random.nextBoolean());
|
||||
}
|
||||
|
||||
public static Contact getContact(Author a, boolean verified) {
|
||||
return getContact(getContactId(), a, verified);
|
||||
}
|
||||
|
||||
public static Contact getContact(ContactId c, Author a, boolean verified) {
|
||||
return new Contact(c, a, getRandomString(MAX_AUTHOR_NAME_LENGTH),
|
||||
getRandomBytes(MAX_PUBLIC_KEY_LENGTH), verified);
|
||||
}
|
||||
|
||||
public static double getMedian(Collection<? extends Number> samples) {
|
||||
int size = samples.size();
|
||||
if (size == 0) throw new IllegalArgumentException();
|
||||
|
||||
@@ -2,7 +2,7 @@ dependencyVerification {
|
||||
verify = [
|
||||
'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.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',
|
||||
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
||||
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
||||
|
||||
@@ -3,10 +3,10 @@ sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
|
||||
apply plugin: 'ru.vyarus.animalsniffer'
|
||||
apply plugin: 'net.ltgt.apt'
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'witness'
|
||||
apply from: 'witness.gradle'
|
||||
apply from: '../dagger.gradle'
|
||||
|
||||
dependencies {
|
||||
implementation project(path: ':bramble-api', configuration: 'default')
|
||||
@@ -17,7 +17,7 @@ dependencies {
|
||||
implementation 'org.whispersystems:curve25519-java:0.5.0'
|
||||
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 '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-junit4: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'
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||
import org.briarproject.bramble.plugin.PluginModule;
|
||||
import org.briarproject.bramble.properties.PropertiesModule;
|
||||
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.transport.TransportModule;
|
||||
import org.briarproject.bramble.versioning.VersioningModule;
|
||||
@@ -31,11 +31,11 @@ public interface BrambleCoreEagerSingletons {
|
||||
|
||||
void inject(ReportingModule.EagerSingletons init);
|
||||
|
||||
void inject(SyncModule.EagerSingletons init);
|
||||
|
||||
void inject(SystemModule.EagerSingletons init);
|
||||
|
||||
void inject(TransportModule.EagerSingletons init);
|
||||
|
||||
void inject(ValidationModule.EagerSingletons init);
|
||||
|
||||
void inject(VersioningModule.EagerSingletons init);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import org.briarproject.bramble.reporting.ReportingModule;
|
||||
import org.briarproject.bramble.settings.SettingsModule;
|
||||
import org.briarproject.bramble.socks.SocksModule;
|
||||
import org.briarproject.bramble.sync.SyncModule;
|
||||
import org.briarproject.bramble.sync.validation.ValidationModule;
|
||||
import org.briarproject.bramble.system.SystemModule;
|
||||
import org.briarproject.bramble.transport.TransportModule;
|
||||
import org.briarproject.bramble.versioning.VersioningModule;
|
||||
@@ -48,7 +47,6 @@ import dagger.Module;
|
||||
SyncModule.class,
|
||||
SystemModule.class,
|
||||
TransportModule.class,
|
||||
ValidationModule.class,
|
||||
VersioningModule.class
|
||||
})
|
||||
public class BrambleCoreModule {
|
||||
@@ -62,9 +60,9 @@ public class BrambleCoreModule {
|
||||
c.inject(new PluginModule.EagerSingletons());
|
||||
c.inject(new PropertiesModule.EagerSingletons());
|
||||
c.inject(new ReportingModule.EagerSingletons());
|
||||
c.inject(new SyncModule.EagerSingletons());
|
||||
c.inject(new SystemModule.EagerSingletons());
|
||||
c.inject(new TransportModule.EagerSingletons());
|
||||
c.inject(new ValidationModule.EagerSingletons());
|
||||
c.inject(new VersioningModule.EagerSingletons());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,13 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public void addLocalMessage(Message m, BdfDictionary metadata,
|
||||
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
|
||||
@@ -107,7 +113,15 @@ class ClientHelperImpl implements ClientHelper {
|
||||
|
||||
@Override
|
||||
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
|
||||
@@ -118,7 +132,15 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public BdfList getMessageAsList(MessageId m) throws DbException,
|
||||
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
|
||||
@@ -130,8 +152,15 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public BdfDictionary getGroupMetadataAsDictionary(GroupId g)
|
||||
throws DbException, FormatException {
|
||||
return db.transactionWithResult(true, txn ->
|
||||
getGroupMetadataAsDictionary(txn, g));
|
||||
BdfDictionary dictionary;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
dictionary = getGroupMetadataAsDictionary(txn, g);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,8 +173,15 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public BdfDictionary getMessageMetadataAsDictionary(MessageId m)
|
||||
throws DbException, FormatException {
|
||||
return db.transactionWithResult(true, txn ->
|
||||
getMessageMetadataAsDictionary(txn, m));
|
||||
BdfDictionary dictionary;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
dictionary = getMessageMetadataAsDictionary(txn, m);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -158,8 +194,15 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
|
||||
GroupId g) throws DbException, FormatException {
|
||||
return db.transactionWithResult(true, txn ->
|
||||
getMessageMetadataAsDictionary(txn, g));
|
||||
Map<MessageId, BdfDictionary> map;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
map = getMessageMetadataAsDictionary(txn, g);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -176,8 +219,15 @@ class ClientHelperImpl implements ClientHelper {
|
||||
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
|
||||
GroupId g, BdfDictionary query) throws DbException,
|
||||
FormatException {
|
||||
return db.transactionWithResult(true, txn ->
|
||||
getMessageMetadataAsDictionary(txn, g, query));
|
||||
Map<MessageId, BdfDictionary> map;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
map = getMessageMetadataAsDictionary(txn, g, query);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -195,7 +245,13 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
|
||||
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
|
||||
@@ -207,7 +263,13 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public void mergeMessageMetadata(MessageId m, BdfDictionary metadata)
|
||||
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
|
||||
|
||||
@@ -39,7 +39,8 @@ class ContactGroupFactoryImpl implements ContactGroupFactory {
|
||||
|
||||
@Override
|
||||
public Group createContactGroup(ClientId clientId, int majorVersion,
|
||||
Contact contact, AuthorId local) {
|
||||
Contact contact) {
|
||||
AuthorId local = contact.getLocalAuthorId();
|
||||
AuthorId remote = contact.getAuthor().getId();
|
||||
byte[] descriptor = createGroupDescriptor(local, remote);
|
||||
return groupFactory.createGroup(clientId, majorVersion, descriptor);
|
||||
|
||||
@@ -2,11 +2,10 @@ package org.briarproject.bramble.contact;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.client.ClientHelper;
|
||||
import org.briarproject.bramble.api.contact.ContactExchangeListener;
|
||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.contact.event.ContactExchangeFailedEvent;
|
||||
import org.briarproject.bramble.api.contact.event.ContactExchangeSucceededEvent;
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||
@@ -14,7 +13,7 @@ import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.db.ContactExistsException;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
@@ -65,7 +64,6 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
private final ClientHelper clientHelper;
|
||||
private final RecordReaderFactory recordReaderFactory;
|
||||
private final RecordWriterFactory recordWriterFactory;
|
||||
private final EventBus eventBus;
|
||||
private final Clock clock;
|
||||
private final ConnectionManager connectionManager;
|
||||
private final ContactManager contactManager;
|
||||
@@ -74,18 +72,18 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
private final StreamReaderFactory streamReaderFactory;
|
||||
private final StreamWriterFactory streamWriterFactory;
|
||||
|
||||
private volatile ContactExchangeListener listener;
|
||||
private volatile LocalAuthor localAuthor;
|
||||
private volatile DuplexTransportConnection conn;
|
||||
private volatile TransportId transportId;
|
||||
private volatile SecretKey masterKey;
|
||||
private volatile SecretKey masterSecret;
|
||||
private volatile boolean alice;
|
||||
|
||||
@Inject
|
||||
ContactExchangeTaskImpl(DatabaseComponent db, ClientHelper clientHelper,
|
||||
RecordReaderFactory recordReaderFactory,
|
||||
RecordWriterFactory recordWriterFactory, EventBus eventBus,
|
||||
Clock clock, ConnectionManager connectionManager,
|
||||
ContactManager contactManager,
|
||||
RecordWriterFactory recordWriterFactory, Clock clock,
|
||||
ConnectionManager connectionManager, ContactManager contactManager,
|
||||
TransportPropertyManager transportPropertyManager,
|
||||
CryptoComponent crypto, StreamReaderFactory streamReaderFactory,
|
||||
StreamWriterFactory streamWriterFactory) {
|
||||
@@ -93,7 +91,6 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
this.clientHelper = clientHelper;
|
||||
this.recordReaderFactory = recordReaderFactory;
|
||||
this.recordWriterFactory = recordWriterFactory;
|
||||
this.eventBus = eventBus;
|
||||
this.clock = clock;
|
||||
this.connectionManager = connectionManager;
|
||||
this.contactManager = contactManager;
|
||||
@@ -104,13 +101,15 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startExchange(LocalAuthor localAuthor, SecretKey masterKey,
|
||||
public void startExchange(ContactExchangeListener listener,
|
||||
LocalAuthor localAuthor, SecretKey masterSecret,
|
||||
DuplexTransportConnection conn, TransportId transportId,
|
||||
boolean alice) {
|
||||
this.listener = listener;
|
||||
this.localAuthor = localAuthor;
|
||||
this.conn = conn;
|
||||
this.transportId = transportId;
|
||||
this.masterKey = masterKey;
|
||||
this.masterSecret = masterSecret;
|
||||
this.alice = alice;
|
||||
start();
|
||||
}
|
||||
@@ -125,8 +124,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
out = conn.getWriter().getOutputStream();
|
||||
} catch (IOException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
listener.contactExchangeFailed();
|
||||
tryToClose(conn);
|
||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -136,15 +135,15 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
localProperties = transportPropertyManager.getLocalProperties();
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
||||
listener.contactExchangeFailed();
|
||||
tryToClose(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
// Derive the header keys for the transport streams
|
||||
SecretKey aliceHeaderKey = crypto.deriveKey(ALICE_KEY_LABEL, masterKey,
|
||||
new byte[] {PROTOCOL_VERSION});
|
||||
SecretKey bobHeaderKey = crypto.deriveKey(BOB_KEY_LABEL, masterKey,
|
||||
SecretKey aliceHeaderKey = crypto.deriveKey(ALICE_KEY_LABEL,
|
||||
masterSecret, new byte[] {PROTOCOL_VERSION});
|
||||
SecretKey bobHeaderKey = crypto.deriveKey(BOB_KEY_LABEL, masterSecret,
|
||||
new byte[] {PROTOCOL_VERSION});
|
||||
|
||||
// Create the readers
|
||||
@@ -159,13 +158,12 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
streamWriterFactory.createContactExchangeStreamWriter(out,
|
||||
alice ? aliceHeaderKey : bobHeaderKey);
|
||||
RecordWriter recordWriter =
|
||||
recordWriterFactory
|
||||
.createRecordWriter(streamWriter.getOutputStream());
|
||||
recordWriterFactory.createRecordWriter(streamWriter.getOutputStream());
|
||||
|
||||
// Derive the nonces to be signed
|
||||
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterKey,
|
||||
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
|
||||
new byte[] {PROTOCOL_VERSION});
|
||||
byte[] bobNonce = crypto.mac(BOB_NONCE_LABEL, masterKey,
|
||||
byte[] bobNonce = crypto.mac(BOB_NONCE_LABEL, masterSecret,
|
||||
new byte[] {PROTOCOL_VERSION});
|
||||
byte[] localNonce = alice ? aliceNonce : bobNonce;
|
||||
byte[] remoteNonce = alice ? bobNonce : aliceNonce;
|
||||
@@ -198,7 +196,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
||||
listener.contactExchangeFailed();
|
||||
tryToClose(conn);
|
||||
return;
|
||||
}
|
||||
@@ -206,7 +204,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
// Verify the contact's signature
|
||||
if (!verify(remoteInfo.author, remoteNonce, remoteInfo.signature)) {
|
||||
LOG.warning("Invalid signature");
|
||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
||||
listener.contactExchangeFailed();
|
||||
tryToClose(conn);
|
||||
return;
|
||||
}
|
||||
@@ -223,17 +221,15 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
conn);
|
||||
// Pseudonym exchange succeeded
|
||||
LOG.info("Pseudonym exchange succeeded");
|
||||
eventBus.broadcast(
|
||||
new ContactExchangeSucceededEvent(remoteInfo.author));
|
||||
listener.contactExchangeSucceeded(remoteInfo.author);
|
||||
} catch (ContactExistsException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
tryToClose(conn);
|
||||
eventBus.broadcast(
|
||||
new ContactExchangeFailedEvent(remoteInfo.author));
|
||||
listener.duplicateContact(remoteInfo.author);
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
tryToClose(conn);
|
||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
||||
listener.contactExchangeFailed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,13 +287,19 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
private ContactId addContact(Author remoteAuthor, long timestamp,
|
||||
Map<TransportId, TransportProperties> remoteProperties)
|
||||
throws DbException {
|
||||
return db.transactionWithResult(false, txn -> {
|
||||
ContactId contactId = contactManager.addContact(txn, remoteAuthor,
|
||||
masterKey, timestamp, alice, true, true);
|
||||
ContactId contactId;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
contactId = contactManager.addContact(txn, remoteAuthor,
|
||||
localAuthor.getId(), masterSecret, timestamp, alice,
|
||||
true, true);
|
||||
transportPropertyManager.addRemoteProperties(txn, contactId,
|
||||
remoteProperties);
|
||||
return contactId;
|
||||
});
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return contactId;
|
||||
}
|
||||
|
||||
private void tryToClose(DuplexTransportConnection conn) {
|
||||
|
||||
@@ -3,61 +3,36 @@ package org.briarproject.bramble.contact;
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
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.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
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.transport.KeyManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
|
||||
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.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
|
||||
@NotNullByDefault
|
||||
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 KeyManager keyManager;
|
||||
private final IdentityManager identityManager;
|
||||
private final List<ContactHook> hooks;
|
||||
|
||||
@Inject
|
||||
ContactManagerImpl(DatabaseComponent db, KeyManager keyManager,
|
||||
IdentityManager identityManager) {
|
||||
ContactManagerImpl(DatabaseComponent db, KeyManager keyManager) {
|
||||
this.db = db;
|
||||
this.keyManager = keyManager;
|
||||
this.identityManager = identityManager;
|
||||
hooks = new CopyOnWriteArrayList<>();
|
||||
}
|
||||
|
||||
@@ -67,127 +42,130 @@ class ContactManagerImpl implements ContactManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactId addContact(Transaction txn, Author a, SecretKey rootKey,
|
||||
public ContactId addContact(Transaction txn, Author remote, AuthorId local,
|
||||
SecretKey master, long timestamp, boolean alice, boolean verified,
|
||||
boolean active) throws DbException {
|
||||
ContactId c = db.addContact(txn, remote, local, verified, active);
|
||||
keyManager.addContact(txn, c, master, timestamp, alice, active);
|
||||
Contact contact = db.getContact(txn, c);
|
||||
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactId addContact(Transaction txn, Author remote, AuthorId local,
|
||||
boolean verified, boolean active) throws DbException {
|
||||
ContactId c = db.addContact(txn, remote, local, verified, active);
|
||||
Contact contact = db.getContact(txn, c);
|
||||
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactId addContact(Author remote, AuthorId local, SecretKey master,
|
||||
long timestamp, boolean alice, boolean verified, boolean active)
|
||||
throws DbException {
|
||||
ContactId c = db.addContact(txn, a, verified);
|
||||
keyManager.addContact(txn, c, rootKey, timestamp, alice, active);
|
||||
Contact contact = db.getContact(txn, c);
|
||||
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactId addContact(Transaction txn, Author a, boolean verified)
|
||||
throws DbException {
|
||||
ContactId c = db.addContact(txn, a, verified);
|
||||
Contact contact = db.getContact(txn, c);
|
||||
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactId addContact(Author a, SecretKey rootKey, long timestamp,
|
||||
boolean alice, boolean verified, boolean active)
|
||||
throws DbException {
|
||||
return db.transactionWithResult(false, txn ->
|
||||
addContact(txn, a, rootKey, timestamp, alice,
|
||||
verified, active));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteContactLink() {
|
||||
// TODO replace with real implementation
|
||||
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));
|
||||
ContactId c;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
c = addContact(txn, remote, local, master, timestamp, alice,
|
||||
verified, active);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return new String(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, new byte[MAX_PUBLIC_KEY_LENGTH], 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
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
public Contact getContact(AuthorId a) throws DbException {
|
||||
return db.transactionWithResult(true, txn -> getContact(txn, a));
|
||||
public Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId)
|
||||
throws DbException {
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
Contact c = getContact(txn, remoteAuthorId, localAuthorId);
|
||||
db.commitTransaction(txn);
|
||||
return c;
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Contact getContact(Transaction txn, AuthorId a) throws DbException {
|
||||
return db.getContact(txn, a);
|
||||
public Contact getContact(Transaction txn, AuthorId remoteAuthorId,
|
||||
AuthorId localAuthorId) throws DbException {
|
||||
Collection<Contact> contacts =
|
||||
db.getContactsByAuthorId(txn, remoteAuthorId);
|
||||
for (Contact c : contacts) {
|
||||
if (c.getLocalAuthorId().equals(localAuthorId)) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
throw new NoSuchContactException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Contact> getContacts() throws DbException {
|
||||
return db.transactionWithResult(true, db::getContacts);
|
||||
public Collection<Contact> getActiveContacts() throws DbException {
|
||||
Collection<Contact> contacts;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
contacts = db.getContacts(txn);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
List<Contact> active = new ArrayList<>(contacts.size());
|
||||
for (Contact c : contacts) if (c.isActive()) active.add(c);
|
||||
return active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeContact(ContactId c) throws DbException {
|
||||
db.transaction(false, txn -> removeContact(txn, c));
|
||||
}
|
||||
|
||||
@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();
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
removeContact(txn, c);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
db.setContactAlias(txn, c, alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContactAlias(ContactId c, @Nullable String alias)
|
||||
public void setContactActive(Transaction txn, ContactId c, boolean active)
|
||||
throws DbException {
|
||||
db.transaction(false, txn -> setContactAlias(txn, c, alias));
|
||||
db.setContactActive(txn, c, active);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contactExists(Transaction txn, AuthorId a)
|
||||
throws DbException {
|
||||
return db.containsContact(txn, a);
|
||||
public boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
|
||||
AuthorId localAuthorId) throws DbException {
|
||||
return db.containsContact(txn, remoteAuthorId, localAuthorId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contactExists(AuthorId a) throws DbException {
|
||||
return db.transactionWithResult(true, txn -> contactExists(txn, a));
|
||||
public boolean contactExists(AuthorId remoteAuthorId,
|
||||
AuthorId localAuthorId) throws DbException {
|
||||
boolean exists;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
exists = contactExists(txn, remoteAuthorId, localAuthorId);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -198,23 +176,4 @@ class ContactManagerImpl implements ContactManager {
|
||||
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);
|
||||
if (db.containsContact(txn, authorId)) {
|
||||
Contact c = db.getContact(txn, authorId);
|
||||
if (c.isVerified()) return new AuthorInfo(VERIFIED, c.getAlias());
|
||||
else return new AuthorInfo(UNVERIFIED, c.getAlias());
|
||||
}
|
||||
return new AuthorInfo(UNKNOWN);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,22 +4,18 @@ import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.crypto.TransportCrypto;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.transport.HandshakeKeys;
|
||||
import org.briarproject.bramble.api.transport.IncomingKeys;
|
||||
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
||||
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.digests.Blake2bDigest;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.lang.System.arraycopy;
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_HANDSHAKE_HEADER_LABEL;
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_HANDSHAKE_TAG_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.BOB_HANDSHAKE_HEADER_LABEL;
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_HANDSHAKE_TAG_LABEL;
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_HEADER_LABEL;
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_TAG_LABEL;
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.ROTATE_LABEL;
|
||||
@@ -28,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.MAX_16_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 {
|
||||
|
||||
@@ -43,44 +36,45 @@ class TransportCryptoImpl implements TransportCrypto {
|
||||
|
||||
@Override
|
||||
public TransportKeys deriveTransportKeys(TransportId t,
|
||||
SecretKey rootKey, long timePeriod, boolean weAreAlice,
|
||||
SecretKey master, long rotationPeriod, boolean alice,
|
||||
boolean active) {
|
||||
// Keys for the previous period are derived from the root key
|
||||
SecretKey inTagPrev = deriveTagKey(rootKey, t, !weAreAlice);
|
||||
SecretKey inHeaderPrev = deriveHeaderKey(rootKey, t, !weAreAlice);
|
||||
SecretKey outTagPrev = deriveTagKey(rootKey, t, weAreAlice);
|
||||
SecretKey outHeaderPrev = deriveHeaderKey(rootKey, t, weAreAlice);
|
||||
// Keys for the previous period are derived from the master secret
|
||||
SecretKey inTagPrev = deriveTagKey(master, t, !alice);
|
||||
SecretKey inHeaderPrev = deriveHeaderKey(master, t, !alice);
|
||||
SecretKey outTagPrev = deriveTagKey(master, t, alice);
|
||||
SecretKey outHeaderPrev = deriveHeaderKey(master, t, alice);
|
||||
// Derive the keys for the current and next periods
|
||||
SecretKey inTagCurr = rotateKey(inTagPrev, timePeriod);
|
||||
SecretKey inHeaderCurr = rotateKey(inHeaderPrev, timePeriod);
|
||||
SecretKey inTagNext = rotateKey(inTagCurr, timePeriod + 1);
|
||||
SecretKey inHeaderNext = rotateKey(inHeaderCurr, timePeriod + 1);
|
||||
SecretKey outTagCurr = rotateKey(outTagPrev, timePeriod);
|
||||
SecretKey outHeaderCurr = rotateKey(outHeaderPrev, timePeriod);
|
||||
SecretKey inTagCurr = rotateKey(inTagPrev, rotationPeriod);
|
||||
SecretKey inHeaderCurr = rotateKey(inHeaderPrev, rotationPeriod);
|
||||
SecretKey inTagNext = rotateKey(inTagCurr, rotationPeriod + 1);
|
||||
SecretKey inHeaderNext = rotateKey(inHeaderCurr, rotationPeriod + 1);
|
||||
SecretKey outTagCurr = rotateKey(outTagPrev, rotationPeriod);
|
||||
SecretKey outHeaderCurr = rotateKey(outHeaderPrev, rotationPeriod);
|
||||
// Initialise the reordering windows and stream counters
|
||||
IncomingKeys inPrev = new IncomingKeys(inTagPrev, inHeaderPrev,
|
||||
timePeriod - 1);
|
||||
rotationPeriod - 1);
|
||||
IncomingKeys inCurr = new IncomingKeys(inTagCurr, inHeaderCurr,
|
||||
timePeriod);
|
||||
rotationPeriod);
|
||||
IncomingKeys inNext = new IncomingKeys(inTagNext, inHeaderNext,
|
||||
timePeriod + 1);
|
||||
rotationPeriod + 1);
|
||||
OutgoingKeys outCurr = new OutgoingKeys(outTagCurr, outHeaderCurr,
|
||||
timePeriod, active);
|
||||
rotationPeriod, active);
|
||||
// Collect and return the keys
|
||||
return new TransportKeys(t, inPrev, inCurr, inNext, outCurr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod) {
|
||||
if (k.getTimePeriod() >= timePeriod) return k;
|
||||
public TransportKeys rotateTransportKeys(TransportKeys k,
|
||||
long rotationPeriod) {
|
||||
if (k.getRotationPeriod() >= rotationPeriod) return k;
|
||||
IncomingKeys inPrev = k.getPreviousIncomingKeys();
|
||||
IncomingKeys inCurr = k.getCurrentIncomingKeys();
|
||||
IncomingKeys inNext = k.getNextIncomingKeys();
|
||||
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
|
||||
long startPeriod = outCurr.getTimePeriod();
|
||||
long startPeriod = outCurr.getRotationPeriod();
|
||||
boolean active = outCurr.isActive();
|
||||
// Rotate the keys
|
||||
for (long p = startPeriod + 1; p <= timePeriod; p++) {
|
||||
for (long p = startPeriod + 1; p <= rotationPeriod; p++) {
|
||||
inPrev = inCurr;
|
||||
inCurr = inNext;
|
||||
SecretKey inNextTag = rotateKey(inNext.getTagKey(), p + 1);
|
||||
@@ -95,117 +89,24 @@ class TransportCryptoImpl implements TransportCrypto {
|
||||
outCurr);
|
||||
}
|
||||
|
||||
private SecretKey rotateKey(SecretKey k, long timePeriod) {
|
||||
private SecretKey rotateKey(SecretKey k, long rotationPeriod) {
|
||||
byte[] period = new byte[INT_64_BYTES];
|
||||
writeUint64(timePeriod, period, 0);
|
||||
ByteUtils.writeUint64(rotationPeriod, period, 0);
|
||||
return crypto.deriveKey(ROTATE_LABEL, k, period);
|
||||
}
|
||||
|
||||
private SecretKey deriveTagKey(SecretKey rootKey, TransportId t,
|
||||
boolean keyBelongsToAlice) {
|
||||
String label = keyBelongsToAlice ? ALICE_TAG_LABEL : BOB_TAG_LABEL;
|
||||
byte[] id = toUtf8(t.getString());
|
||||
return crypto.deriveKey(label, rootKey, id);
|
||||
private SecretKey deriveTagKey(SecretKey master, TransportId t,
|
||||
boolean alice) {
|
||||
String label = alice ? ALICE_TAG_LABEL : BOB_TAG_LABEL;
|
||||
byte[] id = StringUtils.toUtf8(t.getString());
|
||||
return crypto.deriveKey(label, master, id);
|
||||
}
|
||||
|
||||
private SecretKey deriveHeaderKey(SecretKey rootKey, TransportId t,
|
||||
boolean keyBelongsToAlice) {
|
||||
String label = keyBelongsToAlice ? ALICE_HEADER_LABEL :
|
||||
BOB_HEADER_LABEL;
|
||||
byte[] id = toUtf8(t.getString());
|
||||
return crypto.deriveKey(label, rootKey, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandshakeKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey,
|
||||
long timePeriod, boolean weAreAlice) {
|
||||
if (timePeriod < 1) throw new IllegalArgumentException();
|
||||
IncomingKeys inPrev = deriveIncomingHandshakeKeys(t, rootKey,
|
||||
weAreAlice, timePeriod - 1);
|
||||
IncomingKeys inCurr = deriveIncomingHandshakeKeys(t, rootKey,
|
||||
weAreAlice, timePeriod);
|
||||
IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey,
|
||||
weAreAlice, timePeriod + 1);
|
||||
OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey,
|
||||
weAreAlice, timePeriod);
|
||||
return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, rootKey,
|
||||
weAreAlice);
|
||||
}
|
||||
|
||||
private IncomingKeys deriveIncomingHandshakeKeys(TransportId t,
|
||||
SecretKey rootKey, boolean weAreAlice, long timePeriod) {
|
||||
SecretKey tag = deriveHandshakeTagKey(t, rootKey, !weAreAlice,
|
||||
timePeriod);
|
||||
SecretKey header = deriveHandshakeHeaderKey(t, rootKey, !weAreAlice,
|
||||
timePeriod);
|
||||
return new IncomingKeys(tag, header, timePeriod);
|
||||
}
|
||||
|
||||
private OutgoingKeys deriveOutgoingHandshakeKeys(TransportId t,
|
||||
SecretKey rootKey, boolean weAreAlice, long timePeriod) {
|
||||
SecretKey tag = deriveHandshakeTagKey(t, rootKey, weAreAlice,
|
||||
timePeriod);
|
||||
SecretKey header = deriveHandshakeHeaderKey(t, rootKey, weAreAlice,
|
||||
timePeriod);
|
||||
return new OutgoingKeys(tag, header, timePeriod, true);
|
||||
}
|
||||
|
||||
private SecretKey deriveHandshakeTagKey(TransportId t, SecretKey rootKey,
|
||||
boolean keyBelongsToAlice, long timePeriod) {
|
||||
String label = keyBelongsToAlice ? ALICE_HANDSHAKE_TAG_LABEL :
|
||||
BOB_HANDSHAKE_TAG_LABEL;
|
||||
byte[] id = toUtf8(t.getString());
|
||||
byte[] period = new byte[INT_64_BYTES];
|
||||
writeUint64(timePeriod, period, 0);
|
||||
return crypto.deriveKey(label, rootKey, id, period);
|
||||
}
|
||||
|
||||
private SecretKey deriveHandshakeHeaderKey(TransportId t, SecretKey rootKey,
|
||||
boolean keyBelongsToAlice, long timePeriod) {
|
||||
String label = keyBelongsToAlice ? ALICE_HANDSHAKE_HEADER_LABEL :
|
||||
BOB_HANDSHAKE_HEADER_LABEL;
|
||||
byte[] id = toUtf8(t.getString());
|
||||
byte[] period = new byte[INT_64_BYTES];
|
||||
writeUint64(timePeriod, period, 0);
|
||||
return crypto.deriveKey(label, rootKey, id, period);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandshakeKeys updateHandshakeKeys(HandshakeKeys k, long timePeriod) {
|
||||
long elapsed = timePeriod - k.getTimePeriod();
|
||||
TransportId t = k.getTransportId();
|
||||
SecretKey rootKey = k.getRootKey();
|
||||
boolean weAreAlice = k.isAlice();
|
||||
if (elapsed <= 0) {
|
||||
// The keys are for the given period or later - don't update them
|
||||
return k;
|
||||
} else if (elapsed == 1) {
|
||||
// The keys are one period old - shift by one period, keeping the
|
||||
// reordering windows for keys we retain
|
||||
IncomingKeys inPrev = k.getCurrentIncomingKeys();
|
||||
IncomingKeys inCurr = k.getNextIncomingKeys();
|
||||
IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey,
|
||||
weAreAlice, timePeriod + 1);
|
||||
OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey,
|
||||
weAreAlice, timePeriod);
|
||||
return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr,
|
||||
rootKey, weAreAlice);
|
||||
} else if (elapsed == 2) {
|
||||
// The keys are two periods old - shift by two periods, keeping
|
||||
// the reordering windows for keys we retain
|
||||
IncomingKeys inPrev = k.getNextIncomingKeys();
|
||||
IncomingKeys inCurr = deriveIncomingHandshakeKeys(t, rootKey,
|
||||
weAreAlice, timePeriod);
|
||||
IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey,
|
||||
weAreAlice, timePeriod + 1);
|
||||
OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey,
|
||||
weAreAlice, timePeriod);
|
||||
return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr,
|
||||
rootKey, weAreAlice);
|
||||
} else {
|
||||
// The keys are more than two periods old - derive fresh keys
|
||||
return deriveHandshakeKeys(t, rootKey, timePeriod, weAreAlice);
|
||||
}
|
||||
private SecretKey deriveHeaderKey(SecretKey master, TransportId t,
|
||||
boolean alice) {
|
||||
String label = alice ? ALICE_HEADER_LABEL : BOB_HEADER_LABEL;
|
||||
byte[] id = StringUtils.toUtf8(t.getString());
|
||||
return crypto.deriveKey(label, master, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -224,14 +125,14 @@ class TransportCryptoImpl implements TransportCrypto {
|
||||
// The input is the protocol version as a 16-bit integer, followed by
|
||||
// the stream number as a 64-bit integer
|
||||
byte[] protocolVersionBytes = new byte[INT_16_BYTES];
|
||||
writeUint16(protocolVersion, protocolVersionBytes, 0);
|
||||
ByteUtils.writeUint16(protocolVersion, protocolVersionBytes, 0);
|
||||
prf.update(protocolVersionBytes, 0, protocolVersionBytes.length);
|
||||
byte[] streamNumberBytes = new byte[INT_64_BYTES];
|
||||
writeUint64(streamNumber, streamNumberBytes, 0);
|
||||
ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0);
|
||||
prf.update(streamNumberBytes, 0, streamNumberBytes.length);
|
||||
byte[] mac = new byte[macLength];
|
||||
prf.doFinal(mac, 0);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_8;
|
||||
import static org.briarproject.bramble.data.Types.TRUE;
|
||||
import static org.briarproject.bramble.util.StringUtils.fromUtf8;
|
||||
|
||||
@NotThreadSafe
|
||||
@NotNullByDefault
|
||||
@@ -254,7 +253,7 @@ class BdfReaderImpl implements BdfReader {
|
||||
if (length < 0 || length > maxBufferSize) throw new FormatException();
|
||||
if (length == 0) return "";
|
||||
readIntoBuffer(length);
|
||||
return fromUtf8(buf, 0, length);
|
||||
return new String(buf, 0, length, "UTF-8");
|
||||
}
|
||||
|
||||
private int readStringLength() throws IOException {
|
||||
|
||||
@@ -2,13 +2,9 @@ package org.briarproject.bramble.db;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.PendingContact;
|
||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||
import org.briarproject.bramble.api.contact.PendingContactState;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DataTooNewException;
|
||||
import org.briarproject.bramble.api.db.DataTooOldException;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.MessageDeletedException;
|
||||
import org.briarproject.bramble.api.db.Metadata;
|
||||
@@ -26,12 +22,9 @@ import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||
import org.briarproject.bramble.api.transport.HandshakeKeySet;
|
||||
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
|
||||
import org.briarproject.bramble.api.transport.HandshakeKeys;
|
||||
import org.briarproject.bramble.api.transport.TransportKeySet;
|
||||
import org.briarproject.bramble.api.transport.TransportKeySetId;
|
||||
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
||||
import org.briarproject.bramble.api.transport.KeySet;
|
||||
import org.briarproject.bramble.api.transport.KeySetId;
|
||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -40,14 +33,11 @@ import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A low-level interface to the database ({@link DatabaseComponent} provides a
|
||||
* high-level interface).
|
||||
* <p/>
|
||||
* Most operations take a transaction argument, which is obtained by calling
|
||||
* {@link #startTransaction()}. Every transaction must be terminated by calling
|
||||
* either {@link #abortTransaction(Object) abortTransaction(T)} or
|
||||
* {@link #commitTransaction(Object) commitTransaction(T)}, even if an
|
||||
* exception is thrown.
|
||||
* A low-level interface to the database (DatabaseComponent provides a
|
||||
* high-level interface). Most operations take a transaction argument, which is
|
||||
* obtained by calling {@link #startTransaction()}. Every transaction must be
|
||||
* terminated by calling either {@link #abortTransaction(Object) abortTransaction(T)} or
|
||||
* {@link #commitTransaction(Object) commitTransaction(T)}, even if an exception is thrown.
|
||||
*/
|
||||
@NotNullByDefault
|
||||
interface Database<T> {
|
||||
@@ -87,10 +77,11 @@ interface Database<T> {
|
||||
void commitTransaction(T txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a contact with the given pseudonym and returns an ID for the
|
||||
* contact.
|
||||
* Stores a contact associated with the given local and remote pseudonyms,
|
||||
* and returns an ID for the contact.
|
||||
*/
|
||||
ContactId addContact(T txn, Author a, boolean verified) throws DbException;
|
||||
ContactId addContact(T txn, Author remote, AuthorId local, boolean verified,
|
||||
boolean active) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a group.
|
||||
@@ -104,20 +95,6 @@ interface Database<T> {
|
||||
void addGroupVisibility(T txn, ContactId c, GroupId g, boolean shared)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Stores the given handshake keys for the given contact and returns a
|
||||
* key set ID.
|
||||
*/
|
||||
HandshakeKeySetId addHandshakeKeys(T txn, ContactId c, HandshakeKeys k)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Stores the given handshake keys for the given pending contact and
|
||||
* returns a key set ID.
|
||||
*/
|
||||
HandshakeKeySetId addHandshakeKeys(T txn, PendingContactId p,
|
||||
HandshakeKeys k) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a local pseudonym.
|
||||
*/
|
||||
@@ -129,7 +106,7 @@ interface Database<T> {
|
||||
* @param sender the contact from whom the message was received, or null
|
||||
* 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;
|
||||
|
||||
/**
|
||||
@@ -137,18 +114,13 @@ interface Database<T> {
|
||||
* in the given state.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
void addOfferedMessage(T txn, ContactId c, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a pending contact.
|
||||
*/
|
||||
void addPendingContact(T txn, PendingContact p) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a transport.
|
||||
*/
|
||||
@@ -159,15 +131,17 @@ interface Database<T> {
|
||||
* Stores the given transport keys for the given contact and returns a
|
||||
* key set ID.
|
||||
*/
|
||||
TransportKeySetId addTransportKeys(T txn, ContactId c, TransportKeys k)
|
||||
KeySetId addTransportKeys(T txn, ContactId c, TransportKeys k)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given contact.
|
||||
* Returns true if the database contains the given contact for the given
|
||||
* local pseudonym.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
boolean containsContact(T txn, AuthorId a) throws DbException;
|
||||
boolean containsContact(T txn, AuthorId remote, AuthorId local)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given contact.
|
||||
@@ -197,14 +171,6 @@ interface Database<T> {
|
||||
*/
|
||||
boolean containsMessage(T txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given pending contact.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
boolean containsPendingContact(T txn, PendingContactId p)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given transport.
|
||||
* <p/>
|
||||
@@ -249,13 +215,6 @@ interface Database<T> {
|
||||
*/
|
||||
Contact getContact(T txn, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the contact with the given author ID.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Contact getContact(T txn, AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all contacts.
|
||||
* <p/>
|
||||
@@ -263,6 +222,28 @@ interface Database<T> {
|
||||
*/
|
||||
Collection<Contact> getContacts(T txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns a possibly empty collection of contacts with the given author ID.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Collection<Contact> getContactsByAuthorId(T txn, AuthorId remote)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all contacts associated with the given local pseudonym.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Collection<ContactId> getContacts(T txn, AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the amount of free storage space available to the database, in
|
||||
* 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.
|
||||
*/
|
||||
long getFreeSpace() throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the group with the given ID.
|
||||
* <p/>
|
||||
@@ -303,14 +284,6 @@ interface Database<T> {
|
||||
Map<ContactId, Boolean> getGroupVisibility(T txn, GroupId g)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all handshake keys for the given transport.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Collection<HandshakeKeySet> getHandshakeKeys(T txn, TransportId t)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the local pseudonym with the given ID.
|
||||
* <p/>
|
||||
@@ -337,11 +310,11 @@ interface Database<T> {
|
||||
/**
|
||||
* Returns the IDs and states of all dependencies of the given message.
|
||||
* For missing dependencies and dependencies in other groups, the state
|
||||
* {@link MessageState UNKNOWN} is returned.
|
||||
* {@link State UNKNOWN} is returned.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Map<MessageId, MessageState> getMessageDependencies(T txn, MessageId m)
|
||||
Map<MessageId, State> getMessageDependencies(T txn, MessageId m)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
@@ -351,7 +324,7 @@ interface Database<T> {
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Map<MessageId, MessageState> getMessageDependents(T txn, MessageId m)
|
||||
Map<MessageId, State> getMessageDependents(T txn, MessageId m)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
@@ -410,7 +383,7 @@ interface Database<T> {
|
||||
* <p/>
|
||||
* 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
|
||||
@@ -501,13 +474,6 @@ interface Database<T> {
|
||||
*/
|
||||
long getNextSendTime(T txn, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all pending contacts.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Collection<PendingContact> getPendingContacts(T txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the IDs of some messages that are eligible to be sent to the
|
||||
* given contact and have been requested by the contact, up to the given
|
||||
@@ -530,19 +496,13 @@ interface Database<T> {
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Collection<TransportKeySet> getTransportKeys(T txn, TransportId t)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Increments the outgoing stream counter for the given handshake keys.
|
||||
*/
|
||||
void incrementStreamCounter(T txn, TransportId t, HandshakeKeySetId k)
|
||||
Collection<KeySet> getTransportKeys(T txn, TransportId t)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Increments the outgoing stream counter for the given transport keys.
|
||||
*/
|
||||
void incrementStreamCounter(T txn, TransportId t, TransportKeySetId k)
|
||||
void incrementStreamCounter(T txn, TransportId t, KeySetId k)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
@@ -611,12 +571,6 @@ interface Database<T> {
|
||||
void removeGroupVisibility(T txn, ContactId c, GroupId g)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Removes the given handshake keys from the database.
|
||||
*/
|
||||
void removeHandshakeKeys(T txn, TransportId t, HandshakeKeySetId k)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a local pseudonym (and all associated state) from the database.
|
||||
*/
|
||||
@@ -634,11 +588,6 @@ interface Database<T> {
|
||||
void removeOfferedMessages(T txn, ContactId c,
|
||||
Collection<MessageId> requested) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a pending contact (and all associated state) from the database.
|
||||
*/
|
||||
void removePendingContact(T txn, PendingContactId p) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a transport (and all associated state) from the database.
|
||||
*/
|
||||
@@ -647,7 +596,7 @@ interface Database<T> {
|
||||
/**
|
||||
* Removes the given transport keys from the database.
|
||||
*/
|
||||
void removeTransportKeys(T txn, TransportId t, TransportKeySetId k)
|
||||
void removeTransportKeys(T txn, TransportId t, KeySetId k)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
@@ -662,9 +611,9 @@ interface Database<T> {
|
||||
void setContactVerified(T txn, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Sets an alias name for a contact.
|
||||
* Marks the given contact as active or inactive.
|
||||
*/
|
||||
void setContactAlias(T txn, ContactId c, @Nullable String alias)
|
||||
void setContactActive(T txn, ContactId c, boolean active)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
@@ -682,33 +631,19 @@ interface Database<T> {
|
||||
/**
|
||||
* Sets the validation and delivery state of the given message.
|
||||
*/
|
||||
void setMessageState(T txn, MessageId m, MessageState state)
|
||||
throws DbException;
|
||||
void setMessageState(T txn, MessageId m, State state) throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the state of the given pending contact.
|
||||
* Sets the reordering window for the given key set and transport in the
|
||||
* given rotation period.
|
||||
*/
|
||||
void setPendingContactState(T txn, PendingContactId p,
|
||||
PendingContactState state) throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the reordering window for the given transport key set in the given
|
||||
* time period.
|
||||
*/
|
||||
void setReorderingWindow(T txn, TransportKeySetId k, TransportId t,
|
||||
long timePeriod, long base, byte[] bitmap) throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the reordering window for the given handshake key set in the given
|
||||
* time period.
|
||||
*/
|
||||
void setReorderingWindow(T txn, HandshakeKeySetId k, TransportId t,
|
||||
long timePeriod, long base, byte[] bitmap) throws DbException;
|
||||
void setReorderingWindow(T txn, KeySetId k, TransportId t,
|
||||
long rotationPeriod, long base, byte[] bitmap) throws DbException;
|
||||
|
||||
/**
|
||||
* Marks the given transport keys as usable for outgoing streams.
|
||||
*/
|
||||
void setTransportKeysActive(T txn, TransportId t, TransportKeySetId k)
|
||||
void setTransportKeysActive(T txn, TransportId t, KeySetId k)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
@@ -719,13 +654,8 @@ interface Database<T> {
|
||||
void updateExpiryTimeAndEta(T txn, ContactId c, MessageId m, int maxLatency)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Updates the given handshake keys.
|
||||
*/
|
||||
void updateHandshakeKeys(T txn, HandshakeKeySet ks) throws DbException;
|
||||
|
||||
/**
|
||||
* Updates the given transport keys following key rotation.
|
||||
*/
|
||||
void updateTransportKeys(T txn, TransportKeySet ks) throws DbException;
|
||||
void updateTransportKeys(T txn, KeySet ks) throws DbException;
|
||||
}
|
||||
|
||||
@@ -2,34 +2,26 @@ package org.briarproject.bramble.db;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.PendingContact;
|
||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
||||
import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.CommitAction;
|
||||
import org.briarproject.bramble.api.db.CommitAction.Visitor;
|
||||
import org.briarproject.bramble.api.db.ContactExistsException;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbCallable;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.DbRunnable;
|
||||
import org.briarproject.bramble.api.db.EventAction;
|
||||
import org.briarproject.bramble.api.db.Metadata;
|
||||
import org.briarproject.bramble.api.db.MigrationListener;
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||
import org.briarproject.bramble.api.db.NoSuchGroupException;
|
||||
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
|
||||
import org.briarproject.bramble.api.db.NoSuchMessageException;
|
||||
import org.briarproject.bramble.api.db.NoSuchPendingContactException;
|
||||
import org.briarproject.bramble.api.db.NoSuchTransportException;
|
||||
import org.briarproject.bramble.api.db.NullableDbCallable;
|
||||
import org.briarproject.bramble.api.db.PendingContactExistsException;
|
||||
import org.briarproject.bramble.api.db.TaskAction;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.event.EventExecutor;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
@@ -50,6 +42,7 @@ import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||
import org.briarproject.bramble.api.sync.Offer;
|
||||
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.GroupRemovedEvent;
|
||||
import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent;
|
||||
@@ -61,12 +54,8 @@ import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
|
||||
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
|
||||
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
|
||||
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
|
||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||
import org.briarproject.bramble.api.transport.HandshakeKeySet;
|
||||
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
|
||||
import org.briarproject.bramble.api.transport.HandshakeKeys;
|
||||
import org.briarproject.bramble.api.transport.TransportKeySet;
|
||||
import org.briarproject.bramble.api.transport.TransportKeySetId;
|
||||
import org.briarproject.bramble.api.transport.KeySet;
|
||||
import org.briarproject.bramble.api.transport.KeySetId;
|
||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -74,7 +63,6 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.logging.Logger;
|
||||
@@ -86,8 +74,8 @@ import javax.inject.Inject;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
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.validation.MessageState.DELIVERED;
|
||||
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
||||
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.util.LogUtils.logDuration;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
@@ -103,29 +91,25 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
private final Database<T> db;
|
||||
private final Class<T> txnClass;
|
||||
private final EventBus eventBus;
|
||||
private final Executor eventExecutor;
|
||||
private final ShutdownManager shutdownManager;
|
||||
private final ShutdownManager shutdown;
|
||||
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||
private final ReentrantReadWriteLock lock =
|
||||
new ReentrantReadWriteLock(true);
|
||||
private final Visitor visitor = new CommitActionVisitor();
|
||||
|
||||
@Inject
|
||||
DatabaseComponentImpl(Database<T> db, Class<T> txnClass, EventBus eventBus,
|
||||
@EventExecutor Executor eventExecutor,
|
||||
ShutdownManager shutdownManager) {
|
||||
ShutdownManager shutdown) {
|
||||
this.db = db;
|
||||
this.txnClass = txnClass;
|
||||
this.eventBus = eventBus;
|
||||
this.eventExecutor = eventExecutor;
|
||||
this.shutdownManager = shutdownManager;
|
||||
this.shutdown = shutdown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||
throws DbException {
|
||||
boolean reopened = db.open(key, listener);
|
||||
shutdownManager.addShutdownHook(() -> {
|
||||
shutdown.addShutdownHook(() -> {
|
||||
try {
|
||||
close();
|
||||
} catch (DbException e) {
|
||||
@@ -175,16 +159,13 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
public void endTransaction(Transaction transaction) {
|
||||
try {
|
||||
T txn = txnClass.cast(transaction.unbox());
|
||||
if (transaction.isCommitted()) {
|
||||
for (CommitAction a : transaction.getActions())
|
||||
a.accept(visitor);
|
||||
} else {
|
||||
db.abortTransaction(txn);
|
||||
}
|
||||
if (!transaction.isCommitted()) db.abortTransaction(txn);
|
||||
} finally {
|
||||
if (transaction.isReadOnly()) lock.readLock().unlock();
|
||||
else lock.writeLock().unlock();
|
||||
}
|
||||
if (transaction.isCommitted())
|
||||
for (Event e : transaction.getEvents()) eventBus.broadcast(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -212,36 +193,26 @@ 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) {
|
||||
if (transaction.isCommitted()) throw new IllegalStateException();
|
||||
return txnClass.cast(transaction.unbox());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactId addContact(Transaction transaction, Author a,
|
||||
boolean verified) throws DbException {
|
||||
public ContactId addContact(Transaction transaction, Author remote,
|
||||
AuthorId local, boolean verified, boolean active)
|
||||
throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (db.containsLocalAuthor(txn, a.getId()))
|
||||
if (!db.containsLocalAuthor(txn, local))
|
||||
throw new NoSuchLocalAuthorException();
|
||||
if (db.containsLocalAuthor(txn, remote.getId()))
|
||||
throw new ContactExistsException();
|
||||
if (db.containsContact(txn, a.getId()))
|
||||
if (db.containsContact(txn, remote.getId(), local))
|
||||
throw new ContactExistsException();
|
||||
ContactId c = db.addContact(txn, a, verified);
|
||||
transaction.attach(new ContactAddedEvent(c));
|
||||
ContactId c = db.addContact(txn, remote, local, verified, active);
|
||||
transaction.attach(new ContactAddedEvent(c, active));
|
||||
if (active) transaction.attach(new ContactStatusChangedEvent(c, true));
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -255,30 +226,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandshakeKeySetId addHandshakeKeys(Transaction transaction,
|
||||
ContactId c, HandshakeKeys k) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsContact(txn, c))
|
||||
throw new NoSuchContactException();
|
||||
if (!db.containsTransport(txn, k.getTransportId()))
|
||||
throw new NoSuchTransportException();
|
||||
return db.addHandshakeKeys(txn, c, k);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandshakeKeySetId addHandshakeKeys(Transaction transaction,
|
||||
PendingContactId p, HandshakeKeys k) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsPendingContact(txn, p))
|
||||
throw new NoSuchPendingContactException();
|
||||
if (!db.containsTransport(txn, k.getTransportId()))
|
||||
throw new NoSuchTransportException();
|
||||
return db.addHandshakeKeys(txn, p, k);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLocalAuthor(Transaction transaction, LocalAuthor a)
|
||||
throws DbException {
|
||||
@@ -307,16 +254,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
db.mergeMessageMetadata(txn, m.getId(), meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPendingContact(Transaction transaction, PendingContact p)
|
||||
throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (db.containsPendingContact(txn, p.getId()))
|
||||
throw new PendingContactExistsException();
|
||||
db.addPendingContact(txn, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTransport(Transaction transaction, TransportId t,
|
||||
int maxLatency) throws DbException {
|
||||
@@ -327,8 +264,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportKeySetId addTransportKeys(Transaction transaction,
|
||||
ContactId c, TransportKeys k) throws DbException {
|
||||
public KeySetId addTransportKeys(Transaction transaction, ContactId c,
|
||||
TransportKeys k) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsContact(txn, c))
|
||||
@@ -339,10 +276,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsContact(Transaction transaction, AuthorId a)
|
||||
throws DbException {
|
||||
public boolean containsContact(Transaction transaction, AuthorId remote,
|
||||
AuthorId local) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
return db.containsContact(txn, a);
|
||||
if (!db.containsLocalAuthor(txn, local))
|
||||
throw new NoSuchLocalAuthorException();
|
||||
return db.containsContact(txn, remote, local);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -359,13 +298,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
return db.containsLocalAuthor(txn, local);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPendingContact(Transaction transaction,
|
||||
PendingContactId p) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
return db.containsPendingContact(txn, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteMessage(Transaction transaction, MessageId m)
|
||||
throws DbException {
|
||||
@@ -482,15 +414,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
return db.getContact(txn, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Contact getContact(Transaction transaction, AuthorId a)
|
||||
throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsContact(txn, a))
|
||||
throw new NoSuchContactException();
|
||||
return db.getContact(txn, a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Contact> getContacts(Transaction transaction)
|
||||
throws DbException {
|
||||
@@ -498,6 +421,22 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
return db.getContacts(txn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Contact> getContactsByAuthorId(Transaction transaction,
|
||||
AuthorId remote) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
return db.getContactsByAuthorId(txn, remote);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ContactId> getContacts(Transaction transaction,
|
||||
AuthorId a) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsLocalAuthor(txn, a))
|
||||
throw new NoSuchLocalAuthorException();
|
||||
return db.getContacts(txn, a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Group getGroup(Transaction transaction, GroupId g)
|
||||
throws DbException {
|
||||
@@ -532,15 +471,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
return db.getGroupVisibility(txn, c, g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<HandshakeKeySet> getHandshakeKeys(Transaction transaction,
|
||||
TransportId t) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsTransport(txn, t))
|
||||
throw new NoSuchTransportException();
|
||||
return db.getHandshakeKeys(txn, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalAuthor getLocalAuthor(Transaction transaction, AuthorId a)
|
||||
throws DbException {
|
||||
@@ -634,7 +564,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageState getMessageState(Transaction transaction, MessageId m)
|
||||
public State getMessageState(Transaction transaction, MessageId m)
|
||||
throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsMessage(txn, m))
|
||||
@@ -674,8 +604,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<MessageId, MessageState> getMessageDependencies(
|
||||
Transaction transaction, MessageId m) throws DbException {
|
||||
public Map<MessageId, State> getMessageDependencies(Transaction transaction,
|
||||
MessageId m) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsMessage(txn, m))
|
||||
throw new NoSuchMessageException();
|
||||
@@ -683,8 +613,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<MessageId, MessageState> getMessageDependents(
|
||||
Transaction transaction, MessageId m) throws DbException {
|
||||
public Map<MessageId, State> getMessageDependents(Transaction transaction,
|
||||
MessageId m) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsMessage(txn, m))
|
||||
throw new NoSuchMessageException();
|
||||
@@ -698,13 +628,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
return db.getNextSendTime(txn, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PendingContact> getPendingContacts(
|
||||
Transaction transaction) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
return db.getPendingContacts(txn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings getSettings(Transaction transaction, String namespace)
|
||||
throws DbException {
|
||||
@@ -713,7 +636,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<TransportKeySet> getTransportKeys(Transaction transaction,
|
||||
public Collection<KeySet> getTransportKeys(Transaction transaction,
|
||||
TransportId t) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsTransport(txn, t))
|
||||
@@ -723,17 +646,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
|
||||
@Override
|
||||
public void incrementStreamCounter(Transaction transaction, TransportId t,
|
||||
HandshakeKeySetId k) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsTransport(txn, t))
|
||||
throw new NoSuchTransportException();
|
||||
db.incrementStreamCounter(txn, t, k);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementStreamCounter(Transaction transaction, TransportId t,
|
||||
TransportKeySetId k) throws DbException {
|
||||
KeySetId k) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsTransport(txn, t))
|
||||
@@ -882,16 +795,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
transaction.attach(new GroupVisibilityUpdatedEvent(affected));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeHandshakeKeys(Transaction transaction,
|
||||
TransportId t, HandshakeKeySetId k) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsTransport(txn, t))
|
||||
throw new NoSuchTransportException();
|
||||
db.removeHandshakeKeys(txn, t, k);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLocalAuthor(Transaction transaction, AuthorId a)
|
||||
throws DbException {
|
||||
@@ -914,16 +817,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
db.removeMessage(txn, m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePendingContact(Transaction transaction,
|
||||
PendingContactId p) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsPendingContact(txn, p))
|
||||
throw new NoSuchPendingContactException();
|
||||
db.removePendingContact(txn, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTransport(Transaction transaction, TransportId t)
|
||||
throws DbException {
|
||||
@@ -936,7 +829,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
|
||||
@Override
|
||||
public void removeTransportKeys(Transaction transaction,
|
||||
TransportId t, TransportKeySetId k) throws DbException {
|
||||
TransportId t, KeySetId k) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsTransport(txn, t))
|
||||
@@ -956,13 +849,14 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContactAlias(Transaction transaction, ContactId c,
|
||||
@Nullable String alias) throws DbException {
|
||||
public void setContactActive(Transaction transaction, ContactId c,
|
||||
boolean active) 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);
|
||||
db.setContactActive(txn, c, active);
|
||||
transaction.attach(new ContactStatusChangedEvent(c, active));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -999,7 +893,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
|
||||
@Override
|
||||
public void setMessageState(Transaction transaction, MessageId m,
|
||||
MessageState state) throws DbException {
|
||||
State state) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsMessage(txn, m))
|
||||
@@ -1016,38 +910,27 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsMessage(txn, dependent.getId()))
|
||||
throw new NoSuchMessageException();
|
||||
MessageState dependentState =
|
||||
db.getMessageState(txn, dependent.getId());
|
||||
State dependentState = db.getMessageState(txn, dependent.getId());
|
||||
for (MessageId dependency : dependencies) {
|
||||
db.addMessageDependency(txn, dependent, dependency, dependentState);
|
||||
db.addMessageDependency(txn, dependent, dependency,
|
||||
dependentState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReorderingWindow(Transaction transaction,
|
||||
TransportKeySetId k, TransportId t, long timePeriod, long base,
|
||||
byte[] bitmap) throws DbException {
|
||||
public void setReorderingWindow(Transaction transaction, KeySetId k,
|
||||
TransportId t, long rotationPeriod, long base, byte[] bitmap)
|
||||
throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsTransport(txn, t))
|
||||
throw new NoSuchTransportException();
|
||||
db.setReorderingWindow(txn, k, t, timePeriod, base, bitmap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReorderingWindow(Transaction transaction,
|
||||
HandshakeKeySetId k, TransportId t, long timePeriod, long base,
|
||||
byte[] bitmap) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsTransport(txn, t))
|
||||
throw new NoSuchTransportException();
|
||||
db.setReorderingWindow(txn, k, t, timePeriod, base, bitmap);
|
||||
db.setReorderingWindow(txn, k, t, rotationPeriod, base, bitmap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransportKeysActive(Transaction transaction, TransportId t,
|
||||
TransportKeySetId k) throws DbException {
|
||||
KeySetId k) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsTransport(txn, t))
|
||||
@@ -1055,40 +938,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
db.setTransportKeysActive(txn, t, k);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateHandshakeKeys(Transaction transaction,
|
||||
Collection<HandshakeKeySet> keys) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
for (HandshakeKeySet ks : keys) {
|
||||
TransportId t = ks.getKeys().getTransportId();
|
||||
if (db.containsTransport(txn, t))
|
||||
db.updateHandshakeKeys(txn, ks);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTransportKeys(Transaction transaction,
|
||||
Collection<TransportKeySet> keys) throws DbException {
|
||||
Collection<KeySet> keys) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
for (TransportKeySet ks : keys) {
|
||||
TransportId t = ks.getKeys().getTransportId();
|
||||
for (KeySet ks : keys) {
|
||||
TransportId t = ks.getTransportKeys().getTransportId();
|
||||
if (db.containsTransport(txn, t))
|
||||
db.updateTransportKeys(txn, ks);
|
||||
}
|
||||
}
|
||||
|
||||
private class CommitActionVisitor implements Visitor {
|
||||
|
||||
@Override
|
||||
public void visit(EventAction a) {
|
||||
eventBus.broadcast(a.getEvent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(TaskAction a) {
|
||||
eventExecutor.execute(a.getTask());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,11 @@ package org.briarproject.bramble.db;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.event.EventExecutor;
|
||||
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
|
||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@@ -29,9 +27,8 @@ public class DatabaseModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
DatabaseComponent provideDatabaseComponent(Database<Connection> db,
|
||||
EventBus eventBus, @EventExecutor Executor eventExecutor,
|
||||
ShutdownManager shutdownManager) {
|
||||
EventBus eventBus, ShutdownManager shutdown) {
|
||||
return new DatabaseComponentImpl<>(db, Connection.class, eventBus,
|
||||
eventExecutor, shutdownManager);
|
||||
shutdown);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -15,30 +15,21 @@ import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Contains all the H2-specific code for the database.
|
||||
*/
|
||||
@NotNullByDefault
|
||||
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 SECRET_TYPE = "BINARY(32)";
|
||||
private static final String BINARY_TYPE = "BINARY";
|
||||
private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT";
|
||||
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 String url;
|
||||
@@ -49,7 +40,8 @@ class H2Database extends JdbcDatabase {
|
||||
@Inject
|
||||
H2Database(DatabaseConfig config, MessageFactory messageFactory,
|
||||
Clock clock) {
|
||||
super(dbTypes, messageFactory, clock);
|
||||
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
||||
messageFactory, clock);
|
||||
this.config = config;
|
||||
File dir = config.getDatabaseDirectory();
|
||||
String path = new File(dir, "db").getAbsolutePath();
|
||||
@@ -76,6 +68,30 @@ class H2Database extends JdbcDatabase {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFreeSpace() {
|
||||
File dir = config.getDatabaseDirectory();
|
||||
long maxSize = config.getMaxSize();
|
||||
long free = dir.getFreeSpace();
|
||||
long used = getDiskSpace(dir);
|
||||
long quota = maxSize - used;
|
||||
return Math.min(free, quota);
|
||||
}
|
||||
|
||||
private long getDiskSpace(File f) {
|
||||
if (f.isDirectory()) {
|
||||
long total = 0;
|
||||
File[] children = f.listFiles();
|
||||
if (children != null)
|
||||
for (File child : children) total += getDiskSpace(child);
|
||||
return total;
|
||||
} else if (f.isFile()) {
|
||||
return f.length();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Connection createConnection() throws SQLException {
|
||||
SecretKey key = this.key;
|
||||
@@ -104,8 +120,8 @@ class H2Database extends JdbcDatabase {
|
||||
s.close();
|
||||
c.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(s, LOG, WARNING);
|
||||
tryToClose(c, LOG, WARNING);
|
||||
tryToClose(s);
|
||||
tryToClose(c);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user