mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Compare commits
1 Commits
contact-re
...
priority-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4d0a221a3 |
@@ -11,8 +11,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 26
|
targetSdkVersion 26
|
||||||
versionCode 10106
|
versionCode 10105
|
||||||
versionName "1.1.6"
|
versionName "1.1.5"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
@@ -30,8 +30,8 @@ configurations {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bramble-core', configuration: 'default')
|
implementation project(path: ':bramble-core', configuration: 'default')
|
||||||
tor 'org.briarproject:tor-android:0.3.5.8@zip'
|
tor 'org.briarproject:tor-android:0.3.4.8@zip'
|
||||||
tor 'org.briarproject:obfs4proxy-android:0.0.9@zip'
|
tor 'org.briarproject:obfs4proxy-android:0.0.7@zip'
|
||||||
|
|
||||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
|
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
|
||||||
|
|
||||||
|
|||||||
@@ -12,15 +12,11 @@ import org.briarproject.bramble.api.identity.IdentityManager;
|
|||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
|
|
||||||
class AndroidAccountManager extends AccountManagerImpl
|
class AndroidAccountManager extends AccountManagerImpl
|
||||||
implements AccountManager {
|
implements AccountManager {
|
||||||
|
|
||||||
@@ -93,42 +89,20 @@ class AndroidAccountManager extends AccountManagerImpl
|
|||||||
LOG.warning("Could not clear shared preferences");
|
LOG.warning("Could not clear shared preferences");
|
||||||
}
|
}
|
||||||
// Delete files, except lib and shared_prefs directories
|
// Delete files, except lib and shared_prefs directories
|
||||||
Set<File> files = new HashSet<>();
|
|
||||||
File dataDir = new File(appContext.getApplicationInfo().dataDir);
|
File dataDir = new File(appContext.getApplicationInfo().dataDir);
|
||||||
@Nullable
|
File[] children = dataDir.listFiles();
|
||||||
File[] fileArray = dataDir.listFiles();
|
if (children == null) {
|
||||||
if (fileArray == null) {
|
|
||||||
LOG.warning("Could not list files in app data dir");
|
LOG.warning("Could not list files in app data dir");
|
||||||
} else {
|
} else {
|
||||||
for (File file : fileArray) {
|
for (File child : children) {
|
||||||
String name = file.getName();
|
String name = child.getName();
|
||||||
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
||||||
files.add(file);
|
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
|
// Recreate the cache dir as some OpenGL drivers expect it to exist
|
||||||
if (!new File(dataDir, "cache").mkdirs())
|
if (!new File(dataDir, "cache").mkdir())
|
||||||
LOG.warning("Could not recreate cache dir");
|
LOG.warning("Could not recreate cache dir");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addIfNotNull(Set<File> files, @Nullable File file) {
|
|
||||||
if (file != null) files.add(file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ import static java.util.concurrent.TimeUnit.MINUTES;
|
|||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
class AndroidTorPlugin extends TorPlugin {
|
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 Context appContext;
|
||||||
private final RenewableWakeLock wakeLock;
|
private final RenewableWakeLock wakeLock;
|
||||||
|
|
||||||
@@ -52,7 +55,7 @@ class AndroidTorPlugin extends TorPlugin {
|
|||||||
appContext.getSystemService(POWER_SERVICE);
|
appContext.getSystemService(POWER_SERVICE);
|
||||||
if (pm == null) throw new AssertionError();
|
if (pm == null) throw new AssertionError();
|
||||||
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
|
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
|
||||||
getWakeLockTag(), 1, MINUTES);
|
WAKE_LOCK_TAG, 1, MINUTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -84,17 +87,4 @@ class AndroidTorPlugin extends TorPlugin {
|
|||||||
super.stop();
|
super.stop();
|
||||||
wakeLock.release();
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
package org.briarproject.bramble.system;
|
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.AndroidExecutor;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
import org.briarproject.bramble.api.system.ResourceProvider;
|
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||||
import org.briarproject.bramble.api.system.SecureRandomProvider;
|
import org.briarproject.bramble.api.system.SecureRandomProvider;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
@@ -35,13 +32,6 @@ public class AndroidSystemModule {
|
|||||||
return androidExecutor;
|
return androidExecutor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
@EventExecutor
|
|
||||||
Executor provideEventExecutor(AndroidExecutor androidExecutor) {
|
|
||||||
return androidExecutor::runOnUiThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
ResourceProvider provideResourceProvider(AndroidResourceProvider provider) {
|
ResourceProvider provideResourceProvider(AndroidResourceProvider provider) {
|
||||||
|
|||||||
@@ -112,8 +112,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
|||||||
// Other directories should be deleted
|
// Other directories should be deleted
|
||||||
File potatoDir = new File(testDir, ".potato");
|
File potatoDir = new File(testDir, ".potato");
|
||||||
File potatoFile = new File(potatoDir, "file");
|
File potatoFile = new File(potatoDir, "file");
|
||||||
File filesDir = new File(testDir, "filesDir");
|
|
||||||
File externalCacheDir = new File(testDir, "externalCacheDir");
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(prefs).edit();
|
oneOf(prefs).edit();
|
||||||
@@ -130,12 +128,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(app).getApplicationInfo();
|
oneOf(app).getApplicationInfo();
|
||||||
will(returnValue(applicationInfo));
|
will(returnValue(applicationInfo));
|
||||||
oneOf(app).getFilesDir();
|
|
||||||
will(returnValue(filesDir));
|
|
||||||
oneOf(app).getCacheDir();
|
|
||||||
will(returnValue(cacheDir));
|
|
||||||
oneOf(app).getExternalCacheDir();
|
|
||||||
will(returnValue(externalCacheDir));
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertTrue(dbDir.mkdirs());
|
assertTrue(dbDir.mkdirs());
|
||||||
@@ -148,8 +140,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
|||||||
assertTrue(cacheFile.createNewFile());
|
assertTrue(cacheFile.createNewFile());
|
||||||
assertTrue(potatoDir.mkdirs());
|
assertTrue(potatoDir.mkdirs());
|
||||||
assertTrue(potatoFile.createNewFile());
|
assertTrue(potatoFile.createNewFile());
|
||||||
assertTrue(filesDir.mkdirs());
|
|
||||||
assertTrue(externalCacheDir.mkdirs());
|
|
||||||
|
|
||||||
accountManager.deleteAccount();
|
accountManager.deleteAccount();
|
||||||
|
|
||||||
@@ -163,8 +153,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
|||||||
assertFalse(cacheFile.exists());
|
assertFalse(cacheFile.exists());
|
||||||
assertFalse(potatoDir.exists());
|
assertFalse(potatoDir.exists());
|
||||||
assertFalse(potatoFile.exists());
|
assertFalse(potatoFile.exists());
|
||||||
assertFalse(filesDir.exists());
|
|
||||||
assertFalse(externalCacheDir.exists());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|||||||
@@ -1,44 +1,46 @@
|
|||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
verify = [
|
verify = [
|
||||||
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
||||||
'com.android.tools.analytics-library:protos:26.3.2:protos-26.3.2.jar:50238fb4298b297217b184b9cd93c14f83536fcee829eb0ca850bdb5b53251f0',
|
'com.android.tools.analytics-library:protos:26.2.1:protos-26.2.1.jar:2f371f5b1f551e85ab08be4d6a2873471b3d44afd1ebf6aa3298f3b796bf691f',
|
||||||
'com.android.tools.analytics-library:shared:26.3.2:shared-26.3.2.jar:ddd80dcf21905018b7c0583ba72b7282f446084d4952422609a09fbf8237ef71',
|
'com.android.tools.analytics-library:shared:26.2.1:shared-26.2.1.jar:4c1e4e705fa4d45f23aaea230557f6508155012d9c296337787c1d7b26a97f5a',
|
||||||
'com.android.tools.analytics-library:tracker:26.3.2:tracker-26.3.2.jar:28c575d2d1af003e96d7b375a668ee10b2673a2dd0f6438750aa8c3b42e7d0ad',
|
'com.android.tools.analytics-library:tracker:26.2.1:tracker-26.2.1.jar:4a624ecc976539f755ddb0bb8dfc2dd3d08326cfec59a098dbd70f701ca7fb75',
|
||||||
'com.android.tools.build:apksig:3.3.2:apksig-3.3.2.jar:84c4aaa20127c6c1fe6bdd334b3f5df71f54ad080be9029c8a10f43b6a908acd',
|
'com.android.tools.build:aapt2:3.2.1-4818971:aapt2-3.2.1-4818971-linux.jar:f431b6f96c91a2c155144b091a9c97d9805c589fe8efc9c930b6cd346cb60a1e',
|
||||||
'com.android.tools.build:apkzlib:3.3.2:apkzlib-3.3.2.jar:d34e523278e5dff565eba3ef3c089d515b2b5cc7b47dc77e2f3465e5e47176ac',
|
'com.android.tools.build:apksig:3.2.1:apksig-3.2.1.jar:2b46f2feffea66037aab29e4261b2433c190194a6ef97b958511eb157f2ccba5',
|
||||||
'com.android.tools.build:builder-model:3.3.2:builder-model-3.3.2.jar:055e3db0ecee9e06b9f024034999a29cd92cb1885207b37542126bd8bcc57f46',
|
'com.android.tools.build:apkzlib:3.2.1:apkzlib-3.2.1.jar:c39ad0313905932431fe81c8899c2cf39a4d92ad6c4edcaa4b25432f461452aa',
|
||||||
'com.android.tools.build:builder-test-api:3.3.2:builder-test-api-3.3.2.jar:0b2e4cd7615bbcad14a3c91fe45ae26693508d06e40ba06c5968b8bc24416618',
|
'com.android.tools.build:builder-model:3.2.1:builder-model-3.2.1.jar:a9f68e6abcec122f9cb5ad352d3f05a3eb03acbcdca95e4d25c16310c2c965ff',
|
||||||
'com.android.tools.build:builder:3.3.2:builder-3.3.2.jar:65649704da7aef0487235fd326f0f2e99ed5cf958e80f204496e6e08a42bd9f5',
|
'com.android.tools.build:builder-test-api:3.2.1:builder-test-api-3.2.1.jar:533ac6c2b5884bb54967a33791f2628dfdfac7981af39417a333b43d4379b6be',
|
||||||
'com.android.tools.build:gradle-api:3.3.2:gradle-api-3.3.2.jar:3cbd47e41bb70330dd72ec2c9fe51e6173554b484a03829b5a2de9e00841e040',
|
'com.android.tools.build:builder:3.2.1:builder-3.2.1.jar:aedcbfd115dbe91d09b4113e66ef50589b558d0aa3b2f133b1d867c9b87fae83',
|
||||||
'com.android.tools.build:manifest-merger:26.3.2:manifest-merger-26.3.2.jar:05c4a6d8b02fb9f08744876477d0a68547c03a8a9069b1f086684fa04af97c33',
|
'com.android.tools.build:gradle-api:3.2.1:gradle-api-3.2.1.jar:57cf0ac5ac1dca8afdb3f62b94265e776e7dcfa641cc3844fb53a05193de208d',
|
||||||
'com.android.tools.ddms:ddmlib:26.3.2:ddmlib-26.3.2.jar:d248da8a563d6e46d2c7ebbf371a4877e00510f4ca763c0bb272d5a281bf8b85',
|
'com.android.tools.build:manifest-merger:26.2.1:manifest-merger-26.2.1.jar:8830573263361035d38cfdcb51e2db94029c93865b21334f5fbf8a27984281a6',
|
||||||
'com.android.tools.external.com-intellij:intellij-core:26.3.2:intellij-core-26.3.2.jar:6c5ecc968230e9f4dcd0fef28885379feace1f0cd8130de6f61d649c86139bf3',
|
'com.android.tools.ddms:ddmlib:26.2.1:ddmlib-26.2.1.jar:a4bf0a29a19980bf27269465cc782064656750b77c26728f82f9e148b705218b',
|
||||||
'com.android.tools.external.com-intellij:kotlin-compiler:26.3.2:kotlin-compiler-26.3.2.jar:1007d9b07ccb49cd8eaf30fda10ed4681d4714f2f9ab2ecda39b4e539cc51bbe',
|
'com.android.tools.external.com-intellij:intellij-core:26.2.1:intellij-core-26.2.1.jar:4925ad1892c2687cb1a63427d440ef519c8c59215fefe0dc5d541d5d411fcafe',
|
||||||
'com.android.tools.external.org-jetbrains:uast:26.3.2:uast-26.3.2.jar:5d1833e562ea4f38a89708dfde695f0a162cbd39d003d3dde818c3fdc2b05317',
|
'com.android.tools.external.com-intellij:kotlin-compiler:26.2.1:kotlin-compiler-26.2.1.jar:daa064fd708f340ee25fb9823c4c74104ac77f1370b76d907eb9ae6daec0a2ae',
|
||||||
'com.android.tools.layoutlib:layoutlib-api:26.3.2:layoutlib-api-26.3.2.jar:d7e61e874ab95f5c350dd38b6a95b5c9dbe0083a02001884264cdb390cb255b8',
|
'com.android.tools.external.org-jetbrains:uast:26.2.1:uast-26.2.1.jar:f10f7258d2ab9189562cc0f9ad838c0378fdba439229173390a99de02ebac75b',
|
||||||
'com.android.tools.lint:lint-api:26.3.2:lint-api-26.3.2.jar:5867dfd7fb4a4e161a816a5d29d045f9b542d34594c00a1efec46fb4cd0e1033',
|
'com.android.tools.layoutlib:layoutlib-api:26.2.1:layoutlib-api-26.2.1.jar:ddbf4fca123733fa011595b1cc1f4ac2937ed327b60990711fafc33c775c2ade',
|
||||||
'com.android.tools.lint:lint-checks:26.3.2:lint-checks-26.3.2.jar:4b163b9c93790d2771e92ba8de58a0d9e0671ffcf2ccef3cf496efd442e27517',
|
'com.android.tools.lint:lint-api:26.2.1:lint-api-26.2.1.jar:3b57e739de567b98bc9ab56c2c0ee66fc026b4adf5843e8f9804ca0666a6f66e',
|
||||||
'com.android.tools.lint:lint-gradle-api:26.3.2:lint-gradle-api-26.3.2.jar:54cb282e0c054f9bed3f51302ce08b003c8ab7961dfd5a4f6de26c23cc23062f',
|
'com.android.tools.lint:lint-checks:26.2.1:lint-checks-26.2.1.jar:c86f4cc9aaee722ee4ad70062f7b5af91e9b041914af27adc09f545ab0fb3bc6',
|
||||||
'com.android.tools.lint:lint-gradle:26.3.2:lint-gradle-26.3.2.jar:bb139615f4ce97d42cc394b9389b49b76a6eb85be6785a5d272991543b519013',
|
'com.android.tools.lint:lint-gradle-api:26.2.1:lint-gradle-api-26.2.1.jar:2283e7af32e301565f2a797e531f0fc8c648077d457afb3ffdddbee638976c2f',
|
||||||
'com.android.tools.lint:lint:26.3.2:lint-26.3.2.jar:ef7b369f8a56a92ccb0f4c1c357666b9339e4a711a9d84747d446441746cfe4e',
|
'com.android.tools.lint:lint-gradle:26.2.1:lint-gradle-26.2.1.jar:8fd90b2f3ec788cbb9801c07ab3e1ea2255aa31a6093157d7ea0ff13d0315ecb',
|
||||||
'com.android.tools:annotations:26.3.2:annotations-26.3.2.jar:5bcce8e98b6a2f5ccf13ebcefd8f734e0b35f8b19e456575665631442ce1f7a1',
|
'com.android.tools.lint:lint-kotlin:26.2.1:lint-kotlin-26.2.1.jar:7a6a5d2b18f69cf1b900d857c2632b4c683713c533295933b8b759f8cab4a877',
|
||||||
'com.android.tools:common:26.3.2:common-26.3.2.jar:d9f8e7f0669e9a701568e3db6a87c89cf12d8fa6811c9991e969f950215ecfac',
|
'com.android.tools.lint:lint:26.2.1:lint-26.2.1.jar:7848b82ae988b90dee259ae7c7e86e05cbf52db6cd21c8bbd38ce7df08f3f8c5',
|
||||||
'com.android.tools:dvlib:26.3.2:dvlib-26.3.2.jar:d84aad56161c7773579303d69714ded6897c64c6ddfd7d456e453231e4dfe811',
|
'com.android.tools:annotations:26.2.1:annotations-26.2.1.jar:7391c6a1e080174b96e64ceb078dadd31ce4d8a2d2fee0ec65be202126f90f24',
|
||||||
'com.android.tools:repository:26.3.2:repository-26.3.2.jar:da611eeb06e9ab8750d25b9e2901e10db8e5ec6304eb4c8b7103d39e0921ea40',
|
'com.android.tools:common:26.2.1:common-26.2.1.jar:a50aab2d6411ff68f4004a87c7e93d87d8e980a0ec3b352246549897ea2d78e5',
|
||||||
'com.android.tools:sdk-common:26.3.2:sdk-common-26.3.2.jar:82823a3bf25e64fac33a286490f0cf5ac50c2cdb3c540149b030896bb44bf96c',
|
'com.android.tools:dvlib:26.2.1:dvlib-26.2.1.jar:72a83bf2839b1df9b1fbf67ba45d1bfb9f966cd774da4320c762b2be8f1688aa',
|
||||||
'com.android.tools:sdklib:26.3.2:sdklib-26.3.2.jar:424d15492af67321900963238646d27495ab60de2a5b19e6a416963bc5d6932b',
|
'com.android.tools:repository:26.2.1:repository-26.2.1.jar:fa74dae09103faef703df38550ad8fa244c5b6d1bf90d6198be932292b3d9cc1',
|
||||||
|
'com.android.tools:sdk-common:26.2.1:sdk-common-26.2.1.jar:759d4b292ca69a35cf961fca377b54158fc6c88108978006999442e80a011cf4',
|
||||||
|
'com.android.tools:sdklib:26.2.1:sdklib-26.2.1.jar:248df7ad5eac4aeb6f96c394c76760de4b7b89ac056e54d0c21a739368b91b45',
|
||||||
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
|
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
|
||||||
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
|
||||||
'com.google.code.gson:gson:2.8.0:gson-2.8.0.jar:c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825',
|
'com.google.code.gson:gson:2.8.0:gson-2.8.0.jar:c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825',
|
||||||
'com.google.dagger:dagger-compiler:2.19:dagger-compiler-2.19.jar:27a4b202a2de908182edb261f8c0a264e08e5e4733d7514bc7fbf0d31da5c0fc',
|
'com.google.dagger:dagger-compiler:2.19:dagger-compiler-2.19.jar:27a4b202a2de908182edb261f8c0a264e08e5e4733d7514bc7fbf0d31da5c0fc',
|
||||||
'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768',
|
'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768',
|
||||||
'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1',
|
'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1',
|
||||||
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
|
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
|
||||||
|
'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b',
|
||||||
'com.google.errorprone:error_prone_annotations:2.1.3:error_prone_annotations-2.1.3.jar:03d0329547c13da9e17c634d1049ea2ead093925e290567e1a364fd6b1fc7ff8',
|
'com.google.errorprone:error_prone_annotations:2.1.3:error_prone_annotations-2.1.3.jar:03d0329547c13da9e17c634d1049ea2ead093925e290567e1a364fd6b1fc7ff8',
|
||||||
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
||||||
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
|
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
|
||||||
|
'com.google.guava:guava:23.0:guava-23.0.jar:7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596',
|
||||||
'com.google.guava:guava:25.0-jre:guava-25.0-jre.jar:3fd4341776428c7e0e5c18a7c10de129475b69ab9d30aeafbb5c277bb6074fa9',
|
'com.google.guava:guava:25.0-jre:guava-25.0-jre.jar:3fd4341776428c7e0e5c18a7c10de129475b69ab9d30aeafbb5c277bb6074fa9',
|
||||||
'com.google.guava:guava:26.0-jre:guava-26.0-jre.jar:a0e9cabad665bc20bcd2b01f108e5fc03f756e13aea80abaadb9f407033bea2c',
|
|
||||||
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
|
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
|
||||||
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
|
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
|
||||||
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
|
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
|
||||||
@@ -66,22 +68,21 @@ dependencyVerification {
|
|||||||
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||||
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
|
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
|
||||||
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
|
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
|
||||||
'org.briarproject:obfs4proxy-android:0.0.9:obfs4proxy-android-0.0.9.zip:9b7e9181535ea8d8bbe8ae6338e08cf4c5fc1e357a779393e0ce49586d459ae0',
|
'org.briarproject:obfs4proxy-android:0.0.7:obfs4proxy-android-0.0.7.zip:abdfb5d889d848de9bf214f9276abbf454808a505b870819eccc9a9e985bf617',
|
||||||
'org.briarproject:tor-android:0.3.5.8:tor-android-0.3.5.8.zip:42a13a6f185be1a62f42e3f30ce66a3c099ac5ec890a65e7593111b65b44a54a',
|
'org.briarproject:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926',
|
||||||
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
|
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
|
||||||
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
|
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
|
||||||
'org.codehaus.groovy:groovy-all:2.4.15:groovy-all-2.4.15.jar:51d6c4e71782e85674239189499854359d380fb75e1a703756e3aaa5b98a5af0',
|
|
||||||
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
|
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
|
||||||
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
|
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
|
||||||
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
|
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
|
||||||
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
|
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
|
||||||
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
||||||
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
||||||
'org.jetbrains.kotlin:kotlin-reflect:1.3.21:kotlin-reflect-1.3.21.jar:a3065c822633191e0a3e3ee12a29bec234fc4b2864a6bb87ef48cce3e9e0c26a',
|
'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.21:kotlin-stdlib-common-1.3.21.jar:cea61f7b611895e64f58569a9757fc0ab0d582f107211e1930e0ce2a0add52a7',
|
'org.jetbrains.kotlin:kotlin-stdlib-common:1.2.71:kotlin-stdlib-common-1.2.71.jar:63999687ff2fce8a592dd180ffbbf8f1d21c26b4044c55cdc74ff3cf3b3cf328',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21:kotlin-stdlib-jdk7-1.3.21.jar:a87875604fd42140da6938ae4d35ee61081f4482536efc6d2615b8b626a198af',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.71:kotlin-stdlib-jdk7-1.2.71.jar:b136bd61b240e07d4d92ce00d3bd1dbf584400a7bf5f220c2f3cd22446858082',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.21:kotlin-stdlib-jdk8-1.3.21.jar:5823ed66ac122a1c55442ebca5a209a843ccd87f562edc31a787f3d2e47f74d4',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.71:kotlin-stdlib-jdk8-1.2.71.jar:ac3c8abf47790b64b4f7e2509a53f0c145e061ac1612a597520535d199946ea9',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib:1.3.21:kotlin-stdlib-1.3.21.jar:38ba2370d9f06f50433e06b2ca775b94473c2e2785f410926079ab793c72b034',
|
'org.jetbrains.kotlin:kotlin-stdlib:1.2.71:kotlin-stdlib-1.2.71.jar:4c895c270b87f5fec2a2796e1d89c15407ee821de961527c28588bb46afbc68b',
|
||||||
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
|
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
|
||||||
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
|
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
|
||||||
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
||||||
|
|||||||
@@ -18,10 +18,11 @@ public interface ContactGroupFactory {
|
|||||||
* Creates a group for the given client to share with the given contact.
|
* Creates a group for the given client to share with the given contact.
|
||||||
*/
|
*/
|
||||||
Group createContactGroup(ClientId clientId, int majorVersion,
|
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,
|
Group createContactGroup(ClientId clientId, int majorVersion,
|
||||||
AuthorId authorId1, AuthorId authorId2);
|
AuthorId authorId1, AuthorId authorId2);
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package org.briarproject.bramble.api.contact;
|
package org.briarproject.bramble.api.contact;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
import static org.briarproject.bramble.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;
|
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -16,28 +16,24 @@ public class Contact {
|
|||||||
|
|
||||||
private final ContactId id;
|
private final ContactId id;
|
||||||
private final Author author;
|
private final Author author;
|
||||||
|
private final AuthorId localAuthorId;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final String alias;
|
private final String alias;
|
||||||
@Nullable
|
private final boolean verified, active;
|
||||||
private final byte[] handshakePublicKey;
|
|
||||||
private final boolean verified;
|
|
||||||
|
|
||||||
public Contact(ContactId id, Author author, @Nullable String alias,
|
public Contact(ContactId id, Author author, AuthorId localAuthorId,
|
||||||
@Nullable byte[] handshakePublicKey, boolean verified) {
|
@Nullable String alias, boolean verified, boolean active) {
|
||||||
if (alias != null) {
|
if (alias != null) {
|
||||||
int aliasLength = toUtf8(alias).length;
|
int aliasLength = toUtf8(alias).length;
|
||||||
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
|
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
if (handshakePublicKey != null && (handshakePublicKey.length == 0 ||
|
|
||||||
handshakePublicKey.length > MAX_PUBLIC_KEY_LENGTH)) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.author = author;
|
this.author = author;
|
||||||
|
this.localAuthorId = localAuthorId;
|
||||||
this.alias = alias;
|
this.alias = alias;
|
||||||
this.handshakePublicKey = handshakePublicKey;
|
|
||||||
this.verified = verified;
|
this.verified = verified;
|
||||||
|
this.active = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContactId getId() {
|
public ContactId getId() {
|
||||||
@@ -48,20 +44,23 @@ public class Contact {
|
|||||||
return author;
|
return author;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AuthorId getLocalAuthorId() {
|
||||||
|
return localAuthorId;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getAlias() {
|
public String getAlias() {
|
||||||
return alias;
|
return alias;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public byte[] getHandshakePublicKey() {
|
|
||||||
return handshakePublicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVerified() {
|
public boolean isVerified() {
|
||||||
return verified;
|
return verified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return id.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;
|
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 =
|
String ALICE_KEY_LABEL =
|
||||||
"org.briarproject.bramble.contact/ALICE_HEADER_KEY";
|
"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";
|
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";
|
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";
|
String BOB_NONCE_LABEL = "org.briarproject.bramble.contact/BOB_NONCE";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exchanges contact information with a remote peer.
|
* 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,
|
DuplexTransportConnection conn, TransportId transportId,
|
||||||
boolean alice);
|
boolean alice);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import java.util.Collection;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.contact.PendingContact.PendingContactState.FAILED;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface ContactManager {
|
public interface ContactManager {
|
||||||
|
|
||||||
@@ -24,31 +26,34 @@ public interface ContactManager {
|
|||||||
void registerContactHook(ContactHook hook);
|
void registerContactHook(ContactHook hook);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a contact with the given pseudonym, derives and stores transport
|
* Stores a contact associated with the given local and remote pseudonyms,
|
||||||
* keys for each transport, and returns an ID for the contact.
|
* derives and stores transport keys for each transport, and returns an ID
|
||||||
|
* for the contact.
|
||||||
*
|
*
|
||||||
* @param alice true if the local party is Alice
|
* @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)
|
long timestamp, boolean alice, boolean verified, boolean active)
|
||||||
throws DbException;
|
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.
|
* Returns the static link that needs to be sent to the contact to be added.
|
||||||
*/
|
*/
|
||||||
@@ -74,8 +79,7 @@ public interface ContactManager {
|
|||||||
Collection<PendingContact> getPendingContacts();
|
Collection<PendingContact> getPendingContacts();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a {@link PendingContact} that is in state
|
* Removes a {@link PendingContact} that is in state {@link FAILED}.
|
||||||
* {@link PendingContactState FAILED}.
|
|
||||||
*/
|
*/
|
||||||
void removePendingContact(PendingContact pendingContact);
|
void removePendingContact(PendingContact pendingContact);
|
||||||
|
|
||||||
@@ -85,19 +89,27 @@ public interface ContactManager {
|
|||||||
Contact getContact(ContactId c) throws DbException;
|
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.
|
* Returns all active contacts.
|
||||||
*/
|
*/
|
||||||
Collection<Contact> getContacts() throws DbException;
|
Collection<Contact> getActiveContacts() throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a contact and all associated state.
|
* Removes a contact and all associated state.
|
||||||
@@ -109,6 +121,12 @@ public interface ContactManager {
|
|||||||
*/
|
*/
|
||||||
void removeContact(Transaction txn, ContactId c) throws DbException;
|
void removeContact(Transaction txn, ContactId c) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a contact as active or inactive.
|
||||||
|
*/
|
||||||
|
void setContactActive(Transaction txn, ContactId c, boolean active)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an alias name for the contact or unsets it if alias is null.
|
* Sets an alias name for the contact or unsets it if alias is null.
|
||||||
*/
|
*/
|
||||||
@@ -122,14 +140,16 @@ public interface ContactManager {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if a contact with this pseudonym already exists.
|
* Return true if a contact with this name and public key already exists
|
||||||
*/
|
*/
|
||||||
boolean contactExists(Transaction txn, AuthorId a) throws DbException;
|
boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
|
||||||
|
AuthorId localAuthorId) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if a contact with this pseudonym already exists.
|
* Return true if a contact with this name and public key already exists
|
||||||
*/
|
*/
|
||||||
boolean contactExists(AuthorId a) throws DbException;
|
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link AuthorInfo} for the given author.
|
* Returns the {@link AuthorInfo} for the given author.
|
||||||
|
|||||||
@@ -8,29 +8,26 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class PendingContact {
|
public class PendingContact {
|
||||||
|
|
||||||
|
public enum PendingContactState {
|
||||||
|
WAITING_FOR_CONNECTION,
|
||||||
|
CONNECTED,
|
||||||
|
ADDING_CONTACT,
|
||||||
|
FAILED
|
||||||
|
}
|
||||||
|
|
||||||
private final PendingContactId id;
|
private final PendingContactId id;
|
||||||
private final byte[] publicKey;
|
|
||||||
private final String alias;
|
private final String alias;
|
||||||
private final PendingContactState state;
|
private final PendingContactState state;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
|
|
||||||
public PendingContact(PendingContactId id, byte[] publicKey,
|
public PendingContact(PendingContactId id, String alias,
|
||||||
String alias, PendingContactState state, long timestamp) {
|
PendingContactState state, long timestamp) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.publicKey = publicKey;
|
|
||||||
this.alias = alias;
|
this.alias = alias;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PendingContactId getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getPublicKey() {
|
|
||||||
return publicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAlias() {
|
public String getAlias() {
|
||||||
return alias;
|
return alias;
|
||||||
}
|
}
|
||||||
@@ -53,4 +50,5 @@ public class PendingContact {
|
|||||||
return o instanceof PendingContact &&
|
return o instanceof PendingContact &&
|
||||||
id.equals(((PendingContact) o).id);
|
id.equals(((PendingContact) o).id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,11 @@
|
|||||||
package org.briarproject.bramble.api.contact;
|
package org.briarproject.bramble.api.contact;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.UniqueId;
|
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 class PendingContactId extends UniqueId {
|
||||||
|
|
||||||
public PendingContactId(byte[] id) {
|
public PendingContactId(byte[] id) {
|
||||||
super(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 {
|
public class ContactAddedEvent extends Event {
|
||||||
|
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
|
private final boolean active;
|
||||||
|
|
||||||
public ContactAddedEvent(ContactId contactId) {
|
public ContactAddedEvent(ContactId contactId, boolean active) {
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
|
this.active = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContactId getContactId() {
|
public ContactId getContactId() {
|
||||||
return contactId;
|
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,7 +1,7 @@
|
|||||||
package org.briarproject.bramble.api.contact.event;
|
package org.briarproject.bramble.api.contact.event;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.PendingContact.PendingContactState;
|
||||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||||
import org.briarproject.bramble.api.contact.PendingContactState;
|
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package org.briarproject.bramble.api.crypto;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Crypto operations for the key agreement protocol - see
|
* 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 {
|
public interface KeyAgreementCrypto {
|
||||||
|
|
||||||
|
|||||||
@@ -1,45 +1,29 @@
|
|||||||
package org.briarproject.bramble.api.crypto;
|
package org.briarproject.bramble.api.crypto;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.bramble.api.transport.HandshakeKeys;
|
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crypto operations for the transport security protocol - see
|
* 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 {
|
public interface TransportCrypto {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives initial transport keys for the given transport in the given
|
* 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 alice whether the keys are for use by Alice or Bob.
|
||||||
* @param active whether the keys are usable for outgoing streams.
|
* @param active whether the keys are usable for outgoing streams.
|
||||||
*/
|
*/
|
||||||
TransportKeys deriveTransportKeys(TransportId t, SecretKey rootKey,
|
TransportKeys deriveTransportKeys(TransportId t, SecretKey master,
|
||||||
long timePeriod, boolean alice, boolean active);
|
long rotationPeriod, boolean alice, boolean active);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rotates the given transport keys to the given time period. If the keys
|
* Rotates the given transport keys to the given rotation period. If the
|
||||||
* are for the given period or any later period they are not rotated.
|
* keys are for the given period or any later period they are not rotated.
|
||||||
*/
|
*/
|
||||||
TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod);
|
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes the pseudo-random tag that is used to recognise a stream.
|
* Encodes the pseudo-random tag that is used to recognise a stream.
|
||||||
|
|||||||
@@ -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.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
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.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.AuthorId;
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
@@ -22,11 +20,8 @@ import org.briarproject.bramble.api.sync.MessageStatus;
|
|||||||
import org.briarproject.bramble.api.sync.Offer;
|
import org.briarproject.bramble.api.sync.Offer;
|
||||||
import org.briarproject.bramble.api.sync.Request;
|
import org.briarproject.bramble.api.sync.Request;
|
||||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||||
import org.briarproject.bramble.api.transport.HandshakeKeySet;
|
import org.briarproject.bramble.api.transport.KeySet;
|
||||||
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
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.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -102,31 +97,17 @@ public interface DatabaseComponent {
|
|||||||
NullableDbCallable<R, E> task) throws DbException, E;
|
NullableDbCallable<R, E> task) throws DbException, E;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a contact with the given pseudonym and returns an ID for the
|
* Stores a contact associated with the given local and remote pseudonyms,
|
||||||
* contact.
|
* and returns an ID for the contact.
|
||||||
*/
|
*/
|
||||||
ContactId addContact(Transaction txn, Author a, boolean verified)
|
ContactId addContact(Transaction txn, Author remote, AuthorId local,
|
||||||
throws DbException;
|
boolean verified, boolean active) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a group.
|
* Stores a group.
|
||||||
*/
|
*/
|
||||||
void addGroup(Transaction txn, Group g) throws DbException;
|
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.
|
* Stores a local pseudonym.
|
||||||
*/
|
*/
|
||||||
@@ -138,12 +119,6 @@ public interface DatabaseComponent {
|
|||||||
void addLocalMessage(Transaction txn, Message m, Metadata meta,
|
void addLocalMessage(Transaction txn, Message m, Metadata meta,
|
||||||
boolean shared) throws DbException;
|
boolean shared) throws DbException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores a pending contact.
|
|
||||||
*/
|
|
||||||
void addPendingContact(Transaction txn, PendingContact p)
|
|
||||||
throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a transport.
|
* Stores a transport.
|
||||||
*/
|
*/
|
||||||
@@ -154,39 +129,27 @@ public interface DatabaseComponent {
|
|||||||
* Stores the given transport keys for the given contact and returns a
|
* Stores the given transport keys for the given contact and returns a
|
||||||
* key set ID.
|
* key set ID.
|
||||||
*/
|
*/
|
||||||
TransportKeySetId addTransportKeys(Transaction txn, ContactId c,
|
KeySetId addTransportKeys(Transaction txn, ContactId c,
|
||||||
TransportKeys k) throws DbException;
|
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
|
||||||
* <p/>
|
* local pseudonym.
|
||||||
* Read-only.
|
|
||||||
*/
|
*/
|
||||||
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.
|
* Returns true if the database contains the given group.
|
||||||
* <p/>
|
|
||||||
* Read-only.
|
|
||||||
*/
|
*/
|
||||||
boolean containsGroup(Transaction txn, GroupId g) throws DbException;
|
boolean containsGroup(Transaction txn, GroupId g) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the database contains the given local author.
|
* Returns true if the database contains the given local author.
|
||||||
* <p/>
|
|
||||||
* Read-only.
|
|
||||||
*/
|
*/
|
||||||
boolean containsLocalAuthor(Transaction txn, AuthorId local)
|
boolean containsLocalAuthor(Transaction txn, AuthorId local)
|
||||||
throws DbException;
|
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
|
* Deletes the message with the given ID. Unlike
|
||||||
* {@link #removeMessage(Transaction, MessageId)}, the message ID,
|
* {@link #removeMessage(Transaction, MessageId)}, the message ID,
|
||||||
@@ -252,13 +215,6 @@ public interface DatabaseComponent {
|
|||||||
*/
|
*/
|
||||||
Contact getContact(Transaction txn, ContactId c) throws DbException;
|
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.
|
* Returns all contacts.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -266,6 +222,22 @@ public interface DatabaseComponent {
|
|||||||
*/
|
*/
|
||||||
Collection<Contact> getContacts(Transaction txn) throws DbException;
|
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.
|
* Returns the group with the given ID.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -297,14 +269,6 @@ public interface DatabaseComponent {
|
|||||||
Visibility getGroupVisibility(Transaction txn, ContactId c, GroupId g)
|
Visibility getGroupVisibility(Transaction txn, ContactId c, GroupId g)
|
||||||
throws DbException;
|
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.
|
* Returns the local pseudonym with the given ID.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -453,14 +417,6 @@ public interface DatabaseComponent {
|
|||||||
*/
|
*/
|
||||||
long getNextSendTime(Transaction txn, ContactId c) throws DbException;
|
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.
|
* Returns all settings in the given namespace.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -473,20 +429,14 @@ public interface DatabaseComponent {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<TransportKeySet> getTransportKeys(Transaction txn, TransportId t)
|
Collection<KeySet> getTransportKeys(Transaction txn, TransportId t)
|
||||||
throws DbException;
|
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.
|
* Increments the outgoing stream counter for the given transport keys.
|
||||||
*/
|
*/
|
||||||
void incrementStreamCounter(Transaction txn, TransportId t,
|
void incrementStreamCounter(Transaction txn, TransportId t, KeySetId k)
|
||||||
TransportKeySetId k) throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges the given metadata with the existing metadata for the given
|
* Merges the given metadata with the existing metadata for the given
|
||||||
@@ -541,12 +491,6 @@ public interface DatabaseComponent {
|
|||||||
*/
|
*/
|
||||||
void removeGroup(Transaction txn, Group g) throws DbException;
|
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.
|
* Removes a local pseudonym (and all associated state) from the database.
|
||||||
*/
|
*/
|
||||||
@@ -557,12 +501,6 @@ public interface DatabaseComponent {
|
|||||||
*/
|
*/
|
||||||
void removeMessage(Transaction txn, MessageId m) throws DbException;
|
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.
|
* Removes a transport (and all associated state) from the database.
|
||||||
*/
|
*/
|
||||||
@@ -571,14 +509,20 @@ public interface DatabaseComponent {
|
|||||||
/**
|
/**
|
||||||
* Removes the given transport keys from the database.
|
* Removes the given transport keys from the database.
|
||||||
*/
|
*/
|
||||||
void removeTransportKeys(Transaction txn, TransportId t,
|
void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
|
||||||
TransportKeySetId k) throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the given contact as verified.
|
* Marks the given contact as verified.
|
||||||
*/
|
*/
|
||||||
void setContactVerified(Transaction txn, ContactId c) throws DbException;
|
void setContactVerified(Transaction txn, ContactId c) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the given contact as active or inactive.
|
||||||
|
*/
|
||||||
|
void setContactActive(Transaction txn, ContactId c, boolean active)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an alias name for the contact or unsets it if alias is null.
|
* Sets an alias name for the contact or unsets it if alias is null.
|
||||||
*/
|
*/
|
||||||
@@ -609,36 +553,21 @@ public interface DatabaseComponent {
|
|||||||
Collection<MessageId> dependencies) throws DbException;
|
Collection<MessageId> dependencies) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the reordering window for the given transport key set in the given
|
* Sets the reordering window for the given key set and transport in the
|
||||||
* time period.
|
* given rotation period.
|
||||||
*/
|
*/
|
||||||
void setReorderingWindow(Transaction txn, TransportKeySetId k,
|
void setReorderingWindow(Transaction txn, KeySetId k, TransportId t,
|
||||||
TransportId t, long timePeriod, long base, byte[] bitmap)
|
long rotationPeriod, long base, byte[] bitmap) throws DbException;
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the given transport keys as usable for outgoing streams.
|
* Marks the given transport keys as usable for outgoing streams.
|
||||||
*/
|
*/
|
||||||
void setTransportKeysActive(Transaction txn, TransportId t,
|
void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k)
|
||||||
TransportKeySetId k) throws DbException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores the given handshake keys, deleting any keys they have replaced.
|
|
||||||
*/
|
|
||||||
void updateHandshakeKeys(Transaction txn, Collection<HandshakeKeySet> keys)
|
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the given transport keys, deleting any keys they have replaced.
|
* 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;
|
throws DbException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,4 +10,6 @@ public interface DatabaseConfig {
|
|||||||
File getDatabaseDirectory();
|
File getDatabaseDirectory();
|
||||||
|
|
||||||
File getDatabaseKeyDirectory();
|
File getDatabaseKeyDirectory();
|
||||||
|
|
||||||
|
long getMaxSize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,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;
|
package org.briarproject.bramble.api.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventExecutor;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper around a database transaction. Transactions are not thread-safe.
|
* A wrapper around a database transaction. Transactions are not thread-safe.
|
||||||
*/
|
*/
|
||||||
@@ -19,7 +17,7 @@ public class Transaction {
|
|||||||
private final Object txn;
|
private final Object txn;
|
||||||
private final boolean readOnly;
|
private final boolean readOnly;
|
||||||
|
|
||||||
private List<CommitAction> actions = null;
|
private List<Event> events = null;
|
||||||
private boolean committed = false;
|
private boolean committed = false;
|
||||||
|
|
||||||
public Transaction(Object txn, boolean readOnly) {
|
public Transaction(Object txn, boolean readOnly) {
|
||||||
@@ -44,27 +42,19 @@ public class Transaction {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches an event to be broadcast when the transaction has been
|
* 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) {
|
public void attach(Event e) {
|
||||||
if (actions == null) actions = new ArrayList<>();
|
if (events == null) events = new ArrayList<>();
|
||||||
actions.add(new EventAction(e));
|
events.add(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches a task to be executed when the transaction has been
|
* Returns any events attached to the transaction.
|
||||||
* committed. The task will be run on the {@link EventExecutor}.
|
|
||||||
*/
|
*/
|
||||||
public void attach(Runnable r) {
|
public List<Event> getEvents() {
|
||||||
if (actions == null) actions = new ArrayList<>();
|
if (events == null) return Collections.emptyList();
|
||||||
actions.add(new TaskAction(r));
|
return events;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns any actions attached to the transaction.
|
|
||||||
*/
|
|
||||||
public List<CommitAction> getActions() {
|
|
||||||
return actions == null ? emptyList() : actions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ public interface EventBus {
|
|||||||
void removeListener(EventListener l);
|
void removeListener(EventListener l);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously notifies all listeners of an event. Listeners are
|
* Notifies all listeners of an event.
|
||||||
* notified on the {@link EventExecutor}.
|
|
||||||
*/
|
*/
|
||||||
void broadcast(Event e);
|
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
|
* Called when an event is broadcast. Implementations of this method must
|
||||||
* not block.
|
* not block.
|
||||||
*/
|
*/
|
||||||
@EventExecutor
|
|
||||||
void eventOccurred(Event e);
|
void eventOccurred(Event e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,8 @@ package org.briarproject.bramble.api.identity;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pseudonym for the local user.
|
* 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 {
|
public class LocalAuthor extends Author {
|
||||||
|
|
||||||
private final byte[] privateKey;
|
private final byte[] privateKey;
|
||||||
@Nullable
|
|
||||||
private final byte[] handshakePublicKey, handshakePrivateKey;
|
|
||||||
private final long created;
|
private final long created;
|
||||||
|
|
||||||
public LocalAuthor(AuthorId id, int formatVersion, String name,
|
public LocalAuthor(AuthorId id, int formatVersion, String name,
|
||||||
@@ -24,22 +19,6 @@ public class LocalAuthor extends Author {
|
|||||||
super(id, formatVersion, name, publicKey);
|
super(id, formatVersion, name, publicKey);
|
||||||
this.privateKey = privateKey;
|
this.privateKey = privateKey;
|
||||||
this.created = created;
|
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;
|
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
|
* Returns the time the pseudonym was created, in milliseconds since the
|
||||||
* Unix epoch.
|
* Unix epoch.
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ public interface KeyAgreementConstants {
|
|||||||
"org.briarproject.bramble.keyagreement/SHARED_SECRET";
|
"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";
|
"org.briarproject.bramble.keyagreement/MASTER_SECRET";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
package org.briarproject.bramble.api.transport;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
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;
|
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains transport keys for receiving streams from a given contact over a
|
* 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 {
|
public class IncomingKeys {
|
||||||
|
|
||||||
private final SecretKey tagKey, headerKey;
|
private final SecretKey tagKey, headerKey;
|
||||||
private final long timePeriod, windowBase;
|
private final long rotationPeriod, windowBase;
|
||||||
private final byte[] windowBitmap;
|
private final byte[] windowBitmap;
|
||||||
|
|
||||||
public IncomingKeys(SecretKey tagKey, SecretKey headerKey,
|
public IncomingKeys(SecretKey tagKey, SecretKey headerKey,
|
||||||
long timePeriod) {
|
long rotationPeriod) {
|
||||||
this(tagKey, headerKey, timePeriod, 0,
|
this(tagKey, headerKey, rotationPeriod, 0,
|
||||||
new byte[REORDERING_WINDOW_SIZE / 8]);
|
new byte[REORDERING_WINDOW_SIZE / 8]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncomingKeys(SecretKey tagKey, SecretKey headerKey,
|
public IncomingKeys(SecretKey tagKey, SecretKey headerKey,
|
||||||
long timePeriod, long windowBase, byte[] windowBitmap) {
|
long rotationPeriod, long windowBase, byte[] windowBitmap) {
|
||||||
this.tagKey = tagKey;
|
this.tagKey = tagKey;
|
||||||
this.headerKey = headerKey;
|
this.headerKey = headerKey;
|
||||||
this.timePeriod = timePeriod;
|
this.rotationPeriod = rotationPeriod;
|
||||||
this.windowBase = windowBase;
|
this.windowBase = windowBase;
|
||||||
this.windowBitmap = windowBitmap;
|
this.windowBitmap = windowBitmap;
|
||||||
}
|
}
|
||||||
@@ -42,8 +37,8 @@ public class IncomingKeys {
|
|||||||
return headerKey;
|
return headerKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getTimePeriod() {
|
public long getRotationPeriod() {
|
||||||
return timePeriod;
|
return rotationPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getWindowBase() {
|
public long getWindowBase() {
|
||||||
|
|||||||
@@ -27,14 +27,14 @@ public interface KeyManager {
|
|||||||
* @param alice true if the local party is Alice
|
* @param alice true if the local party is Alice
|
||||||
* @param active whether the derived keys can be used for outgoing streams
|
* @param active whether the derived keys can be used for outgoing streams
|
||||||
*/
|
*/
|
||||||
Map<TransportId, TransportKeySetId> addContact(Transaction txn, ContactId c,
|
Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
|
||||||
SecretKey rootKey, long timestamp, boolean alice, boolean active)
|
SecretKey master, long timestamp, boolean alice, boolean active)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the given transport keys as usable for outgoing streams.
|
* 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;
|
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;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type-safe wrapper for an integer that uniquely identifies a
|
* Type-safe wrapper for an integer that uniquely identifies a set of transport
|
||||||
* {@link TransportKeySet set of transport keys} within the scope of the local
|
* keys within the scope of the local device.
|
||||||
* device.
|
|
||||||
* <p/>
|
* <p/>
|
||||||
* Key sets created on a given device must have increasing identifiers.
|
* Key sets created on a given device must have increasing identifiers.
|
||||||
*/
|
*/
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class TransportKeySetId {
|
public class KeySetId {
|
||||||
|
|
||||||
private final int id;
|
private final int id;
|
||||||
|
|
||||||
public TransportKeySetId(int id) {
|
public KeySetId(int id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +31,6 @@ public class TransportKeySetId {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
return o instanceof TransportKeySetId &&
|
return o instanceof KeySetId && id == ((KeySetId) o).id;
|
||||||
id == ((TransportKeySetId) o).id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,32 +1,27 @@
|
|||||||
package org.briarproject.bramble.api.transport;
|
package org.briarproject.bramble.api.transport;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
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
|
* 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 {
|
public class OutgoingKeys {
|
||||||
|
|
||||||
private final SecretKey tagKey, headerKey;
|
private final SecretKey tagKey, headerKey;
|
||||||
private final long timePeriod, streamCounter;
|
private final long rotationPeriod, streamCounter;
|
||||||
private final boolean active;
|
private final boolean active;
|
||||||
|
|
||||||
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
|
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
|
||||||
long timePeriod, boolean active) {
|
long rotationPeriod, boolean active) {
|
||||||
this(tagKey, headerKey, timePeriod, 0, active);
|
this(tagKey, headerKey, rotationPeriod, 0, active);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
|
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
|
||||||
long timePeriod, long streamCounter, boolean active) {
|
long rotationPeriod, long streamCounter, boolean active) {
|
||||||
this.tagKey = tagKey;
|
this.tagKey = tagKey;
|
||||||
this.headerKey = headerKey;
|
this.headerKey = headerKey;
|
||||||
this.timePeriod = timePeriod;
|
this.rotationPeriod = rotationPeriod;
|
||||||
this.streamCounter = streamCounter;
|
this.streamCounter = streamCounter;
|
||||||
this.active = active;
|
this.active = active;
|
||||||
}
|
}
|
||||||
@@ -39,8 +34,8 @@ public class OutgoingKeys {
|
|||||||
return headerKey;
|
return headerKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getTimePeriod() {
|
public long getRotationPeriod() {
|
||||||
return timePeriod;
|
return rotationPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getStreamCounter() {
|
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.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
@NotNullByDefault
|
|
||||||
public class StreamContext {
|
public class StreamContext {
|
||||||
|
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
|
|||||||
@@ -82,58 +82,30 @@ public interface TransportConstants {
|
|||||||
int REORDERING_WINDOW_SIZE = 32;
|
int REORDERING_WINDOW_SIZE = 32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Label for deriving Alice's initial tag key from the root key in
|
* Label for deriving Alice's initial tag key from the master secret.
|
||||||
* rotation mode.
|
|
||||||
*/
|
*/
|
||||||
String ALICE_TAG_LABEL = "org.briarproject.bramble.transport/ALICE_TAG_KEY";
|
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
|
* Label for deriving Bob's initial tag key from the master secret.
|
||||||
* mode.
|
|
||||||
*/
|
*/
|
||||||
String BOB_TAG_LABEL = "org.briarproject.bramble.transport/BOB_TAG_KEY";
|
String BOB_TAG_LABEL = "org.briarproject.bramble.transport/BOB_TAG_KEY";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Label for deriving Alice's initial header key from the root key in
|
* Label for deriving Alice's initial header key from the master secret.
|
||||||
* rotation mode.
|
|
||||||
*/
|
*/
|
||||||
String ALICE_HEADER_LABEL =
|
String ALICE_HEADER_LABEL =
|
||||||
"org.briarproject.bramble.transport/ALICE_HEADER_KEY";
|
"org.briarproject.bramble.transport/ALICE_HEADER_KEY";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Label for deriving Bob's initial header key from the root key in
|
* Label for deriving Bob's initial header key from the master secret.
|
||||||
* rotation mode.
|
|
||||||
*/
|
*/
|
||||||
String BOB_HEADER_LABEL =
|
String BOB_HEADER_LABEL =
|
||||||
"org.briarproject.bramble.transport/BOB_HEADER_KEY";
|
"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";
|
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;
|
package org.briarproject.bramble.api.transport;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keys for communicating with a given contact over a given transport. Unlike
|
* Keys for communicating with a given contact over a given transport.
|
||||||
* {@link HandshakeKeys} these keys provide forward secrecy.
|
|
||||||
*/
|
*/
|
||||||
@Immutable
|
public class TransportKeys {
|
||||||
@NotNullByDefault
|
|
||||||
public class TransportKeys extends AbstractTransportKeys {
|
private final TransportId transportId;
|
||||||
|
private final IncomingKeys inPrev, inCurr, inNext;
|
||||||
|
private final OutgoingKeys outCurr;
|
||||||
|
|
||||||
public TransportKeys(TransportId transportId, IncomingKeys inPrev,
|
public TransportKeys(TransportId transportId, IncomingKeys inPrev,
|
||||||
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) {
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
package org.briarproject.bramble.test;
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.UniqueId;
|
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.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.AuthorId;
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
@@ -29,7 +25,6 @@ import java.util.Random;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
import static 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.Author.FORMAT_VERSION;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
@@ -46,7 +41,6 @@ public class TestUtils {
|
|||||||
new AtomicInteger((int) (Math.random() * 1000 * 1000));
|
new AtomicInteger((int) (Math.random() * 1000 * 1000));
|
||||||
private static final Random random = new Random();
|
private static final Random random = new Random();
|
||||||
private static final long timestamp = System.currentTimeMillis();
|
private static final long timestamp = System.currentTimeMillis();
|
||||||
private static final AtomicInteger nextContactId = new AtomicInteger(1);
|
|
||||||
|
|
||||||
public static File getTestDirectory() {
|
public static File getTestDirectory() {
|
||||||
int name = nextTestDir.getAndIncrement();
|
int name = nextTestDir.getAndIncrement();
|
||||||
@@ -146,35 +140,6 @@ public class TestUtils {
|
|||||||
return new Message(id, groupId, timestamp, body);
|
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) {
|
public static double getMedian(Collection<? extends Number> samples) {
|
||||||
int size = samples.size();
|
int size = samples.size();
|
||||||
if (size == 0) throw new IllegalArgumentException();
|
if (size == 0) throw new IllegalArgumentException();
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package org.briarproject.bramble;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public class PriorityExecutor {
|
||||||
|
|
||||||
|
private final Object lock = new Object();
|
||||||
|
private final Executor delegate, high, low;
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private final Queue<Runnable> highQueue = new LinkedList<>();
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private final Queue<Runnable> lowQueue = new LinkedList<>();
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private boolean isTaskRunning = false;
|
||||||
|
|
||||||
|
public PriorityExecutor(Executor delegate) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
high = r -> submit(r, true);
|
||||||
|
low = r -> submit(r, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Executor getHighPriorityExecutor() {
|
||||||
|
return high;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Executor getLowPriorityExecutor() {
|
||||||
|
return low;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void submit(Runnable r, boolean isHighPriority) {
|
||||||
|
Runnable wrapped = () -> {
|
||||||
|
try {
|
||||||
|
r.run();
|
||||||
|
} finally {
|
||||||
|
scheduleNext();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
synchronized (lock) {
|
||||||
|
if (!isTaskRunning && highQueue.isEmpty() &&
|
||||||
|
(isHighPriority || lowQueue.isEmpty())) {
|
||||||
|
isTaskRunning = true;
|
||||||
|
delegate.execute(wrapped);
|
||||||
|
} else if (isHighPriority) {
|
||||||
|
highQueue.add(wrapped);
|
||||||
|
} else {
|
||||||
|
lowQueue.add(wrapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleNext() {
|
||||||
|
synchronized (lock) {
|
||||||
|
Runnable next = highQueue.poll();
|
||||||
|
if (next == null) next = lowQueue.poll();
|
||||||
|
if (next == null) isTaskRunning = false;
|
||||||
|
else delegate.execute(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,7 +39,8 @@ class ContactGroupFactoryImpl implements ContactGroupFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Group createContactGroup(ClientId clientId, int majorVersion,
|
public Group createContactGroup(ClientId clientId, int majorVersion,
|
||||||
Contact contact, AuthorId local) {
|
Contact contact) {
|
||||||
|
AuthorId local = contact.getLocalAuthorId();
|
||||||
AuthorId remote = contact.getAuthor().getId();
|
AuthorId remote = contact.getAuthor().getId();
|
||||||
byte[] descriptor = createGroupDescriptor(local, remote);
|
byte[] descriptor = createGroupDescriptor(local, remote);
|
||||||
return groupFactory.createGroup(clientId, majorVersion, descriptor);
|
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.FormatException;
|
||||||
import org.briarproject.bramble.api.client.ClientHelper;
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
|
import org.briarproject.bramble.api.contact.ContactExchangeListener;
|
||||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactExchangeFailedEvent;
|
|
||||||
import org.briarproject.bramble.api.contact.event.ContactExchangeSucceededEvent;
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||||
@@ -14,7 +13,6 @@ import org.briarproject.bramble.api.data.BdfList;
|
|||||||
import org.briarproject.bramble.api.db.ContactExistsException;
|
import org.briarproject.bramble.api.db.ContactExistsException;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
@@ -65,7 +63,6 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
private final ClientHelper clientHelper;
|
private final ClientHelper clientHelper;
|
||||||
private final RecordReaderFactory recordReaderFactory;
|
private final RecordReaderFactory recordReaderFactory;
|
||||||
private final RecordWriterFactory recordWriterFactory;
|
private final RecordWriterFactory recordWriterFactory;
|
||||||
private final EventBus eventBus;
|
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final ConnectionManager connectionManager;
|
private final ConnectionManager connectionManager;
|
||||||
private final ContactManager contactManager;
|
private final ContactManager contactManager;
|
||||||
@@ -74,18 +71,18 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
private final StreamReaderFactory streamReaderFactory;
|
private final StreamReaderFactory streamReaderFactory;
|
||||||
private final StreamWriterFactory streamWriterFactory;
|
private final StreamWriterFactory streamWriterFactory;
|
||||||
|
|
||||||
|
private volatile ContactExchangeListener listener;
|
||||||
private volatile LocalAuthor localAuthor;
|
private volatile LocalAuthor localAuthor;
|
||||||
private volatile DuplexTransportConnection conn;
|
private volatile DuplexTransportConnection conn;
|
||||||
private volatile TransportId transportId;
|
private volatile TransportId transportId;
|
||||||
private volatile SecretKey masterKey;
|
private volatile SecretKey masterSecret;
|
||||||
private volatile boolean alice;
|
private volatile boolean alice;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ContactExchangeTaskImpl(DatabaseComponent db, ClientHelper clientHelper,
|
ContactExchangeTaskImpl(DatabaseComponent db, ClientHelper clientHelper,
|
||||||
RecordReaderFactory recordReaderFactory,
|
RecordReaderFactory recordReaderFactory,
|
||||||
RecordWriterFactory recordWriterFactory, EventBus eventBus,
|
RecordWriterFactory recordWriterFactory, Clock clock,
|
||||||
Clock clock, ConnectionManager connectionManager,
|
ConnectionManager connectionManager, ContactManager contactManager,
|
||||||
ContactManager contactManager,
|
|
||||||
TransportPropertyManager transportPropertyManager,
|
TransportPropertyManager transportPropertyManager,
|
||||||
CryptoComponent crypto, StreamReaderFactory streamReaderFactory,
|
CryptoComponent crypto, StreamReaderFactory streamReaderFactory,
|
||||||
StreamWriterFactory streamWriterFactory) {
|
StreamWriterFactory streamWriterFactory) {
|
||||||
@@ -93,7 +90,6 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
this.clientHelper = clientHelper;
|
this.clientHelper = clientHelper;
|
||||||
this.recordReaderFactory = recordReaderFactory;
|
this.recordReaderFactory = recordReaderFactory;
|
||||||
this.recordWriterFactory = recordWriterFactory;
|
this.recordWriterFactory = recordWriterFactory;
|
||||||
this.eventBus = eventBus;
|
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.connectionManager = connectionManager;
|
this.connectionManager = connectionManager;
|
||||||
this.contactManager = contactManager;
|
this.contactManager = contactManager;
|
||||||
@@ -104,13 +100,15 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startExchange(LocalAuthor localAuthor, SecretKey masterKey,
|
public void startExchange(ContactExchangeListener listener,
|
||||||
|
LocalAuthor localAuthor, SecretKey masterSecret,
|
||||||
DuplexTransportConnection conn, TransportId transportId,
|
DuplexTransportConnection conn, TransportId transportId,
|
||||||
boolean alice) {
|
boolean alice) {
|
||||||
|
this.listener = listener;
|
||||||
this.localAuthor = localAuthor;
|
this.localAuthor = localAuthor;
|
||||||
this.conn = conn;
|
this.conn = conn;
|
||||||
this.transportId = transportId;
|
this.transportId = transportId;
|
||||||
this.masterKey = masterKey;
|
this.masterSecret = masterSecret;
|
||||||
this.alice = alice;
|
this.alice = alice;
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
@@ -125,8 +123,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
out = conn.getWriter().getOutputStream();
|
out = conn.getWriter().getOutputStream();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
|
listener.contactExchangeFailed();
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,15 +134,15 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
localProperties = transportPropertyManager.getLocalProperties();
|
localProperties = transportPropertyManager.getLocalProperties();
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
listener.contactExchangeFailed();
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive the header keys for the transport streams
|
// Derive the header keys for the transport streams
|
||||||
SecretKey aliceHeaderKey = crypto.deriveKey(ALICE_KEY_LABEL, masterKey,
|
SecretKey aliceHeaderKey = crypto.deriveKey(ALICE_KEY_LABEL,
|
||||||
new byte[] {PROTOCOL_VERSION});
|
masterSecret, new byte[] {PROTOCOL_VERSION});
|
||||||
SecretKey bobHeaderKey = crypto.deriveKey(BOB_KEY_LABEL, masterKey,
|
SecretKey bobHeaderKey = crypto.deriveKey(BOB_KEY_LABEL, masterSecret,
|
||||||
new byte[] {PROTOCOL_VERSION});
|
new byte[] {PROTOCOL_VERSION});
|
||||||
|
|
||||||
// Create the readers
|
// Create the readers
|
||||||
@@ -163,9 +161,9 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
.createRecordWriter(streamWriter.getOutputStream());
|
.createRecordWriter(streamWriter.getOutputStream());
|
||||||
|
|
||||||
// Derive the nonces to be signed
|
// Derive the nonces to be signed
|
||||||
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterKey,
|
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
|
||||||
new byte[] {PROTOCOL_VERSION});
|
new byte[] {PROTOCOL_VERSION});
|
||||||
byte[] bobNonce = crypto.mac(BOB_NONCE_LABEL, masterKey,
|
byte[] bobNonce = crypto.mac(BOB_NONCE_LABEL, masterSecret,
|
||||||
new byte[] {PROTOCOL_VERSION});
|
new byte[] {PROTOCOL_VERSION});
|
||||||
byte[] localNonce = alice ? aliceNonce : bobNonce;
|
byte[] localNonce = alice ? aliceNonce : bobNonce;
|
||||||
byte[] remoteNonce = alice ? bobNonce : aliceNonce;
|
byte[] remoteNonce = alice ? bobNonce : aliceNonce;
|
||||||
@@ -198,7 +196,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
listener.contactExchangeFailed();
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -206,7 +204,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
// Verify the contact's signature
|
// Verify the contact's signature
|
||||||
if (!verify(remoteInfo.author, remoteNonce, remoteInfo.signature)) {
|
if (!verify(remoteInfo.author, remoteNonce, remoteInfo.signature)) {
|
||||||
LOG.warning("Invalid signature");
|
LOG.warning("Invalid signature");
|
||||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
listener.contactExchangeFailed();
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -223,17 +221,15 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
conn);
|
conn);
|
||||||
// Pseudonym exchange succeeded
|
// Pseudonym exchange succeeded
|
||||||
LOG.info("Pseudonym exchange succeeded");
|
LOG.info("Pseudonym exchange succeeded");
|
||||||
eventBus.broadcast(
|
listener.contactExchangeSucceeded(remoteInfo.author);
|
||||||
new ContactExchangeSucceededEvent(remoteInfo.author));
|
|
||||||
} catch (ContactExistsException e) {
|
} catch (ContactExistsException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
eventBus.broadcast(
|
listener.duplicateContact(remoteInfo.author);
|
||||||
new ContactExchangeFailedEvent(remoteInfo.author));
|
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
eventBus.broadcast(new ContactExchangeFailedEvent());
|
listener.contactExchangeFailed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +289,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
throws DbException {
|
throws DbException {
|
||||||
return db.transactionWithResult(false, txn -> {
|
return db.transactionWithResult(false, txn -> {
|
||||||
ContactId contactId = contactManager.addContact(txn, remoteAuthor,
|
ContactId contactId = contactManager.addContact(txn, remoteAuthor,
|
||||||
masterKey, timestamp, alice, true, true);
|
localAuthor.getId(), masterSecret, timestamp, alice,
|
||||||
|
true, true);
|
||||||
transportPropertyManager.addRemoteProperties(txn, contactId,
|
transportPropertyManager.addRemoteProperties(txn, contactId,
|
||||||
remoteProperties);
|
remoteProperties);
|
||||||
return contactId;
|
return contactId;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.contact.PendingContactId;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.AuthorId;
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
@@ -17,6 +18,7 @@ import org.briarproject.bramble.api.identity.LocalAuthor;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.transport.KeyManager;
|
import org.briarproject.bramble.api.transport.KeyManager;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
@@ -28,9 +30,8 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
|
import static org.briarproject.bramble.api.contact.PendingContact.PendingContactState.WAITING_FOR_CONNECTION;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
import static org.briarproject.bramble.api.identity.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.OURSELVES;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN;
|
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.UNVERIFIED;
|
||||||
@@ -67,31 +68,31 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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)
|
long timestamp, boolean alice, boolean verified, boolean active)
|
||||||
throws DbException {
|
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 ->
|
return db.transactionWithResult(false, txn ->
|
||||||
addContact(txn, a, rootKey, timestamp, alice,
|
addContact(txn, remote, local, master, timestamp, alice,
|
||||||
verified, active));
|
verified, active));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,8 +123,8 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
public PendingContact addRemoteContactRequest(String link, String alias) {
|
public PendingContact addRemoteContactRequest(String link, String alias) {
|
||||||
// TODO replace with real implementation
|
// TODO replace with real implementation
|
||||||
PendingContactId id = new PendingContactId(link.getBytes());
|
PendingContactId id = new PendingContactId(link.getBytes());
|
||||||
return new PendingContact(id, new byte[MAX_PUBLIC_KEY_LENGTH], alias,
|
return new PendingContact(id, alias, WAITING_FOR_CONNECTION,
|
||||||
WAITING_FOR_CONNECTION, System.currentTimeMillis());
|
System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -143,18 +144,32 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Contact getContact(AuthorId a) throws DbException {
|
public Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId)
|
||||||
return db.transactionWithResult(true, txn -> getContact(txn, a));
|
throws DbException {
|
||||||
|
return db.transactionWithResult(true, txn ->
|
||||||
|
getContact(txn, remoteAuthorId, localAuthorId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Contact getContact(Transaction txn, AuthorId a) throws DbException {
|
public Contact getContact(Transaction txn, AuthorId remoteAuthorId,
|
||||||
return db.getContact(txn, a);
|
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
|
@Override
|
||||||
public Collection<Contact> getContacts() throws DbException {
|
public Collection<Contact> getActiveContacts() throws DbException {
|
||||||
return db.transactionWithResult(true, db::getContacts);
|
Collection<Contact> contacts =
|
||||||
|
db.transactionWithResult(true, db::getContacts);
|
||||||
|
List<Contact> active = new ArrayList<>(contacts.size());
|
||||||
|
for (Contact c : contacts) if (c.isActive()) active.add(c);
|
||||||
|
return active;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -162,6 +177,12 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
db.transaction(false, txn -> removeContact(txn, c));
|
db.transaction(false, txn -> removeContact(txn, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContactActive(Transaction txn, ContactId c, boolean active)
|
||||||
|
throws DbException {
|
||||||
|
db.setContactActive(txn, c, active);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setContactAlias(Transaction txn, ContactId c,
|
public void setContactAlias(Transaction txn, ContactId c,
|
||||||
@Nullable String alias) throws DbException {
|
@Nullable String alias) throws DbException {
|
||||||
@@ -180,14 +201,16 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contactExists(Transaction txn, AuthorId a)
|
public boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
|
||||||
throws DbException {
|
AuthorId localAuthorId) throws DbException {
|
||||||
return db.containsContact(txn, a);
|
return db.containsContact(txn, remoteAuthorId, localAuthorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contactExists(AuthorId a) throws DbException {
|
public boolean contactExists(AuthorId remoteAuthorId,
|
||||||
return db.transactionWithResult(true, txn -> contactExists(txn, a));
|
AuthorId localAuthorId) throws DbException {
|
||||||
|
return db.transactionWithResult(true, txn ->
|
||||||
|
contactExists(txn, remoteAuthorId, localAuthorId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -209,12 +232,12 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
|
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
|
||||||
if (localAuthor.getId().equals(authorId))
|
if (localAuthor.getId().equals(authorId))
|
||||||
return new AuthorInfo(OURSELVES);
|
return new AuthorInfo(OURSELVES);
|
||||||
if (db.containsContact(txn, authorId)) {
|
Collection<Contact> contacts = db.getContactsByAuthorId(txn, authorId);
|
||||||
Contact c = db.getContact(txn, authorId);
|
if (contacts.isEmpty()) return new AuthorInfo(UNKNOWN);
|
||||||
if (c.isVerified()) return new AuthorInfo(VERIFIED, c.getAlias());
|
if (contacts.size() > 1) throw new AssertionError();
|
||||||
else return new AuthorInfo(UNVERIFIED, c.getAlias());
|
Contact c = contacts.iterator().next();
|
||||||
}
|
if (c.isVerified()) return new AuthorInfo(VERIFIED, c.getAlias());
|
||||||
return new AuthorInfo(UNKNOWN);
|
else return new AuthorInfo(UNVERIFIED, c.getAlias());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,22 +4,18 @@ import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.crypto.TransportCrypto;
|
import org.briarproject.bramble.api.crypto.TransportCrypto;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
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.IncomingKeys;
|
||||||
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
|
import org.briarproject.bramble.util.ByteUtils;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.spongycastle.crypto.Digest;
|
import org.spongycastle.crypto.Digest;
|
||||||
import org.spongycastle.crypto.digests.Blake2bDigest;
|
import org.spongycastle.crypto.digests.Blake2bDigest;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.lang.System.arraycopy;
|
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_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_HEADER_LABEL;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_TAG_LABEL;
|
import static org.briarproject.bramble.api.transport.TransportConstants.ALICE_TAG_LABEL;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_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_HEADER_LABEL;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_TAG_LABEL;
|
import static org.briarproject.bramble.api.transport.TransportConstants.BOB_TAG_LABEL;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.ROTATE_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.INT_64_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.writeUint16;
|
|
||||||
import static org.briarproject.bramble.util.ByteUtils.writeUint64;
|
|
||||||
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
|
||||||
|
|
||||||
class TransportCryptoImpl implements TransportCrypto {
|
class TransportCryptoImpl implements TransportCrypto {
|
||||||
|
|
||||||
@@ -43,44 +36,45 @@ class TransportCryptoImpl implements TransportCrypto {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransportKeys deriveTransportKeys(TransportId t,
|
public TransportKeys deriveTransportKeys(TransportId t,
|
||||||
SecretKey rootKey, long timePeriod, boolean weAreAlice,
|
SecretKey master, long rotationPeriod, boolean alice,
|
||||||
boolean active) {
|
boolean active) {
|
||||||
// Keys for the previous period are derived from the root key
|
// Keys for the previous period are derived from the master secret
|
||||||
SecretKey inTagPrev = deriveTagKey(rootKey, t, !weAreAlice);
|
SecretKey inTagPrev = deriveTagKey(master, t, !alice);
|
||||||
SecretKey inHeaderPrev = deriveHeaderKey(rootKey, t, !weAreAlice);
|
SecretKey inHeaderPrev = deriveHeaderKey(master, t, !alice);
|
||||||
SecretKey outTagPrev = deriveTagKey(rootKey, t, weAreAlice);
|
SecretKey outTagPrev = deriveTagKey(master, t, alice);
|
||||||
SecretKey outHeaderPrev = deriveHeaderKey(rootKey, t, weAreAlice);
|
SecretKey outHeaderPrev = deriveHeaderKey(master, t, alice);
|
||||||
// Derive the keys for the current and next periods
|
// Derive the keys for the current and next periods
|
||||||
SecretKey inTagCurr = rotateKey(inTagPrev, timePeriod);
|
SecretKey inTagCurr = rotateKey(inTagPrev, rotationPeriod);
|
||||||
SecretKey inHeaderCurr = rotateKey(inHeaderPrev, timePeriod);
|
SecretKey inHeaderCurr = rotateKey(inHeaderPrev, rotationPeriod);
|
||||||
SecretKey inTagNext = rotateKey(inTagCurr, timePeriod + 1);
|
SecretKey inTagNext = rotateKey(inTagCurr, rotationPeriod + 1);
|
||||||
SecretKey inHeaderNext = rotateKey(inHeaderCurr, timePeriod + 1);
|
SecretKey inHeaderNext = rotateKey(inHeaderCurr, rotationPeriod + 1);
|
||||||
SecretKey outTagCurr = rotateKey(outTagPrev, timePeriod);
|
SecretKey outTagCurr = rotateKey(outTagPrev, rotationPeriod);
|
||||||
SecretKey outHeaderCurr = rotateKey(outHeaderPrev, timePeriod);
|
SecretKey outHeaderCurr = rotateKey(outHeaderPrev, rotationPeriod);
|
||||||
// Initialise the reordering windows and stream counters
|
// Initialise the reordering windows and stream counters
|
||||||
IncomingKeys inPrev = new IncomingKeys(inTagPrev, inHeaderPrev,
|
IncomingKeys inPrev = new IncomingKeys(inTagPrev, inHeaderPrev,
|
||||||
timePeriod - 1);
|
rotationPeriod - 1);
|
||||||
IncomingKeys inCurr = new IncomingKeys(inTagCurr, inHeaderCurr,
|
IncomingKeys inCurr = new IncomingKeys(inTagCurr, inHeaderCurr,
|
||||||
timePeriod);
|
rotationPeriod);
|
||||||
IncomingKeys inNext = new IncomingKeys(inTagNext, inHeaderNext,
|
IncomingKeys inNext = new IncomingKeys(inTagNext, inHeaderNext,
|
||||||
timePeriod + 1);
|
rotationPeriod + 1);
|
||||||
OutgoingKeys outCurr = new OutgoingKeys(outTagCurr, outHeaderCurr,
|
OutgoingKeys outCurr = new OutgoingKeys(outTagCurr, outHeaderCurr,
|
||||||
timePeriod, active);
|
rotationPeriod, active);
|
||||||
// Collect and return the keys
|
// Collect and return the keys
|
||||||
return new TransportKeys(t, inPrev, inCurr, inNext, outCurr);
|
return new TransportKeys(t, inPrev, inCurr, inNext, outCurr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod) {
|
public TransportKeys rotateTransportKeys(TransportKeys k,
|
||||||
if (k.getTimePeriod() >= timePeriod) return k;
|
long rotationPeriod) {
|
||||||
|
if (k.getRotationPeriod() >= rotationPeriod) return k;
|
||||||
IncomingKeys inPrev = k.getPreviousIncomingKeys();
|
IncomingKeys inPrev = k.getPreviousIncomingKeys();
|
||||||
IncomingKeys inCurr = k.getCurrentIncomingKeys();
|
IncomingKeys inCurr = k.getCurrentIncomingKeys();
|
||||||
IncomingKeys inNext = k.getNextIncomingKeys();
|
IncomingKeys inNext = k.getNextIncomingKeys();
|
||||||
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
|
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
|
||||||
long startPeriod = outCurr.getTimePeriod();
|
long startPeriod = outCurr.getRotationPeriod();
|
||||||
boolean active = outCurr.isActive();
|
boolean active = outCurr.isActive();
|
||||||
// Rotate the keys
|
// Rotate the keys
|
||||||
for (long p = startPeriod + 1; p <= timePeriod; p++) {
|
for (long p = startPeriod + 1; p <= rotationPeriod; p++) {
|
||||||
inPrev = inCurr;
|
inPrev = inCurr;
|
||||||
inCurr = inNext;
|
inCurr = inNext;
|
||||||
SecretKey inNextTag = rotateKey(inNext.getTagKey(), p + 1);
|
SecretKey inNextTag = rotateKey(inNext.getTagKey(), p + 1);
|
||||||
@@ -95,117 +89,24 @@ class TransportCryptoImpl implements TransportCrypto {
|
|||||||
outCurr);
|
outCurr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey rotateKey(SecretKey k, long timePeriod) {
|
private SecretKey rotateKey(SecretKey k, long rotationPeriod) {
|
||||||
byte[] period = new byte[INT_64_BYTES];
|
byte[] period = new byte[INT_64_BYTES];
|
||||||
writeUint64(timePeriod, period, 0);
|
ByteUtils.writeUint64(rotationPeriod, period, 0);
|
||||||
return crypto.deriveKey(ROTATE_LABEL, k, period);
|
return crypto.deriveKey(ROTATE_LABEL, k, period);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey deriveTagKey(SecretKey rootKey, TransportId t,
|
private SecretKey deriveTagKey(SecretKey master, TransportId t,
|
||||||
boolean keyBelongsToAlice) {
|
boolean alice) {
|
||||||
String label = keyBelongsToAlice ? ALICE_TAG_LABEL : BOB_TAG_LABEL;
|
String label = alice ? ALICE_TAG_LABEL : BOB_TAG_LABEL;
|
||||||
byte[] id = toUtf8(t.getString());
|
byte[] id = StringUtils.toUtf8(t.getString());
|
||||||
return crypto.deriveKey(label, rootKey, id);
|
return crypto.deriveKey(label, master, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey deriveHeaderKey(SecretKey rootKey, TransportId t,
|
private SecretKey deriveHeaderKey(SecretKey master, TransportId t,
|
||||||
boolean keyBelongsToAlice) {
|
boolean alice) {
|
||||||
String label = keyBelongsToAlice ? ALICE_HEADER_LABEL :
|
String label = alice ? ALICE_HEADER_LABEL : BOB_HEADER_LABEL;
|
||||||
BOB_HEADER_LABEL;
|
byte[] id = StringUtils.toUtf8(t.getString());
|
||||||
byte[] id = toUtf8(t.getString());
|
return crypto.deriveKey(label, master, id);
|
||||||
return crypto.deriveKey(label, 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -224,14 +125,14 @@ class TransportCryptoImpl implements TransportCrypto {
|
|||||||
// The input is the protocol version as a 16-bit integer, followed by
|
// The input is the protocol version as a 16-bit integer, followed by
|
||||||
// the stream number as a 64-bit integer
|
// the stream number as a 64-bit integer
|
||||||
byte[] protocolVersionBytes = new byte[INT_16_BYTES];
|
byte[] protocolVersionBytes = new byte[INT_16_BYTES];
|
||||||
writeUint16(protocolVersion, protocolVersionBytes, 0);
|
ByteUtils.writeUint16(protocolVersion, protocolVersionBytes, 0);
|
||||||
prf.update(protocolVersionBytes, 0, protocolVersionBytes.length);
|
prf.update(protocolVersionBytes, 0, protocolVersionBytes.length);
|
||||||
byte[] streamNumberBytes = new byte[INT_64_BYTES];
|
byte[] streamNumberBytes = new byte[INT_64_BYTES];
|
||||||
writeUint64(streamNumber, streamNumberBytes, 0);
|
ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0);
|
||||||
prf.update(streamNumberBytes, 0, streamNumberBytes.length);
|
prf.update(streamNumberBytes, 0, streamNumberBytes.length);
|
||||||
byte[] mac = new byte[macLength];
|
byte[] mac = new byte[macLength];
|
||||||
prf.doFinal(mac, 0);
|
prf.doFinal(mac, 0);
|
||||||
// The output is the first TAG_LENGTH bytes of the MAC
|
// The output is the first TAG_LENGTH bytes of the MAC
|
||||||
arraycopy(mac, 0, tag, 0, TAG_LENGTH);
|
System.arraycopy(mac, 0, tag, 0, TAG_LENGTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,9 @@ package org.briarproject.bramble.db;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.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.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DataTooNewException;
|
import org.briarproject.bramble.api.db.DataTooNewException;
|
||||||
import org.briarproject.bramble.api.db.DataTooOldException;
|
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.DbException;
|
||||||
import org.briarproject.bramble.api.db.MessageDeletedException;
|
import org.briarproject.bramble.api.db.MessageDeletedException;
|
||||||
import org.briarproject.bramble.api.db.Metadata;
|
import org.briarproject.bramble.api.db.Metadata;
|
||||||
@@ -27,11 +23,8 @@ import org.briarproject.bramble.api.sync.Message;
|
|||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||||
import org.briarproject.bramble.api.transport.HandshakeKeySet;
|
import org.briarproject.bramble.api.transport.KeySet;
|
||||||
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
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.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -40,14 +33,11 @@ import java.util.Map;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A low-level interface to the database ({@link DatabaseComponent} provides a
|
* A low-level interface to the database (DatabaseComponent provides a
|
||||||
* high-level interface).
|
* high-level interface). Most operations take a transaction argument, which is
|
||||||
* <p/>
|
* obtained by calling {@link #startTransaction()}. Every transaction must be
|
||||||
* Most operations take a transaction argument, which is obtained by calling
|
* terminated by calling either {@link #abortTransaction(Object) abortTransaction(T)} or
|
||||||
* {@link #startTransaction()}. Every transaction must be terminated by calling
|
* {@link #commitTransaction(Object) commitTransaction(T)}, even if an exception is thrown.
|
||||||
* either {@link #abortTransaction(Object) abortTransaction(T)} or
|
|
||||||
* {@link #commitTransaction(Object) commitTransaction(T)}, even if an
|
|
||||||
* exception is thrown.
|
|
||||||
*/
|
*/
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
interface Database<T> {
|
interface Database<T> {
|
||||||
@@ -87,10 +77,11 @@ interface Database<T> {
|
|||||||
void commitTransaction(T txn) throws DbException;
|
void commitTransaction(T txn) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a contact with the given pseudonym and returns an ID for the
|
* Stores a contact associated with the given local and remote pseudonyms,
|
||||||
* contact.
|
* 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.
|
* Stores a group.
|
||||||
@@ -104,20 +95,6 @@ interface Database<T> {
|
|||||||
void addGroupVisibility(T txn, ContactId c, GroupId g, boolean shared)
|
void addGroupVisibility(T txn, ContactId c, GroupId g, boolean shared)
|
||||||
throws DbException;
|
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.
|
* Stores a local pseudonym.
|
||||||
*/
|
*/
|
||||||
@@ -144,11 +121,6 @@ interface Database<T> {
|
|||||||
*/
|
*/
|
||||||
void addOfferedMessage(T txn, ContactId c, MessageId m) throws DbException;
|
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.
|
* Stores a transport.
|
||||||
*/
|
*/
|
||||||
@@ -159,15 +131,17 @@ interface Database<T> {
|
|||||||
* Stores the given transport keys for the given contact and returns a
|
* Stores the given transport keys for the given contact and returns a
|
||||||
* key set ID.
|
* key set ID.
|
||||||
*/
|
*/
|
||||||
TransportKeySetId addTransportKeys(T txn, ContactId c, TransportKeys k)
|
KeySetId addTransportKeys(T txn, ContactId c, TransportKeys k)
|
||||||
throws DbException;
|
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/>
|
* <p/>
|
||||||
* Read-only.
|
* 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.
|
* Returns true if the database contains the given contact.
|
||||||
@@ -197,14 +171,6 @@ interface Database<T> {
|
|||||||
*/
|
*/
|
||||||
boolean containsMessage(T txn, MessageId m) throws DbException;
|
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.
|
* Returns true if the database contains the given transport.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -249,13 +215,6 @@ interface Database<T> {
|
|||||||
*/
|
*/
|
||||||
Contact getContact(T txn, ContactId c) throws DbException;
|
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.
|
* Returns all contacts.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -263,6 +222,28 @@ interface Database<T> {
|
|||||||
*/
|
*/
|
||||||
Collection<Contact> getContacts(T txn) throws DbException;
|
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.
|
* Returns the group with the given ID.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -303,14 +284,6 @@ interface Database<T> {
|
|||||||
Map<ContactId, Boolean> getGroupVisibility(T txn, GroupId g)
|
Map<ContactId, Boolean> getGroupVisibility(T txn, GroupId g)
|
||||||
throws DbException;
|
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.
|
* Returns the local pseudonym with the given ID.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -501,13 +474,6 @@ interface Database<T> {
|
|||||||
*/
|
*/
|
||||||
long getNextSendTime(T txn, ContactId c) throws DbException;
|
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
|
* 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
|
* given contact and have been requested by the contact, up to the given
|
||||||
@@ -530,19 +496,13 @@ interface Database<T> {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<TransportKeySet> getTransportKeys(T txn, TransportId t)
|
Collection<KeySet> 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)
|
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increments the outgoing stream counter for the given transport keys.
|
* 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;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -611,12 +571,6 @@ interface Database<T> {
|
|||||||
void removeGroupVisibility(T txn, ContactId c, GroupId g)
|
void removeGroupVisibility(T txn, ContactId c, GroupId g)
|
||||||
throws DbException;
|
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.
|
* Removes a local pseudonym (and all associated state) from the database.
|
||||||
*/
|
*/
|
||||||
@@ -634,11 +588,6 @@ interface Database<T> {
|
|||||||
void removeOfferedMessages(T txn, ContactId c,
|
void removeOfferedMessages(T txn, ContactId c,
|
||||||
Collection<MessageId> requested) throws DbException;
|
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.
|
* 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.
|
* 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;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -661,6 +610,12 @@ interface Database<T> {
|
|||||||
*/
|
*/
|
||||||
void setContactVerified(T txn, ContactId c) throws DbException;
|
void setContactVerified(T txn, ContactId c) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the given contact as active or inactive.
|
||||||
|
*/
|
||||||
|
void setContactActive(T txn, ContactId c, boolean active)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an alias name for a contact.
|
* Sets an alias name for a contact.
|
||||||
*/
|
*/
|
||||||
@@ -686,29 +641,16 @@ interface Database<T> {
|
|||||||
throws DbException;
|
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,
|
void setReorderingWindow(T txn, KeySetId k, TransportId t,
|
||||||
PendingContactState state) throws DbException;
|
long rotationPeriod, long base, byte[] bitmap) 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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the given transport keys as usable for outgoing streams.
|
* 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;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -719,13 +661,8 @@ interface Database<T> {
|
|||||||
void updateExpiryTimeAndEta(T txn, ContactId c, MessageId m, int maxLatency)
|
void updateExpiryTimeAndEta(T txn, ContactId c, MessageId m, int maxLatency)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the given handshake keys.
|
|
||||||
*/
|
|
||||||
void updateHandshakeKeys(T txn, HandshakeKeySet ks) throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the given transport keys following key rotation.
|
* 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,27 @@ package org.briarproject.bramble.db;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.PendingContact;
|
|
||||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
|
||||||
import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
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.contact.event.ContactVerifiedEvent;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
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.ContactExistsException;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbCallable;
|
import org.briarproject.bramble.api.db.DbCallable;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.DbRunnable;
|
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.Metadata;
|
||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
import org.briarproject.bramble.api.db.MigrationListener;
|
||||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||||
import org.briarproject.bramble.api.db.NoSuchGroupException;
|
import org.briarproject.bramble.api.db.NoSuchGroupException;
|
||||||
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
|
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
|
||||||
import org.briarproject.bramble.api.db.NoSuchMessageException;
|
import org.briarproject.bramble.api.db.NoSuchMessageException;
|
||||||
import org.briarproject.bramble.api.db.NoSuchPendingContactException;
|
|
||||||
import org.briarproject.bramble.api.db.NoSuchTransportException;
|
import org.briarproject.bramble.api.db.NoSuchTransportException;
|
||||||
import org.briarproject.bramble.api.db.NullableDbCallable;
|
import org.briarproject.bramble.api.db.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.db.Transaction;
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
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.Author;
|
||||||
import org.briarproject.bramble.api.identity.AuthorId;
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
@@ -62,11 +55,8 @@ import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
|
|||||||
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
|
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
|
||||||
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
|
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
|
||||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||||
import org.briarproject.bramble.api.transport.HandshakeKeySet;
|
import org.briarproject.bramble.api.transport.KeySet;
|
||||||
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
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.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -74,7 +64,6 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -103,29 +92,25 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
private final Database<T> db;
|
private final Database<T> db;
|
||||||
private final Class<T> txnClass;
|
private final Class<T> txnClass;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final Executor eventExecutor;
|
private final ShutdownManager shutdown;
|
||||||
private final ShutdownManager shutdownManager;
|
|
||||||
private final AtomicBoolean closed = new AtomicBoolean(false);
|
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||||
private final ReentrantReadWriteLock lock =
|
private final ReentrantReadWriteLock lock =
|
||||||
new ReentrantReadWriteLock(true);
|
new ReentrantReadWriteLock(true);
|
||||||
private final Visitor visitor = new CommitActionVisitor();
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
DatabaseComponentImpl(Database<T> db, Class<T> txnClass, EventBus eventBus,
|
DatabaseComponentImpl(Database<T> db, Class<T> txnClass, EventBus eventBus,
|
||||||
@EventExecutor Executor eventExecutor,
|
ShutdownManager shutdown) {
|
||||||
ShutdownManager shutdownManager) {
|
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.txnClass = txnClass;
|
this.txnClass = txnClass;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.eventExecutor = eventExecutor;
|
this.shutdown = shutdown;
|
||||||
this.shutdownManager = shutdownManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean open(SecretKey key, @Nullable MigrationListener listener)
|
public boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
boolean reopened = db.open(key, listener);
|
boolean reopened = db.open(key, listener);
|
||||||
shutdownManager.addShutdownHook(() -> {
|
shutdown.addShutdownHook(() -> {
|
||||||
try {
|
try {
|
||||||
close();
|
close();
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -175,16 +160,13 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
public void endTransaction(Transaction transaction) {
|
public void endTransaction(Transaction transaction) {
|
||||||
try {
|
try {
|
||||||
T txn = txnClass.cast(transaction.unbox());
|
T txn = txnClass.cast(transaction.unbox());
|
||||||
if (transaction.isCommitted()) {
|
if (!transaction.isCommitted()) db.abortTransaction(txn);
|
||||||
for (CommitAction a : transaction.getActions())
|
|
||||||
a.accept(visitor);
|
|
||||||
} else {
|
|
||||||
db.abortTransaction(txn);
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
if (transaction.isReadOnly()) lock.readLock().unlock();
|
if (transaction.isReadOnly()) lock.readLock().unlock();
|
||||||
else lock.writeLock().unlock();
|
else lock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
if (transaction.isCommitted())
|
||||||
|
for (Event e : transaction.getEvents()) eventBus.broadcast(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -232,16 +214,20 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContactId addContact(Transaction transaction, Author a,
|
public ContactId addContact(Transaction transaction, Author remote,
|
||||||
boolean verified) throws DbException {
|
AuthorId local, boolean verified, boolean active)
|
||||||
|
throws DbException {
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
T txn = unbox(transaction);
|
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();
|
throw new ContactExistsException();
|
||||||
if (db.containsContact(txn, a.getId()))
|
if (db.containsContact(txn, remote.getId(), local))
|
||||||
throw new ContactExistsException();
|
throw new ContactExistsException();
|
||||||
ContactId c = db.addContact(txn, a, verified);
|
ContactId c = db.addContact(txn, remote, local, verified, active);
|
||||||
transaction.attach(new ContactAddedEvent(c));
|
transaction.attach(new ContactAddedEvent(c, active));
|
||||||
|
if (active) transaction.attach(new ContactStatusChangedEvent(c, true));
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,30 +241,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
|
@Override
|
||||||
public void addLocalAuthor(Transaction transaction, LocalAuthor a)
|
public void addLocalAuthor(Transaction transaction, LocalAuthor a)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -307,16 +269,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
db.mergeMessageMetadata(txn, m.getId(), meta);
|
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
|
@Override
|
||||||
public void addTransport(Transaction transaction, TransportId t,
|
public void addTransport(Transaction transaction, TransportId t,
|
||||||
int maxLatency) throws DbException {
|
int maxLatency) throws DbException {
|
||||||
@@ -327,8 +279,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransportKeySetId addTransportKeys(Transaction transaction,
|
public KeySetId addTransportKeys(Transaction transaction, ContactId c,
|
||||||
ContactId c, TransportKeys k) throws DbException {
|
TransportKeys k) throws DbException {
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsContact(txn, c))
|
if (!db.containsContact(txn, c))
|
||||||
@@ -339,10 +291,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsContact(Transaction transaction, AuthorId a)
|
public boolean containsContact(Transaction transaction, AuthorId remote,
|
||||||
throws DbException {
|
AuthorId local) throws DbException {
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
return db.containsContact(txn, a);
|
if (!db.containsLocalAuthor(txn, local))
|
||||||
|
throw new NoSuchLocalAuthorException();
|
||||||
|
return db.containsContact(txn, remote, local);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -359,13 +313,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
return db.containsLocalAuthor(txn, local);
|
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
|
@Override
|
||||||
public void deleteMessage(Transaction transaction, MessageId m)
|
public void deleteMessage(Transaction transaction, MessageId m)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -482,15 +429,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
return db.getContact(txn, c);
|
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
|
@Override
|
||||||
public Collection<Contact> getContacts(Transaction transaction)
|
public Collection<Contact> getContacts(Transaction transaction)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -498,6 +436,22 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
return db.getContacts(txn);
|
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
|
@Override
|
||||||
public Group getGroup(Transaction transaction, GroupId g)
|
public Group getGroup(Transaction transaction, GroupId g)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -532,15 +486,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
return db.getGroupVisibility(txn, c, g);
|
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
|
@Override
|
||||||
public LocalAuthor getLocalAuthor(Transaction transaction, AuthorId a)
|
public LocalAuthor getLocalAuthor(Transaction transaction, AuthorId a)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -698,13 +643,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
return db.getNextSendTime(txn, c);
|
return db.getNextSendTime(txn, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<PendingContact> getPendingContacts(
|
|
||||||
Transaction transaction) throws DbException {
|
|
||||||
T txn = unbox(transaction);
|
|
||||||
return db.getPendingContacts(txn);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Settings getSettings(Transaction transaction, String namespace)
|
public Settings getSettings(Transaction transaction, String namespace)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -713,7 +651,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<TransportKeySet> getTransportKeys(Transaction transaction,
|
public Collection<KeySet> getTransportKeys(Transaction transaction,
|
||||||
TransportId t) throws DbException {
|
TransportId t) throws DbException {
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsTransport(txn, t))
|
if (!db.containsTransport(txn, t))
|
||||||
@@ -723,17 +661,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void incrementStreamCounter(Transaction transaction, TransportId t,
|
public void incrementStreamCounter(Transaction transaction, TransportId t,
|
||||||
HandshakeKeySetId k) throws DbException {
|
KeySetId 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 {
|
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsTransport(txn, t))
|
if (!db.containsTransport(txn, t))
|
||||||
@@ -882,16 +810,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
transaction.attach(new GroupVisibilityUpdatedEvent(affected));
|
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
|
@Override
|
||||||
public void removeLocalAuthor(Transaction transaction, AuthorId a)
|
public void removeLocalAuthor(Transaction transaction, AuthorId a)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -914,16 +832,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
db.removeMessage(txn, m);
|
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
|
@Override
|
||||||
public void removeTransport(Transaction transaction, TransportId t)
|
public void removeTransport(Transaction transaction, TransportId t)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -936,7 +844,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeTransportKeys(Transaction transaction,
|
public void removeTransportKeys(Transaction transaction,
|
||||||
TransportId t, TransportKeySetId k) throws DbException {
|
TransportId t, KeySetId k) throws DbException {
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsTransport(txn, t))
|
if (!db.containsTransport(txn, t))
|
||||||
@@ -955,6 +863,17 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
transaction.attach(new ContactVerifiedEvent(c));
|
transaction.attach(new ContactVerifiedEvent(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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.setContactActive(txn, c, active);
|
||||||
|
transaction.attach(new ContactStatusChangedEvent(c, active));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setContactAlias(Transaction transaction, ContactId c,
|
public void setContactAlias(Transaction transaction, ContactId c,
|
||||||
@Nullable String alias) throws DbException {
|
@Nullable String alias) throws DbException {
|
||||||
@@ -1024,30 +943,19 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setReorderingWindow(Transaction transaction,
|
public void setReorderingWindow(Transaction transaction, KeySetId k,
|
||||||
TransportKeySetId k, TransportId t, long timePeriod, long base,
|
TransportId t, long rotationPeriod, long base, byte[] bitmap)
|
||||||
byte[] bitmap) throws DbException {
|
throws DbException {
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsTransport(txn, t))
|
if (!db.containsTransport(txn, t))
|
||||||
throw new NoSuchTransportException();
|
throw new NoSuchTransportException();
|
||||||
db.setReorderingWindow(txn, k, t, timePeriod, base, bitmap);
|
db.setReorderingWindow(txn, k, t, rotationPeriod, 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTransportKeysActive(Transaction transaction, TransportId t,
|
public void setTransportKeysActive(Transaction transaction, TransportId t,
|
||||||
TransportKeySetId k) throws DbException {
|
KeySetId k) throws DbException {
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsTransport(txn, t))
|
if (!db.containsTransport(txn, t))
|
||||||
@@ -1055,40 +963,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
db.setTransportKeysActive(txn, t, k);
|
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
|
@Override
|
||||||
public void updateTransportKeys(Transaction transaction,
|
public void updateTransportKeys(Transaction transaction,
|
||||||
Collection<TransportKeySet> keys) throws DbException {
|
Collection<KeySet> keys) throws DbException {
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
for (TransportKeySet ks : keys) {
|
for (KeySet ks : keys) {
|
||||||
TransportId t = ks.getKeys().getTransportId();
|
TransportId t = ks.getTransportKeys().getTransportId();
|
||||||
if (db.containsTransport(txn, t))
|
if (db.containsTransport(txn, t))
|
||||||
db.updateTransportKeys(txn, ks);
|
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.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
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.lifecycle.ShutdownManager;
|
||||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
@@ -29,9 +27,8 @@ public class DatabaseModule {
|
|||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
DatabaseComponent provideDatabaseComponent(Database<Connection> db,
|
DatabaseComponent provideDatabaseComponent(Database<Connection> db,
|
||||||
EventBus eventBus, @EventExecutor Executor eventExecutor,
|
EventBus eventBus, ShutdownManager shutdown) {
|
||||||
ShutdownManager shutdownManager) {
|
|
||||||
return new DatabaseComponentImpl<>(db, Connection.class, eventBus,
|
return new DatabaseComponentImpl<>(db, Connection.class, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,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
|
@Override
|
||||||
protected Connection createConnection() throws SQLException {
|
protected Connection createConnection() throws SQLException {
|
||||||
SecretKey key = this.key;
|
SecretKey key = this.key;
|
||||||
|
|||||||
@@ -86,6 +86,30 @@ class HyperSqlDatabase 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
|
@Override
|
||||||
protected Connection createConnection() throws SQLException {
|
protected Connection createConnection() throws SQLException {
|
||||||
SecretKey key = this.key;
|
SecretKey key = this.key;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@ class Migration40_41 implements Migration<Connection> {
|
|||||||
|
|
||||||
private final DatabaseTypes dbTypes;
|
private final DatabaseTypes dbTypes;
|
||||||
|
|
||||||
Migration40_41(DatabaseTypes databaseTypes) {
|
public Migration40_41(DatabaseTypes databaseTypes) {
|
||||||
this.dbTypes = databaseTypes;
|
this.dbTypes = databaseTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
package org.briarproject.bramble.db;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
|
||||||
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
|
||||||
|
|
||||||
class Migration41_42 implements Migration<Connection> {
|
|
||||||
|
|
||||||
private static final Logger LOG = getLogger(Migration41_42.class.getName());
|
|
||||||
|
|
||||||
private final DatabaseTypes dbTypes;
|
|
||||||
|
|
||||||
Migration41_42(DatabaseTypes dbTypes) {
|
|
||||||
this.dbTypes = dbTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getStartVersion() {
|
|
||||||
return 41;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getEndVersion() {
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void migrate(Connection txn) throws DbException {
|
|
||||||
Statement s = null;
|
|
||||||
try {
|
|
||||||
s = txn.createStatement();
|
|
||||||
s.execute("ALTER TABLE outgoingKeys"
|
|
||||||
+ " ALTER COLUMN rotationPeriod"
|
|
||||||
+ " RENAME TO timePeriod");
|
|
||||||
s.execute("ALTER TABLE incomingKeys"
|
|
||||||
+ " ALTER COLUMN rotationPeriod"
|
|
||||||
+ " RENAME TO timePeriod");
|
|
||||||
s.execute("ALTER TABLE incomingKeys"
|
|
||||||
+ " DROP COLUMN contactId");
|
|
||||||
s.execute(dbTypes.replaceTypes("CREATE TABLE pendingContacts"
|
|
||||||
+ " (pendingContactId _HASH NOT NULL,"
|
|
||||||
+ " publicKey _BINARY NOT NULL,"
|
|
||||||
+ " alias _STRING NOT NULL,"
|
|
||||||
+ " state INT NOT NULL,"
|
|
||||||
+ " timestamp BIGINT NOT NULL,"
|
|
||||||
+ " PRIMARY KEY (pendingContactId))"));
|
|
||||||
s.execute(dbTypes.replaceTypes("CREATE TABLE outgoingHandshakeKeys"
|
|
||||||
+ " (transportId _STRING NOT NULL,"
|
|
||||||
+ " keySetId _COUNTER,"
|
|
||||||
+ " timePeriod BIGINT NOT NULL,"
|
|
||||||
+ " contactId INT," // Null if contact is pending
|
|
||||||
+ " pendingContactId _HASH," // Null if not pending
|
|
||||||
+ " rootKey _SECRET NOT NULL,"
|
|
||||||
+ " alice BOOLEAN NOT NULL,"
|
|
||||||
+ " tagKey _SECRET NOT NULL,"
|
|
||||||
+ " headerKey _SECRET NOT NULL,"
|
|
||||||
+ " stream BIGINT NOT NULL,"
|
|
||||||
+ " PRIMARY KEY (transportId, keySetId),"
|
|
||||||
+ " FOREIGN KEY (transportId)"
|
|
||||||
+ " REFERENCES transports (transportId)"
|
|
||||||
+ " ON DELETE CASCADE,"
|
|
||||||
+ " UNIQUE (keySetId),"
|
|
||||||
+ " FOREIGN KEY (contactId)"
|
|
||||||
+ " REFERENCES contacts (contactId)"
|
|
||||||
+ " ON DELETE CASCADE,"
|
|
||||||
+ " FOREIGN KEY (pendingContactId)"
|
|
||||||
+ " REFERENCES pendingContacts (pendingContactId)"
|
|
||||||
+ " ON DELETE CASCADE)"));
|
|
||||||
s.execute(dbTypes.replaceTypes("CREATE TABLE incomingHandshakeKeys"
|
|
||||||
+ " (transportId _STRING NOT NULL,"
|
|
||||||
+ " keySetId INT NOT NULL,"
|
|
||||||
+ " timePeriod BIGINT NOT NULL,"
|
|
||||||
+ " tagKey _SECRET NOT NULL,"
|
|
||||||
+ " headerKey _SECRET NOT NULL,"
|
|
||||||
+ " base BIGINT NOT NULL,"
|
|
||||||
+ " bitmap _BINARY NOT NULL,"
|
|
||||||
+ " periodOffset INT NOT NULL,"
|
|
||||||
+ " PRIMARY KEY (transportId, keySetId, periodOffset),"
|
|
||||||
+ " FOREIGN KEY (transportId)"
|
|
||||||
+ " REFERENCES transports (transportId)"
|
|
||||||
+ " ON DELETE CASCADE,"
|
|
||||||
+ " FOREIGN KEY (keySetId)"
|
|
||||||
+ " REFERENCES outgoingHandshakeKeys (keySetId)"
|
|
||||||
+ " ON DELETE CASCADE)"));
|
|
||||||
} catch (SQLException e) {
|
|
||||||
tryToClose(s, LOG, WARNING);
|
|
||||||
throw new DbException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package org.briarproject.bramble.db;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
|
||||||
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
|
||||||
|
|
||||||
class Migration42_43 implements Migration<Connection> {
|
|
||||||
|
|
||||||
private static final Logger LOG = getLogger(Migration42_43.class.getName());
|
|
||||||
|
|
||||||
private final DatabaseTypes dbTypes;
|
|
||||||
|
|
||||||
Migration42_43(DatabaseTypes dbTypes) {
|
|
||||||
this.dbTypes = dbTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getStartVersion() {
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getEndVersion() {
|
|
||||||
return 43;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void migrate(Connection txn) throws DbException {
|
|
||||||
Statement s = null;
|
|
||||||
try {
|
|
||||||
s = txn.createStatement();
|
|
||||||
s.execute(dbTypes.replaceTypes("ALTER TABLE localAuthors"
|
|
||||||
+ " ADD COLUMN handshakePublicKey _BINARY"));
|
|
||||||
s.execute(dbTypes.replaceTypes("ALTER TABLE localAuthors"
|
|
||||||
+ " ADD COLUMN handshakePrivateKey _BINARY"));
|
|
||||||
s.execute(dbTypes.replaceTypes("ALTER TABLE contacts"
|
|
||||||
+ " ADD COLUMN handshakePublicKey _BINARY"));
|
|
||||||
s.execute("ALTER TABLE contacts"
|
|
||||||
+ " DROP COLUMN active");
|
|
||||||
} catch (SQLException e) {
|
|
||||||
tryToClose(s, LOG, WARNING);
|
|
||||||
throw new DbException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package org.briarproject.bramble.db;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
|
||||||
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
|
||||||
|
|
||||||
class Migration43_44 implements Migration<Connection> {
|
|
||||||
|
|
||||||
private static final Logger LOG = getLogger(Migration43_44.class.getName());
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getStartVersion() {
|
|
||||||
return 43;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getEndVersion() {
|
|
||||||
return 44;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void migrate(Connection txn) throws DbException {
|
|
||||||
Statement s = null;
|
|
||||||
try {
|
|
||||||
s = txn.createStatement();
|
|
||||||
s.execute("ALTER TABLE contacts"
|
|
||||||
+ " DROP COLUMN localAuthorId");
|
|
||||||
} catch (SQLException e) {
|
|
||||||
tryToClose(s, LOG, WARNING);
|
|
||||||
throw new DbException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package org.briarproject.bramble.event;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.EventExecutor;
|
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.Provides;
|
|
||||||
|
|
||||||
import static java.util.concurrent.Executors.newSingleThreadExecutor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default implementation of {@link EventExecutor} that uses a dedicated thread
|
|
||||||
* to notify listeners of events. Applications may prefer to supply an
|
|
||||||
* implementation that uses an existing thread, such as the UI thread.
|
|
||||||
*/
|
|
||||||
@Module
|
|
||||||
public class DefaultEventExecutorModule {
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
@EventExecutor
|
|
||||||
Executor provideEventExecutor() {
|
|
||||||
return newSingleThreadExecutor(r -> {
|
|
||||||
Thread t = new Thread(r);
|
|
||||||
t.setDaemon(true);
|
|
||||||
return t;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,16 +2,13 @@ package org.briarproject.bramble.event;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.event.EventExecutor;
|
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -19,12 +16,6 @@ class EventBusImpl implements EventBus {
|
|||||||
|
|
||||||
private final Collection<EventListener> listeners =
|
private final Collection<EventListener> listeners =
|
||||||
new CopyOnWriteArrayList<>();
|
new CopyOnWriteArrayList<>();
|
||||||
private final Executor eventExecutor;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
EventBusImpl(@EventExecutor Executor eventExecutor) {
|
|
||||||
this.eventExecutor = eventExecutor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addListener(EventListener l) {
|
public void addListener(EventListener l) {
|
||||||
@@ -38,8 +29,6 @@ class EventBusImpl implements EventBus {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void broadcast(Event e) {
|
public void broadcast(Event e) {
|
||||||
eventExecutor.execute(() -> {
|
for (EventListener l : listeners) l.eventOccurred(e);
|
||||||
for (EventListener l : listeners) l.eventOccurred(e);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class EventModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
EventBus provideEventBus(EventBusImpl eventBus) {
|
EventBus provideEventBus() {
|
||||||
return eventBus;
|
return new EventBusImpl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import java.io.IOException;
|
|||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_KEY_LABEL;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_SECRET_LABEL;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL;
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ class KeyAgreementProtocol {
|
|||||||
/**
|
/**
|
||||||
* Perform the BQP protocol.
|
* Perform the BQP protocol.
|
||||||
*
|
*
|
||||||
* @return the negotiated master key.
|
* @return the negotiated master secret.
|
||||||
* @throws AbortException when the protocol may have been tampered with.
|
* @throws AbortException when the protocol may have been tampered with.
|
||||||
* @throws IOException for all other other connection errors.
|
* @throws IOException for all other other connection errors.
|
||||||
*/
|
*/
|
||||||
@@ -115,7 +115,7 @@ class KeyAgreementProtocol {
|
|||||||
receiveConfirm(s, theirPublicKey);
|
receiveConfirm(s, theirPublicKey);
|
||||||
sendConfirm(s, theirPublicKey);
|
sendConfirm(s, theirPublicKey);
|
||||||
}
|
}
|
||||||
return crypto.deriveKey(MASTER_KEY_LABEL, s);
|
return crypto.deriveKey(MASTER_SECRET_LABEL, s);
|
||||||
} catch (AbortException e) {
|
} catch (AbortException e) {
|
||||||
sendAbort(e.getCause() != null);
|
sendAbort(e.getCause() != null);
|
||||||
throw e;
|
throw e;
|
||||||
|
|||||||
@@ -114,9 +114,9 @@ class KeyAgreementTaskImpl extends Thread implements KeyAgreementTask,
|
|||||||
keyAgreementCrypto, payloadEncoder, transport, remotePayload,
|
keyAgreementCrypto, payloadEncoder, transport, remotePayload,
|
||||||
localPayload, localKeyPair, alice);
|
localPayload, localKeyPair, alice);
|
||||||
try {
|
try {
|
||||||
SecretKey masterKey = protocol.perform();
|
SecretKey master = protocol.perform();
|
||||||
KeyAgreementResult result =
|
KeyAgreementResult result =
|
||||||
new KeyAgreementResult(masterKey, transport.getConnection(),
|
new KeyAgreementResult(master, transport.getConnection(),
|
||||||
transport.getTransportId(), alice);
|
transport.getTransportId(), alice);
|
||||||
LOG.info("Finished BQP protocol");
|
LOG.info("Finished BQP protocol");
|
||||||
// Broadcast result to caller
|
// Broadcast result to caller
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.briarproject.bramble.plugin;
|
package org.briarproject.bramble.plugin;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
@@ -80,10 +80,12 @@ class Poller implements EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof ContactAddedEvent) {
|
if (e instanceof ContactStatusChangedEvent) {
|
||||||
ContactAddedEvent c = (ContactAddedEvent) e;
|
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
|
||||||
// Connect to the newly activated contact
|
if (c.isActive()) {
|
||||||
connectToContact(c.getContactId());
|
// Connect to the newly activated contact
|
||||||
|
connectToContact(c.getContactId());
|
||||||
|
}
|
||||||
} else if (e instanceof ConnectionClosedEvent) {
|
} else if (e instanceof ConnectionClosedEvent) {
|
||||||
ConnectionClosedEvent c = (ConnectionClosedEvent) e;
|
ConnectionClosedEvent c = (ConnectionClosedEvent) e;
|
||||||
// Reschedule polling, the polling interval may have decreased
|
// Reschedule polling, the polling interval may have decreased
|
||||||
|
|||||||
@@ -17,24 +17,16 @@ public interface CircumventionProvider {
|
|||||||
String[] BLOCKED = {"CN", "IR", "EG", "BY", "TR", "SY", "VE"};
|
String[] BLOCKED = {"CN", "IR", "EG", "BY", "TR", "SY", "VE"};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Countries where obfs4 bridge connection are likely to work.
|
* Countries where vanilla bridge connection are likely to work.
|
||||||
* Should be a subset of {@link #BLOCKED}.
|
* Should be a subset of {@link #BLOCKED}.
|
||||||
*/
|
*/
|
||||||
String[] BRIDGES = { "CN", "IR", "EG", "BY", "TR", "SY", "VE" };
|
String[] BRIDGES = { "EG", "BY", "TR", "SY", "VE" };
|
||||||
|
|
||||||
/**
|
|
||||||
* Countries where obfs4 bridges won't work and meek is needed.
|
|
||||||
* Should be a subset of {@link #BRIDGES}.
|
|
||||||
*/
|
|
||||||
String[] NEEDS_MEEK = {"CN", "IR"};
|
|
||||||
|
|
||||||
boolean isTorProbablyBlocked(String countryCode);
|
boolean isTorProbablyBlocked(String countryCode);
|
||||||
|
|
||||||
boolean doBridgesWork(String countryCode);
|
boolean doBridgesWork(String countryCode);
|
||||||
|
|
||||||
boolean needsMeek(String countryCode);
|
|
||||||
|
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
List<String> getBridges(boolean meek);
|
List<String> getBridges();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ class CircumventionProviderImpl implements CircumventionProvider {
|
|||||||
new HashSet<>(asList(BLOCKED));
|
new HashSet<>(asList(BLOCKED));
|
||||||
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
|
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
|
||||||
new HashSet<>(asList(BRIDGES));
|
new HashSet<>(asList(BRIDGES));
|
||||||
private static final Set<String> BRIDGES_NEED_MEEK =
|
|
||||||
new HashSet<>(asList(NEEDS_MEEK));
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private volatile List<String> bridges = null;
|
private volatile List<String> bridges = null;
|
||||||
@@ -42,14 +40,9 @@ class CircumventionProviderImpl implements CircumventionProvider {
|
|||||||
return BRIDGES_WORK_IN_COUNTRIES.contains(countryCode);
|
return BRIDGES_WORK_IN_COUNTRIES.contains(countryCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean needsMeek(String countryCode) {
|
|
||||||
return BRIDGES_NEED_MEEK.contains(countryCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
public List<String> getBridges(boolean useMeek) {
|
public List<String> getBridges() {
|
||||||
List<String> bridges = this.bridges;
|
List<String> bridges = this.bridges;
|
||||||
if (bridges != null) return new ArrayList<>(bridges);
|
if (bridges != null) return new ArrayList<>(bridges);
|
||||||
|
|
||||||
@@ -60,8 +53,6 @@ class CircumventionProviderImpl implements CircumventionProvider {
|
|||||||
bridges = new ArrayList<>();
|
bridges = new ArrayList<>();
|
||||||
while (scanner.hasNextLine()) {
|
while (scanner.hasNextLine()) {
|
||||||
String line = scanner.nextLine();
|
String line = scanner.nextLine();
|
||||||
boolean isMeekBridge = line.startsWith("Bridge meek");
|
|
||||||
if (useMeek && !isMeekBridge || !useMeek && isMeekBridge) continue;
|
|
||||||
if (!line.startsWith("#")) bridges.add(line);
|
if (!line.startsWith("#")) bridges.add(line);
|
||||||
}
|
}
|
||||||
scanner.close();
|
scanner.close();
|
||||||
|
|||||||
@@ -470,19 +470,13 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (!enable) callback.transportDisabled();
|
if (!enable) callback.transportDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableBridges(boolean enable, boolean needsMeek)
|
private void enableBridges(boolean enable) throws IOException {
|
||||||
throws IOException {
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
Collection<String> conf = new ArrayList<>();
|
Collection<String> conf = new ArrayList<>();
|
||||||
conf.add("UseBridges 1");
|
conf.add("UseBridges 1");
|
||||||
if (needsMeek) {
|
conf.add("ClientTransportPlugin obfs4 exec " +
|
||||||
conf.add("ClientTransportPlugin meek_lite exec " +
|
obfs4File.getAbsolutePath());
|
||||||
obfs4File.getAbsolutePath());
|
conf.addAll(circumventionProvider.getBridges());
|
||||||
} else {
|
|
||||||
conf.add("ClientTransportPlugin obfs4 exec " +
|
|
||||||
obfs4File.getAbsolutePath());
|
|
||||||
}
|
|
||||||
conf.addAll(circumventionProvider.getBridges(needsMeek));
|
|
||||||
controlConnection.setConf(conf);
|
controlConnection.setConf(conf);
|
||||||
} else {
|
} else {
|
||||||
controlConnection.setConf("UseBridges", "0");
|
controlConnection.setConf("UseBridges", "0");
|
||||||
@@ -722,17 +716,12 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
enableNetwork(false);
|
enableNetwork(false);
|
||||||
} else if (network == PREF_TOR_NETWORK_WITH_BRIDGES ||
|
} else if (network == PREF_TOR_NETWORK_WITH_BRIDGES ||
|
||||||
(automatic && bridgesWork)) {
|
(automatic && bridgesWork)) {
|
||||||
if (circumventionProvider.needsMeek(country)) {
|
LOG.info("Enabling network, using bridges");
|
||||||
LOG.info("Enabling network, using meek bridges");
|
enableBridges(true);
|
||||||
enableBridges(true, true);
|
|
||||||
} else {
|
|
||||||
LOG.info("Enabling network, using obfs4 bridges");
|
|
||||||
enableBridges(true, false);
|
|
||||||
}
|
|
||||||
enableNetwork(true);
|
enableNetwork(true);
|
||||||
} else {
|
} else {
|
||||||
LOG.info("Enabling network, not using bridges");
|
LOG.info("Enabling network, not using bridges");
|
||||||
enableBridges(false, false);
|
enableBridges(false);
|
||||||
enableNetwork(true);
|
enableNetwork(true);
|
||||||
}
|
}
|
||||||
if (online && wifi && charging) {
|
if (online && wifi && charging) {
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Metadata;
|
import org.briarproject.bramble.api.db.Metadata;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.identity.AuthorId;
|
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
@@ -46,7 +44,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
|
|
||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
private final ClientHelper clientHelper;
|
private final ClientHelper clientHelper;
|
||||||
private final IdentityManager identityManager;
|
|
||||||
private final ClientVersioningManager clientVersioningManager;
|
private final ClientVersioningManager clientVersioningManager;
|
||||||
private final MetadataParser metadataParser;
|
private final MetadataParser metadataParser;
|
||||||
private final ContactGroupFactory contactGroupFactory;
|
private final ContactGroupFactory contactGroupFactory;
|
||||||
@@ -56,13 +53,11 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
@Inject
|
@Inject
|
||||||
TransportPropertyManagerImpl(DatabaseComponent db,
|
TransportPropertyManagerImpl(DatabaseComponent db,
|
||||||
ClientHelper clientHelper,
|
ClientHelper clientHelper,
|
||||||
IdentityManager identityManager,
|
|
||||||
ClientVersioningManager clientVersioningManager,
|
ClientVersioningManager clientVersioningManager,
|
||||||
MetadataParser metadataParser,
|
MetadataParser metadataParser,
|
||||||
ContactGroupFactory contactGroupFactory, Clock clock) {
|
ContactGroupFactory contactGroupFactory, Clock clock) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.clientHelper = clientHelper;
|
this.clientHelper = clientHelper;
|
||||||
this.identityManager = identityManager;
|
|
||||||
this.clientVersioningManager = clientVersioningManager;
|
this.clientVersioningManager = clientVersioningManager;
|
||||||
this.metadataParser = metadataParser;
|
this.metadataParser = metadataParser;
|
||||||
this.contactGroupFactory = contactGroupFactory;
|
this.contactGroupFactory = contactGroupFactory;
|
||||||
@@ -82,7 +77,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
@Override
|
@Override
|
||||||
public void addingContact(Transaction txn, Contact c) throws DbException {
|
public void addingContact(Transaction txn, Contact c) throws DbException {
|
||||||
// Create a group to share with the contact
|
// Create a group to share with the contact
|
||||||
Group g = getContactGroup(c, getLocalAuthorId(txn));
|
Group g = getContactGroup(c);
|
||||||
db.addGroup(txn, g);
|
db.addGroup(txn, g);
|
||||||
// Apply the client's visibility to the contact group
|
// Apply the client's visibility to the contact group
|
||||||
Visibility client = clientVersioningManager.getClientVisibility(txn,
|
Visibility client = clientVersioningManager.getClientVisibility(txn,
|
||||||
@@ -98,14 +93,14 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removingContact(Transaction txn, Contact c) throws DbException {
|
public void removingContact(Transaction txn, Contact c) throws DbException {
|
||||||
db.removeGroup(txn, getContactGroup(c, getLocalAuthorId(txn)));
|
db.removeGroup(txn, getContactGroup(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClientVisibilityChanging(Transaction txn, Contact c,
|
public void onClientVisibilityChanging(Transaction txn, Contact c,
|
||||||
Visibility v) throws DbException {
|
Visibility v) throws DbException {
|
||||||
// Apply the client's visibility to the contact group
|
// Apply the client's visibility to the contact group
|
||||||
Group g = getContactGroup(c, getLocalAuthorId(txn));
|
Group g = getContactGroup(c);
|
||||||
db.setGroupVisibility(txn, c.getId(), g.getId(), v);
|
db.setGroupVisibility(txn, c.getId(), g.getId(), v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +132,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
@Override
|
@Override
|
||||||
public void addRemoteProperties(Transaction txn, ContactId c,
|
public void addRemoteProperties(Transaction txn, ContactId c,
|
||||||
Map<TransportId, TransportProperties> props) throws DbException {
|
Map<TransportId, TransportProperties> props) throws DbException {
|
||||||
Group g = getContactGroup(db.getContact(txn, c), getLocalAuthorId(txn));
|
Group g = getContactGroup(db.getContact(txn, c));
|
||||||
for (Entry<TransportId, TransportProperties> e : props.entrySet()) {
|
for (Entry<TransportId, TransportProperties> e : props.entrySet()) {
|
||||||
storeMessage(txn, g.getId(), e.getKey(), e.getValue(), 0,
|
storeMessage(txn, g.getId(), e.getKey(), e.getValue(), 0,
|
||||||
false, false);
|
false, false);
|
||||||
@@ -196,16 +191,17 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
TransportId t) throws DbException {
|
TransportId t) throws DbException {
|
||||||
return db.transactionWithResult(true, txn -> {
|
return db.transactionWithResult(true, txn -> {
|
||||||
Map<ContactId, TransportProperties> remote = new HashMap<>();
|
Map<ContactId, TransportProperties> remote = new HashMap<>();
|
||||||
AuthorId local = getLocalAuthorId(txn);
|
|
||||||
for (Contact c : db.getContacts(txn))
|
for (Contact c : db.getContacts(txn))
|
||||||
remote.put(c.getId(), getRemoteProperties(txn, c, local, t));
|
remote.put(c.getId(), getRemoteProperties(txn, c, t));
|
||||||
return remote;
|
return remote;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private TransportProperties getRemoteProperties(Transaction txn, Contact c,
|
private TransportProperties getRemoteProperties(Transaction txn, Contact c,
|
||||||
AuthorId local, TransportId t) throws DbException {
|
TransportId t) throws DbException {
|
||||||
Group g = getContactGroup(c, local);
|
// Don't return properties for inactive contacts
|
||||||
|
if (!c.isActive()) return new TransportProperties();
|
||||||
|
Group g = getContactGroup(c);
|
||||||
try {
|
try {
|
||||||
// Find the latest remote update
|
// Find the latest remote update
|
||||||
LatestUpdate latest = findLatest(txn, g.getId(), t, false);
|
LatestUpdate latest = findLatest(txn, g.getId(), t, false);
|
||||||
@@ -222,11 +218,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
@Override
|
@Override
|
||||||
public TransportProperties getRemoteProperties(ContactId c, TransportId t)
|
public TransportProperties getRemoteProperties(ContactId c, TransportId t)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
return db.transactionWithResult(true, txn -> {
|
return db.transactionWithResult(true, txn ->
|
||||||
Contact contact = db.getContact(txn ,c);
|
getRemoteProperties(txn, db.getContact(txn, c), t));
|
||||||
AuthorId local = getLocalAuthorId(txn);
|
|
||||||
return getRemoteProperties(txn, contact, local, t);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -259,9 +252,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
if (latest != null)
|
if (latest != null)
|
||||||
db.removeMessage(txn, latest.messageId);
|
db.removeMessage(txn, latest.messageId);
|
||||||
// Store the merged properties in each contact's group
|
// Store the merged properties in each contact's group
|
||||||
AuthorId localAuthorId = getLocalAuthorId(txn);
|
|
||||||
for (Contact c : db.getContacts(txn)) {
|
for (Contact c : db.getContacts(txn)) {
|
||||||
Group g = getContactGroup(c, localAuthorId);
|
Group g = getContactGroup(c);
|
||||||
latest = findLatest(txn, g.getId(), t, true);
|
latest = findLatest(txn, g.getId(), t, true);
|
||||||
version = latest == null ? 1 : latest.version + 1;
|
version = latest == null ? 1 : latest.version + 1;
|
||||||
storeMessage(txn, g.getId(), t, merged, version,
|
storeMessage(txn, g.getId(), t, merged, version,
|
||||||
@@ -277,13 +269,9 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuthorId getLocalAuthorId(Transaction txn) throws DbException {
|
private Group getContactGroup(Contact c) {
|
||||||
return identityManager.getLocalAuthor(txn).getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Group getContactGroup(Contact c, AuthorId local) {
|
|
||||||
return contactGroupFactory.createContactGroup(CLIENT_ID,
|
return contactGroupFactory.createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, c, local);
|
MAJOR_VERSION, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void storeMessage(Transaction txn, GroupId g, TransportId t,
|
private void storeMessage(Transaction txn, GroupId g, TransportId t,
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package org.briarproject.bramble.transport;
|
package org.briarproject.bramble.transport;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||||
|
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
@@ -17,8 +19,8 @@ import org.briarproject.bramble.api.plugin.TransportId;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.transport.KeyManager;
|
import org.briarproject.bramble.api.transport.KeyManager;
|
||||||
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
import org.briarproject.bramble.api.transport.StreamContext;
|
import org.briarproject.bramble.api.transport.StreamContext;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeySetId;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -44,6 +46,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
private final Executor dbExecutor;
|
private final Executor dbExecutor;
|
||||||
private final PluginConfig pluginConfig;
|
private final PluginConfig pluginConfig;
|
||||||
private final TransportKeyManagerFactory transportKeyManagerFactory;
|
private final TransportKeyManagerFactory transportKeyManagerFactory;
|
||||||
|
private final Map<ContactId, Boolean> activeContacts;
|
||||||
private final ConcurrentHashMap<TransportId, TransportKeyManager> managers;
|
private final ConcurrentHashMap<TransportId, TransportKeyManager> managers;
|
||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
@@ -55,6 +58,8 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
this.dbExecutor = dbExecutor;
|
this.dbExecutor = dbExecutor;
|
||||||
this.pluginConfig = pluginConfig;
|
this.pluginConfig = pluginConfig;
|
||||||
this.transportKeyManagerFactory = transportKeyManagerFactory;
|
this.transportKeyManagerFactory = transportKeyManagerFactory;
|
||||||
|
// Use a ConcurrentHashMap as a thread-safe set
|
||||||
|
activeContacts = new ConcurrentHashMap<>();
|
||||||
managers = new ConcurrentHashMap<>();
|
managers = new ConcurrentHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +73,8 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
transports.put(f.getId(), f.getMaxLatency());
|
transports.put(f.getId(), f.getMaxLatency());
|
||||||
try {
|
try {
|
||||||
db.transaction(false, txn -> {
|
db.transaction(false, txn -> {
|
||||||
|
for (Contact c : db.getContacts(txn))
|
||||||
|
if (c.isActive()) activeContacts.put(c.getId(), true);
|
||||||
for (Entry<TransportId, Integer> e : transports.entrySet())
|
for (Entry<TransportId, Integer> e : transports.entrySet())
|
||||||
db.addTransport(txn, e.getKey(), e.getValue());
|
db.addTransport(txn, e.getKey(), e.getValue());
|
||||||
for (Entry<TransportId, Integer> e : transports.entrySet()) {
|
for (Entry<TransportId, Integer> e : transports.entrySet()) {
|
||||||
@@ -88,22 +95,22 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<TransportId, TransportKeySetId> addContact(Transaction txn,
|
public Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
|
||||||
ContactId c, SecretKey rootKey, long timestamp, boolean alice,
|
SecretKey master, long timestamp, boolean alice, boolean active)
|
||||||
boolean active) throws DbException {
|
throws DbException {
|
||||||
Map<TransportId, TransportKeySetId> ids = new HashMap<>();
|
Map<TransportId, KeySetId> ids = new HashMap<>();
|
||||||
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
|
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
|
||||||
TransportId t = e.getKey();
|
TransportId t = e.getKey();
|
||||||
TransportKeyManager m = e.getValue();
|
TransportKeyManager m = e.getValue();
|
||||||
ids.put(t, m.addContact(txn, c, rootKey, timestamp, alice, active));
|
ids.put(t, m.addContact(txn, c, master, timestamp, alice, active));
|
||||||
}
|
}
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activateKeys(Transaction txn, Map<TransportId,
|
public void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
||||||
TransportKeySetId> keys) throws DbException {
|
throws DbException {
|
||||||
for (Entry<TransportId, TransportKeySetId> e : keys.entrySet()) {
|
for (Entry<TransportId, KeySetId> e : keys.entrySet()) {
|
||||||
TransportId t = e.getKey();
|
TransportId t = e.getKey();
|
||||||
TransportKeyManager m = managers.get(t);
|
TransportKeyManager m = managers.get(t);
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
@@ -123,6 +130,8 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
@Override
|
@Override
|
||||||
public StreamContext getStreamContext(ContactId c, TransportId t)
|
public StreamContext getStreamContext(ContactId c, TransportId t)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
|
// Don't allow outgoing streams to inactive contacts
|
||||||
|
if (!activeContacts.containsKey(c)) return null;
|
||||||
TransportKeyManager m = managers.get(t);
|
TransportKeyManager m = managers.get(t);
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
|
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
|
||||||
@@ -148,10 +157,15 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof ContactRemovedEvent) {
|
if (e instanceof ContactRemovedEvent) {
|
||||||
removeContact(((ContactRemovedEvent) e).getContactId());
|
removeContact(((ContactRemovedEvent) e).getContactId());
|
||||||
|
} else if (e instanceof ContactStatusChangedEvent) {
|
||||||
|
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
|
||||||
|
if (c.isActive()) activeContacts.put(c.getContactId(), true);
|
||||||
|
else activeContacts.remove(c.getContactId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeContact(ContactId c) {
|
private void removeContact(ContactId c) {
|
||||||
|
activeContacts.remove(c);
|
||||||
dbExecutor.execute(() -> {
|
dbExecutor.execute(() -> {
|
||||||
for (TransportKeyManager m : managers.values()) m.removeContact(c);
|
for (TransportKeyManager m : managers.values()) m.removeContact(c);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,18 +11,18 @@ import javax.annotation.concurrent.NotThreadSafe;
|
|||||||
class MutableIncomingKeys {
|
class MutableIncomingKeys {
|
||||||
|
|
||||||
private final SecretKey tagKey, headerKey;
|
private final SecretKey tagKey, headerKey;
|
||||||
private final long timePeriod;
|
private final long rotationPeriod;
|
||||||
private final ReorderingWindow window;
|
private final ReorderingWindow window;
|
||||||
|
|
||||||
MutableIncomingKeys(IncomingKeys in) {
|
MutableIncomingKeys(IncomingKeys in) {
|
||||||
tagKey = in.getTagKey();
|
tagKey = in.getTagKey();
|
||||||
headerKey = in.getHeaderKey();
|
headerKey = in.getHeaderKey();
|
||||||
timePeriod = in.getTimePeriod();
|
rotationPeriod = in.getRotationPeriod();
|
||||||
window = new ReorderingWindow(in.getWindowBase(), in.getWindowBitmap());
|
window = new ReorderingWindow(in.getWindowBase(), in.getWindowBitmap());
|
||||||
}
|
}
|
||||||
|
|
||||||
IncomingKeys snapshot() {
|
IncomingKeys snapshot() {
|
||||||
return new IncomingKeys(tagKey, headerKey, timePeriod,
|
return new IncomingKeys(tagKey, headerKey, rotationPeriod,
|
||||||
window.getBase(), window.getBitmap());
|
window.getBase(), window.getBitmap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,8 +34,8 @@ class MutableIncomingKeys {
|
|||||||
return headerKey;
|
return headerKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
long getTimePeriod() {
|
long getRotationPeriod() {
|
||||||
return timePeriod;
|
return rotationPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReorderingWindow getWindow() {
|
ReorderingWindow getWindow() {
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
package org.briarproject.bramble.transport;
|
package org.briarproject.bramble.transport;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeySetId;
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
|
|
||||||
class MutableKeySet {
|
class MutableKeySet {
|
||||||
|
|
||||||
private final TransportKeySetId keySetId;
|
private final KeySetId keySetId;
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final MutableTransportKeys transportKeys;
|
private final MutableTransportKeys transportKeys;
|
||||||
|
|
||||||
MutableKeySet(TransportKeySetId keySetId, ContactId contactId,
|
MutableKeySet(KeySetId keySetId, ContactId contactId,
|
||||||
MutableTransportKeys transportKeys) {
|
MutableTransportKeys transportKeys) {
|
||||||
this.keySetId = keySetId;
|
this.keySetId = keySetId;
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
this.transportKeys = transportKeys;
|
this.transportKeys = transportKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransportKeySetId getKeySetId() {
|
KeySetId getKeySetId() {
|
||||||
return keySetId;
|
return keySetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,20 +11,20 @@ import javax.annotation.concurrent.NotThreadSafe;
|
|||||||
class MutableOutgoingKeys {
|
class MutableOutgoingKeys {
|
||||||
|
|
||||||
private final SecretKey tagKey, headerKey;
|
private final SecretKey tagKey, headerKey;
|
||||||
private final long timePeriod;
|
private final long rotationPeriod;
|
||||||
private long streamCounter;
|
private long streamCounter;
|
||||||
private boolean active;
|
private boolean active;
|
||||||
|
|
||||||
MutableOutgoingKeys(OutgoingKeys out) {
|
MutableOutgoingKeys(OutgoingKeys out) {
|
||||||
tagKey = out.getTagKey();
|
tagKey = out.getTagKey();
|
||||||
headerKey = out.getHeaderKey();
|
headerKey = out.getHeaderKey();
|
||||||
timePeriod = out.getTimePeriod();
|
rotationPeriod = out.getRotationPeriod();
|
||||||
streamCounter = out.getStreamCounter();
|
streamCounter = out.getStreamCounter();
|
||||||
active = out.isActive();
|
active = out.isActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
OutgoingKeys snapshot() {
|
OutgoingKeys snapshot() {
|
||||||
return new OutgoingKeys(tagKey, headerKey, timePeriod,
|
return new OutgoingKeys(tagKey, headerKey, rotationPeriod,
|
||||||
streamCounter, active);
|
streamCounter, active);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,8 +36,8 @@ class MutableOutgoingKeys {
|
|||||||
return headerKey;
|
return headerKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
long getTimePeriod() {
|
long getRotationPeriod() {
|
||||||
return timePeriod;
|
return rotationPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
long getStreamCounter() {
|
long getStreamCounter() {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import org.briarproject.bramble.api.crypto.SecretKey;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
import org.briarproject.bramble.api.transport.StreamContext;
|
import org.briarproject.bramble.api.transport.StreamContext;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeySetId;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -15,11 +15,10 @@ interface TransportKeyManager {
|
|||||||
|
|
||||||
void start(Transaction txn) throws DbException;
|
void start(Transaction txn) throws DbException;
|
||||||
|
|
||||||
TransportKeySetId addContact(Transaction txn, ContactId c,
|
KeySetId addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
SecretKey rootKey, long timestamp, boolean alice, boolean active)
|
long timestamp, boolean alice, boolean active) throws DbException;
|
||||||
throws DbException;
|
|
||||||
|
|
||||||
void activateKeys(Transaction txn, TransportKeySetId k) throws DbException;
|
void activateKeys(Transaction txn, KeySetId k) throws DbException;
|
||||||
|
|
||||||
void removeContact(ContactId c);
|
void removeContact(ContactId c);
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
|
import org.briarproject.bramble.api.transport.KeySet;
|
||||||
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
import org.briarproject.bramble.api.transport.StreamContext;
|
import org.briarproject.bramble.api.transport.StreamContext;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeySet;
|
|
||||||
import org.briarproject.bramble.api.transport.TransportKeySetId;
|
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
import org.briarproject.bramble.transport.ReorderingWindow.Change;
|
import org.briarproject.bramble.transport.ReorderingWindow.Change;
|
||||||
|
|
||||||
@@ -51,12 +51,12 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final TransportId transportId;
|
private final TransportId transportId;
|
||||||
private final long timePeriodLength;
|
private final long rotationPeriodLength;
|
||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
private final ReentrantLock lock = new ReentrantLock();
|
private final ReentrantLock lock = new ReentrantLock();
|
||||||
|
|
||||||
// The following are locking: lock
|
// The following are locking: lock
|
||||||
private final Map<TransportKeySetId, MutableKeySet> keys = new HashMap<>();
|
private final Map<KeySetId, MutableKeySet> keys = new HashMap<>();
|
||||||
private final Map<Bytes, TagContext> inContexts = new HashMap<>();
|
private final Map<Bytes, TagContext> inContexts = new HashMap<>();
|
||||||
private final Map<ContactId, MutableKeySet> outContexts = new HashMap<>();
|
private final Map<ContactId, MutableKeySet> outContexts = new HashMap<>();
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.transportId = transportId;
|
this.transportId = transportId;
|
||||||
timePeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE;
|
rotationPeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -80,9 +80,8 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
// Load the transport keys from the DB
|
// Load the transport keys from the DB
|
||||||
Collection<TransportKeySet> loaded =
|
Collection<KeySet> loaded = db.getTransportKeys(txn, transportId);
|
||||||
db.getTransportKeys(txn, transportId);
|
// Rotate the keys to the current rotation period
|
||||||
// Rotate the keys to the current time period
|
|
||||||
RotationResult rotationResult = rotateKeys(loaded, now);
|
RotationResult rotationResult = rotateKeys(loaded, now);
|
||||||
// Initialise mutable state for all contacts
|
// Initialise mutable state for all contacts
|
||||||
addKeys(rotationResult.current);
|
addKeys(rotationResult.current);
|
||||||
@@ -96,17 +95,15 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
scheduleKeyRotation(now);
|
scheduleKeyRotation(now);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RotationResult rotateKeys(Collection<TransportKeySet> keys,
|
private RotationResult rotateKeys(Collection<KeySet> keys, long now) {
|
||||||
long now) {
|
|
||||||
RotationResult rotationResult = new RotationResult();
|
RotationResult rotationResult = new RotationResult();
|
||||||
long timePeriod = now / timePeriodLength;
|
long rotationPeriod = now / rotationPeriodLength;
|
||||||
for (TransportKeySet ks : keys) {
|
for (KeySet ks : keys) {
|
||||||
TransportKeys k = ks.getKeys();
|
TransportKeys k = ks.getTransportKeys();
|
||||||
TransportKeys k1 = transportCrypto.rotateTransportKeys(k,
|
TransportKeys k1 =
|
||||||
timePeriod);
|
transportCrypto.rotateTransportKeys(k, rotationPeriod);
|
||||||
TransportKeySet ks1 = new TransportKeySet(ks.getKeySetId(),
|
KeySet ks1 = new KeySet(ks.getKeySetId(), ks.getContactId(), k1);
|
||||||
ks.getContactId(), k1);
|
if (k1.getRotationPeriod() > k.getRotationPeriod())
|
||||||
if (k1.getTimePeriod() > k.getTimePeriod())
|
|
||||||
rotationResult.rotated.add(ks1);
|
rotationResult.rotated.add(ks1);
|
||||||
rotationResult.current.add(ks1);
|
rotationResult.current.add(ks1);
|
||||||
}
|
}
|
||||||
@@ -114,15 +111,15 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Locking: lock
|
// Locking: lock
|
||||||
private void addKeys(Collection<TransportKeySet> keys) {
|
private void addKeys(Collection<KeySet> keys) {
|
||||||
for (TransportKeySet ks : keys) {
|
for (KeySet ks : keys) {
|
||||||
addKeys(ks.getKeySetId(), ks.getContactId(),
|
addKeys(ks.getKeySetId(), ks.getContactId(),
|
||||||
new MutableTransportKeys(ks.getKeys()));
|
new MutableTransportKeys(ks.getTransportKeys()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: lock
|
// Locking: lock
|
||||||
private void addKeys(TransportKeySetId keySetId, ContactId contactId,
|
private void addKeys(KeySetId keySetId, ContactId contactId,
|
||||||
MutableTransportKeys m) {
|
MutableTransportKeys m) {
|
||||||
MutableKeySet ks = new MutableKeySet(keySetId, contactId, m);
|
MutableKeySet ks = new MutableKeySet(keySetId, contactId, m);
|
||||||
keys.put(keySetId, ks);
|
keys.put(keySetId, ks);
|
||||||
@@ -133,7 +130,7 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Locking: lock
|
// Locking: lock
|
||||||
private void encodeTags(TransportKeySetId keySetId, ContactId contactId,
|
private void encodeTags(KeySetId keySetId, ContactId contactId,
|
||||||
MutableIncomingKeys inKeys) {
|
MutableIncomingKeys inKeys) {
|
||||||
for (long streamNumber : inKeys.getWindow().getUnseen()) {
|
for (long streamNumber : inKeys.getWindow().getUnseen()) {
|
||||||
TagContext tagCtx =
|
TagContext tagCtx =
|
||||||
@@ -158,7 +155,7 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleKeyRotation(long now) {
|
private void scheduleKeyRotation(long now) {
|
||||||
long delay = timePeriodLength - now % timePeriodLength;
|
long delay = rotationPeriodLength - now % rotationPeriodLength;
|
||||||
scheduler.schedule((Runnable) this::rotateKeys, delay, MILLISECONDS);
|
scheduler.schedule((Runnable) this::rotateKeys, delay, MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,21 +170,20 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransportKeySetId addContact(Transaction txn, ContactId c,
|
public KeySetId addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
SecretKey rootKey, long timestamp, boolean alice, boolean active)
|
long timestamp, boolean alice, boolean active) throws DbException {
|
||||||
throws DbException {
|
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
// Work out what time period the timestamp belongs to
|
// Work out what rotation period the timestamp belongs to
|
||||||
long timePeriod = timestamp / timePeriodLength;
|
long rotationPeriod = timestamp / rotationPeriodLength;
|
||||||
// Derive the transport keys
|
// Derive the transport keys
|
||||||
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
||||||
rootKey, timePeriod, alice, active);
|
master, rotationPeriod, alice, active);
|
||||||
// Rotate the keys to the current time period if necessary
|
// Rotate the keys to the current rotation period if necessary
|
||||||
timePeriod = clock.currentTimeMillis() / timePeriodLength;
|
rotationPeriod = clock.currentTimeMillis() / rotationPeriodLength;
|
||||||
k = transportCrypto.rotateTransportKeys(k, timePeriod);
|
k = transportCrypto.rotateTransportKeys(k, rotationPeriod);
|
||||||
// Write the keys back to the DB
|
// Write the keys back to the DB
|
||||||
TransportKeySetId keySetId = db.addTransportKeys(txn, c, k);
|
KeySetId keySetId = db.addTransportKeys(txn, c, k);
|
||||||
// Initialise mutable state for the contact
|
// Initialise mutable state for the contact
|
||||||
addKeys(keySetId, c, new MutableTransportKeys(k));
|
addKeys(keySetId, c, new MutableTransportKeys(k));
|
||||||
return keySetId;
|
return keySetId;
|
||||||
@@ -197,8 +193,7 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activateKeys(Transaction txn, TransportKeySetId k)
|
public void activateKeys(Transaction txn, KeySetId k) throws DbException {
|
||||||
throws DbException {
|
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
MutableKeySet ks = keys.get(k);
|
MutableKeySet ks = keys.get(k);
|
||||||
@@ -305,7 +300,7 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
// Write the window back to the DB
|
// Write the window back to the DB
|
||||||
db.setReorderingWindow(txn, tagCtx.keySetId, transportId,
|
db.setReorderingWindow(txn, tagCtx.keySetId, transportId,
|
||||||
inKeys.getTimePeriod(), window.getBase(),
|
inKeys.getRotationPeriod(), window.getBase(),
|
||||||
window.getBitmap());
|
window.getBitmap());
|
||||||
// If the outgoing keys are inactive, activate them
|
// If the outgoing keys are inactive, activate them
|
||||||
MutableKeySet ks = keys.get(tagCtx.keySetId);
|
MutableKeySet ks = keys.get(tagCtx.keySetId);
|
||||||
@@ -327,11 +322,11 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
// Rotate the keys to the current time period
|
// Rotate the keys to the current rotation period
|
||||||
Collection<TransportKeySet> snapshot = new ArrayList<>(keys.size());
|
Collection<KeySet> snapshot = new ArrayList<>(keys.size());
|
||||||
for (MutableKeySet ks : keys.values()) {
|
for (MutableKeySet ks : keys.values()) {
|
||||||
snapshot.add(new TransportKeySet(ks.getKeySetId(),
|
snapshot.add(new KeySet(ks.getKeySetId(), ks.getContactId(),
|
||||||
ks.getContactId(), ks.getTransportKeys().snapshot()));
|
ks.getTransportKeys().snapshot()));
|
||||||
}
|
}
|
||||||
RotationResult rotationResult = rotateKeys(snapshot, now);
|
RotationResult rotationResult = rotateKeys(snapshot, now);
|
||||||
// Rebuild the mutable state for all contacts
|
// Rebuild the mutable state for all contacts
|
||||||
@@ -351,12 +346,12 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
|
|
||||||
private static class TagContext {
|
private static class TagContext {
|
||||||
|
|
||||||
private final TransportKeySetId keySetId;
|
private final KeySetId keySetId;
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final MutableIncomingKeys inKeys;
|
private final MutableIncomingKeys inKeys;
|
||||||
private final long streamNumber;
|
private final long streamNumber;
|
||||||
|
|
||||||
private TagContext(TransportKeySetId keySetId, ContactId contactId,
|
private TagContext(KeySetId keySetId, ContactId contactId,
|
||||||
MutableIncomingKeys inKeys, long streamNumber) {
|
MutableIncomingKeys inKeys, long streamNumber) {
|
||||||
this.keySetId = keySetId;
|
this.keySetId = keySetId;
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
@@ -367,7 +362,7 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
|
|
||||||
private static class RotationResult {
|
private static class RotationResult {
|
||||||
|
|
||||||
private final Collection<TransportKeySet> current = new ArrayList<>();
|
private final Collection<KeySet> current = new ArrayList<>();
|
||||||
private final Collection<TransportKeySet> rotated = new ArrayList<>();
|
private final Collection<KeySet> rotated = new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Metadata;
|
import org.briarproject.bramble.api.db.Metadata;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.identity.AuthorId;
|
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.Service;
|
import org.briarproject.bramble.api.lifecycle.Service;
|
||||||
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
@@ -60,7 +58,6 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
|
|||||||
|
|
||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
private final ClientHelper clientHelper;
|
private final ClientHelper clientHelper;
|
||||||
private final IdentityManager identityManager;
|
|
||||||
private final ContactGroupFactory contactGroupFactory;
|
private final ContactGroupFactory contactGroupFactory;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final Group localGroup;
|
private final Group localGroup;
|
||||||
@@ -71,11 +68,9 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ClientVersioningManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
|
ClientVersioningManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
|
||||||
IdentityManager identityManager,
|
|
||||||
ContactGroupFactory contactGroupFactory, Clock clock) {
|
ContactGroupFactory contactGroupFactory, Clock clock) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.clientHelper = clientHelper;
|
this.clientHelper = clientHelper;
|
||||||
this.identityManager = identityManager;
|
|
||||||
this.contactGroupFactory = contactGroupFactory;
|
this.contactGroupFactory = contactGroupFactory;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID,
|
localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID,
|
||||||
@@ -159,7 +154,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
|
|||||||
@Override
|
@Override
|
||||||
public void addingContact(Transaction txn, Contact c) throws DbException {
|
public void addingContact(Transaction txn, Contact c) throws DbException {
|
||||||
// Create a group and share it with the contact
|
// Create a group and share it with the contact
|
||||||
Group g = getContactGroup(c, getLocalAuthorId(txn));
|
Group g = getContactGroup(c);
|
||||||
db.addGroup(txn, g);
|
db.addGroup(txn, g);
|
||||||
db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED);
|
db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED);
|
||||||
// Attach the contact ID to the group
|
// Attach the contact ID to the group
|
||||||
@@ -178,7 +173,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removingContact(Transaction txn, Contact c) throws DbException {
|
public void removingContact(Transaction txn, Contact c) throws DbException {
|
||||||
db.removeGroup(txn, getContactGroup(c, getLocalAuthorId(txn)));
|
db.removeGroup(txn, getContactGroup(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -313,7 +308,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
|
|||||||
List<ClientVersion> versions) throws DbException {
|
List<ClientVersion> versions) throws DbException {
|
||||||
try {
|
try {
|
||||||
// Find the latest local and remote updates
|
// Find the latest local and remote updates
|
||||||
Group g = getContactGroup(c, getLocalAuthorId(txn));
|
Group g = getContactGroup(c);
|
||||||
LatestUpdates latest = findLatestUpdates(txn, g.getId());
|
LatestUpdates latest = findLatestUpdates(txn, g.getId());
|
||||||
// Load and parse the latest local update
|
// Load and parse the latest local update
|
||||||
if (latest.local == null) throw new DbException();
|
if (latest.local == null) throw new DbException();
|
||||||
@@ -349,20 +344,16 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuthorId getLocalAuthorId(Transaction txn) throws DbException {
|
private Group getContactGroup(Contact c) {
|
||||||
return identityManager.getLocalAuthor(txn).getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Group getContactGroup(Contact c, AuthorId local) {
|
|
||||||
return contactGroupFactory.createContactGroup(CLIENT_ID,
|
return contactGroupFactory.createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, c, local);
|
MAJOR_VERSION, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private LatestUpdates findLatestUpdates(Transaction txn, ContactId c)
|
private LatestUpdates findLatestUpdates(Transaction txn, ContactId c)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
Contact contact = db.getContact(txn, c);
|
Contact contact = db.getContact(txn, c);
|
||||||
Group g = getContactGroup(contact, getLocalAuthorId(txn));
|
Group g = getContactGroup(contact);
|
||||||
// Contact may be in the process of being added or removed, so
|
// Contact may be in the process of being added or removed, so
|
||||||
// contact group may not exist
|
// contact group may not exist
|
||||||
if (!db.containsGroup(txn, g.getId())) return null;
|
if (!db.containsGroup(txn, g.getId())) return null;
|
||||||
|
|||||||
@@ -2,4 +2,3 @@ Bridge obfs4 78.46.188.239:37356 5A2D2F4158D0453E00C7C176978D3F41D69C45DB cert=3
|
|||||||
Bridge obfs4 52.15.78.72:9443 02069A3C5362476936B62BA6F5ACC41ABD573A9B cert=ijYG/OKc7kqu2YzKNFfeXN7/BG2BOgfEP2KyYEiGDQthnHbsOiTWHeIG0WJVW+BckzDgKw iat-mode=0
|
Bridge obfs4 52.15.78.72:9443 02069A3C5362476936B62BA6F5ACC41ABD573A9B cert=ijYG/OKc7kqu2YzKNFfeXN7/BG2BOgfEP2KyYEiGDQthnHbsOiTWHeIG0WJVW+BckzDgKw iat-mode=0
|
||||||
Bridge obfs4 13.58.29.242:9443 0C58939A77DA6B6B29D4B5236A75865659607AE0 cert=OylWIEHb/ezpq1zWxW0sgKRn+9ARH2eOcQOZ8/Gew+4l+oKOhQ2jUX/Y+FSl61JorXZUWA iat-mode=0
|
Bridge obfs4 13.58.29.242:9443 0C58939A77DA6B6B29D4B5236A75865659607AE0 cert=OylWIEHb/ezpq1zWxW0sgKRn+9ARH2eOcQOZ8/Gew+4l+oKOhQ2jUX/Y+FSl61JorXZUWA iat-mode=0
|
||||||
Bridge obfs4 45.33.37.112:9443 60A609BB4ABE8D46E634AE81ED29ADAB7776B399 cert=t5v19WmNv5Sc2YPNr8RQids365W7MY8zJwQVkOxBjUMFomMWARDzsbYpcWLLcw0J9Gm+BQ iat-mode=0
|
Bridge obfs4 45.33.37.112:9443 60A609BB4ABE8D46E634AE81ED29ADAB7776B399 cert=t5v19WmNv5Sc2YPNr8RQids365W7MY8zJwQVkOxBjUMFomMWARDzsbYpcWLLcw0J9Gm+BQ iat-mode=0
|
||||||
Bridge meek_lite 0.0.2.0:2 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com
|
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package org.briarproject.bramble;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Vector;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.concurrent.Executors.newSingleThreadExecutor;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public class PriorityExecutorTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHighPriorityTasksAreDelegatedInOrderOfSubmission()
|
||||||
|
throws Exception {
|
||||||
|
Executor delegate = newSingleThreadExecutor();
|
||||||
|
PriorityExecutor priority = new PriorityExecutor(delegate);
|
||||||
|
Executor high = priority.getHighPriorityExecutor();
|
||||||
|
testTasksAreDelegatedInOrderOfSubmission(high);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLowPriorityTasksAreDelegatedInOrderOfSubmission()
|
||||||
|
throws Exception {
|
||||||
|
Executor delegate = newSingleThreadExecutor();
|
||||||
|
PriorityExecutor priority = new PriorityExecutor(delegate);
|
||||||
|
Executor low = priority.getLowPriorityExecutor();
|
||||||
|
testTasksAreDelegatedInOrderOfSubmission(low);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHighPriorityTasksAreRunFirst() throws Exception {
|
||||||
|
Executor delegate = newSingleThreadExecutor();
|
||||||
|
PriorityExecutor priority = new PriorityExecutor(delegate);
|
||||||
|
Executor high = priority.getHighPriorityExecutor();
|
||||||
|
Executor low = priority.getLowPriorityExecutor();
|
||||||
|
// Submit a task that will block, causing other tasks to be queued
|
||||||
|
CountDownLatch cork = new CountDownLatch(1);
|
||||||
|
low.execute(() -> {
|
||||||
|
try {
|
||||||
|
cork.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Submit alternating tasks to the high and low priority executors
|
||||||
|
List<Integer> results = new Vector<>();
|
||||||
|
CountDownLatch tasksFinished = new CountDownLatch(10);
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
int result = i;
|
||||||
|
Runnable task = () -> {
|
||||||
|
results.add(result);
|
||||||
|
tasksFinished.countDown();
|
||||||
|
};
|
||||||
|
if (i % 2 == 0) high.execute(task);
|
||||||
|
else low.execute(task);
|
||||||
|
}
|
||||||
|
// Release the cork and wait for all tasks to finish
|
||||||
|
cork.countDown();
|
||||||
|
tasksFinished.await();
|
||||||
|
// The high-priority tasks should have run before the low-priority tasks
|
||||||
|
assertEquals(asList(0, 2, 4, 6, 8, 1, 3, 5, 7, 9), results);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testTasksAreDelegatedInOrderOfSubmission(Executor e)
|
||||||
|
throws Exception {
|
||||||
|
List<Integer> results = new Vector<>();
|
||||||
|
CountDownLatch tasksFinished = new CountDownLatch(10);
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
int result = i;
|
||||||
|
e.execute(() -> {
|
||||||
|
results.add(result);
|
||||||
|
tasksFinished.countDown();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Wait for all the tasks to finish
|
||||||
|
tasksFinished.await();
|
||||||
|
// The tasks should have run in the order they were submitted
|
||||||
|
assertEquals(asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), results);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,20 +5,27 @@ import org.briarproject.bramble.api.contact.ContactId;
|
|||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
import org.briarproject.bramble.api.identity.AuthorInfo;
|
import org.briarproject.bramble.api.identity.AuthorInfo;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
import org.briarproject.bramble.api.transport.KeyManager;
|
import org.briarproject.bramble.api.transport.KeyManager;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.DbExpectations;
|
import org.briarproject.bramble.test.DbExpectations;
|
||||||
|
import org.jmock.Expectations;
|
||||||
import org.jmock.Mockery;
|
import org.jmock.Mockery;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
|
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
|
||||||
@@ -26,8 +33,8 @@ 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.UNVERIFIED;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
|
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContact;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -42,40 +49,42 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final IdentityManager identityManager =
|
private final IdentityManager identityManager =
|
||||||
context.mock(IdentityManager.class);
|
context.mock(IdentityManager.class);
|
||||||
private final ContactManager contactManager;
|
private final ContactManager contactManager;
|
||||||
private final Author author = getAuthor();
|
private final ContactId contactId = new ContactId(42);
|
||||||
|
private final Author remote = getAuthor();
|
||||||
|
private final AuthorId local = new AuthorId(getRandomId());
|
||||||
private final LocalAuthor localAuthor = getLocalAuthor();
|
private final LocalAuthor localAuthor = getLocalAuthor();
|
||||||
|
private final String alias = getRandomString(MAX_AUTHOR_NAME_LENGTH);
|
||||||
private final boolean verified = false, active = true;
|
private final boolean verified = false, active = true;
|
||||||
private final Contact contact = getContact(author, verified);
|
private final Contact contact =
|
||||||
private final ContactId contactId = contact.getId();
|
new Contact(contactId, remote, local, alias, verified, active);
|
||||||
|
|
||||||
public ContactManagerImplTest() {
|
public ContactManagerImplTest() {
|
||||||
contactManager =
|
contactManager = new ContactManagerImpl(db, keyManager, identityManager);
|
||||||
new ContactManagerImpl(db, keyManager, identityManager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddContact() throws Exception {
|
public void testAddContact() throws Exception {
|
||||||
SecretKey rootKey = getSecretKey();
|
SecretKey master = getSecretKey();
|
||||||
long timestamp = System.currentTimeMillis();
|
long timestamp = System.currentTimeMillis();
|
||||||
boolean alice = new Random().nextBoolean();
|
boolean alice = new Random().nextBoolean();
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(false), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(false), withDbCallable(txn));
|
||||||
oneOf(db).addContact(txn, author, verified);
|
oneOf(db).addContact(txn, remote, local, verified, active);
|
||||||
will(returnValue(contactId));
|
will(returnValue(contactId));
|
||||||
oneOf(keyManager).addContact(txn, contactId, rootKey, timestamp,
|
oneOf(keyManager).addContact(txn, contactId, master, timestamp,
|
||||||
alice, active);
|
alice, active);
|
||||||
oneOf(db).getContact(txn, contactId);
|
oneOf(db).getContact(txn, contactId);
|
||||||
will(returnValue(contact));
|
will(returnValue(contact));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertEquals(contactId, contactManager.addContact(author, rootKey,
|
assertEquals(contactId, contactManager.addContact(remote, local,
|
||||||
timestamp, alice, verified, active));
|
master, timestamp, alice, verified, active));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetContactByContactId() throws Exception {
|
public void testGetContact() throws Exception {
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
@@ -87,20 +96,49 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetContactByAuthorId() throws Exception {
|
public void testGetContactByAuthor() throws Exception {
|
||||||
|
Transaction txn = new Transaction(null, true);
|
||||||
|
Collection<Contact> contacts = Collections.singleton(contact);
|
||||||
|
context.checking(new DbExpectations() {{
|
||||||
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
|
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||||
|
will(returnValue(contacts));
|
||||||
|
}});
|
||||||
|
|
||||||
|
assertEquals(contact, contactManager.getContact(remote.getId(), local));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = NoSuchContactException.class)
|
||||||
|
public void testGetContactByUnknownAuthor() throws Exception {
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
oneOf(db).getContact(txn, author.getId());
|
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||||
will(returnValue(contact));
|
will(returnValue(emptyList()));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertEquals(contact, contactManager.getContact(author.getId()));
|
contactManager.getContact(remote.getId(), local);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = NoSuchContactException.class)
|
||||||
|
public void testGetContactByUnknownLocalAuthor() throws Exception {
|
||||||
|
Transaction txn = new Transaction(null, true);
|
||||||
|
Collection<Contact> contacts = Collections.singleton(contact);
|
||||||
|
context.checking(new DbExpectations() {{
|
||||||
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
|
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||||
|
will(returnValue(contacts));
|
||||||
|
}});
|
||||||
|
|
||||||
|
contactManager.getContact(remote.getId(), new AuthorId(getRandomId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetContacts() throws Exception {
|
public void testGetActiveContacts() throws Exception {
|
||||||
Collection<Contact> contacts = singletonList(contact);
|
Collection<Contact> activeContacts = Collections.singletonList(contact);
|
||||||
|
Collection<Contact> contacts = new ArrayList<>(activeContacts);
|
||||||
|
contacts.add(new Contact(new ContactId(3), remote, local, alias, true,
|
||||||
|
false));
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
@@ -108,7 +146,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(contacts));
|
will(returnValue(contacts));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertEquals(contacts, contactManager.getContacts());
|
assertEquals(activeContacts, contactManager.getActiveContacts());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -124,11 +162,19 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
contactManager.removeContact(contactId);
|
contactManager.removeContact(contactId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetContactActive() throws Exception {
|
||||||
|
Transaction txn = new Transaction(null, false);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(db).setContactActive(txn, contactId, active);
|
||||||
|
}});
|
||||||
|
|
||||||
|
contactManager.setContactActive(txn, contactId, active);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetContactAlias() throws Exception {
|
public void testSetContactAlias() throws Exception {
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
String alias = getRandomString(MAX_AUTHOR_NAME_LENGTH);
|
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||||
oneOf(db).setContactAlias(txn, contactId, alias);
|
oneOf(db).setContactAlias(txn, contactId, alias);
|
||||||
@@ -149,82 +195,85 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
oneOf(db).containsContact(txn, author.getId());
|
oneOf(db).containsContact(txn, remote.getId(), local);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertTrue(contactManager.contactExists(author.getId()));
|
assertTrue(contactManager.contactExists(remote.getId(), local));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetAuthorInfoOurselves() throws Exception {
|
public void testGetAuthorInfo() throws Exception {
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
|
Collection<Contact> contacts = singletonList(
|
||||||
|
new Contact(new ContactId(1), remote, localAuthor.getId(),
|
||||||
|
alias, false, true));
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
oneOf(identityManager).getLocalAuthor(txn);
|
oneOf(identityManager).getLocalAuthor(txn);
|
||||||
will(returnValue(localAuthor));
|
will(returnValue(localAuthor));
|
||||||
|
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||||
|
will(returnValue(contacts));
|
||||||
}});
|
}});
|
||||||
AuthorInfo authorInfo =
|
AuthorInfo authorInfo =
|
||||||
contactManager.getAuthorInfo(txn, localAuthor.getId());
|
contactManager.getAuthorInfo(txn, remote.getId());
|
||||||
|
assertEquals(UNVERIFIED, authorInfo.getStatus());
|
||||||
|
assertEquals(alias, contact.getAlias());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAuthorInfoTransaction() throws DbException {
|
||||||
|
Transaction txn = new Transaction(null, true);
|
||||||
|
|
||||||
|
// check unknown author
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(identityManager).getLocalAuthor(txn);
|
||||||
|
will(returnValue(localAuthor));
|
||||||
|
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||||
|
will(returnValue(emptyList()));
|
||||||
|
}});
|
||||||
|
AuthorInfo authorInfo =
|
||||||
|
contactManager.getAuthorInfo(txn, remote.getId());
|
||||||
|
assertEquals(UNKNOWN, authorInfo.getStatus());
|
||||||
|
assertNull(authorInfo.getAlias());
|
||||||
|
|
||||||
|
// check unverified contact
|
||||||
|
Collection<Contact> contacts = singletonList(
|
||||||
|
new Contact(new ContactId(1), remote, localAuthor.getId(),
|
||||||
|
alias, false, true));
|
||||||
|
checkAuthorInfoContext(txn, remote.getId(), contacts);
|
||||||
|
authorInfo = contactManager.getAuthorInfo(txn, remote.getId());
|
||||||
|
assertEquals(UNVERIFIED, authorInfo.getStatus());
|
||||||
|
assertEquals(alias, contact.getAlias());
|
||||||
|
|
||||||
|
// check verified contact
|
||||||
|
contacts = singletonList(new Contact(new ContactId(1), remote,
|
||||||
|
localAuthor.getId(), alias, true, true));
|
||||||
|
checkAuthorInfoContext(txn, remote.getId(), contacts);
|
||||||
|
authorInfo = contactManager.getAuthorInfo(txn, remote.getId());
|
||||||
|
assertEquals(VERIFIED, authorInfo.getStatus());
|
||||||
|
assertEquals(alias, contact.getAlias());
|
||||||
|
|
||||||
|
// check ourselves
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(identityManager).getLocalAuthor(txn);
|
||||||
|
will(returnValue(localAuthor));
|
||||||
|
never(db).getContactsByAuthorId(txn, remote.getId());
|
||||||
|
}});
|
||||||
|
authorInfo = contactManager.getAuthorInfo(txn, localAuthor.getId());
|
||||||
assertEquals(OURSELVES, authorInfo.getStatus());
|
assertEquals(OURSELVES, authorInfo.getStatus());
|
||||||
assertNull(authorInfo.getAlias());
|
assertNull(authorInfo.getAlias());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private void checkAuthorInfoContext(Transaction txn, AuthorId authorId,
|
||||||
public void testGetAuthorInfoVerified() throws Exception {
|
Collection<Contact> contacts) throws DbException {
|
||||||
Transaction txn = new Transaction(null, true);
|
context.checking(new Expectations() {{
|
||||||
Contact verified = getContact(author, true);
|
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
|
||||||
oneOf(identityManager).getLocalAuthor(txn);
|
oneOf(identityManager).getLocalAuthor(txn);
|
||||||
will(returnValue(localAuthor));
|
will(returnValue(localAuthor));
|
||||||
oneOf(db).containsContact(txn, author.getId());
|
oneOf(db).getContactsByAuthorId(txn, authorId);
|
||||||
will(returnValue(true));
|
will(returnValue(contacts));
|
||||||
oneOf(db).getContact(txn, author.getId());
|
|
||||||
will(returnValue(verified));
|
|
||||||
}});
|
}});
|
||||||
AuthorInfo authorInfo =
|
|
||||||
contactManager.getAuthorInfo(txn, author.getId());
|
|
||||||
assertEquals(VERIFIED, authorInfo.getStatus());
|
|
||||||
assertEquals(verified.getAlias(), authorInfo.getAlias());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetAuthorInfoUnverified() throws Exception {
|
|
||||||
Transaction txn = new Transaction(null, true);
|
|
||||||
Contact unverified = getContact(author, false);
|
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
|
||||||
oneOf(identityManager).getLocalAuthor(txn);
|
|
||||||
will(returnValue(localAuthor));
|
|
||||||
oneOf(db).containsContact(txn, author.getId());
|
|
||||||
will(returnValue(true));
|
|
||||||
oneOf(db).getContact(txn, author.getId());
|
|
||||||
will(returnValue(unverified));
|
|
||||||
}});
|
|
||||||
AuthorInfo authorInfo =
|
|
||||||
contactManager.getAuthorInfo(txn, author.getId());
|
|
||||||
assertEquals(UNVERIFIED, authorInfo.getStatus());
|
|
||||||
assertEquals(unverified.getAlias(), authorInfo.getAlias());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetAuthorInfoUnknown() throws Exception {
|
|
||||||
Transaction txn = new Transaction(null, true);
|
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
|
||||||
oneOf(identityManager).getLocalAuthor(txn);
|
|
||||||
will(returnValue(localAuthor));
|
|
||||||
oneOf(db).containsContact(txn, author.getId());
|
|
||||||
will(returnValue(false));
|
|
||||||
}});
|
|
||||||
AuthorInfo authorInfo =
|
|
||||||
contactManager.getAuthorInfo(txn, author.getId());
|
|
||||||
assertEquals(UNKNOWN, authorInfo.getStatus());
|
|
||||||
assertNull(authorInfo.getAlias());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,167 +0,0 @@
|
|||||||
package org.briarproject.bramble.crypto;
|
|
||||||
|
|
||||||
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.test.BrambleTestCase;
|
|
||||||
import org.briarproject.bramble.test.TestSecureRandomProvider;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import static org.briarproject.bramble.crypto.KeyDerivationTestUtils.assertAllDifferent;
|
|
||||||
import static org.briarproject.bramble.crypto.KeyDerivationTestUtils.assertMatches;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotEquals;
|
|
||||||
import static org.junit.Assert.assertSame;
|
|
||||||
|
|
||||||
public class HandshakeKeyDerivationTest extends BrambleTestCase {
|
|
||||||
|
|
||||||
private final CryptoComponent crypto =
|
|
||||||
new CryptoComponentImpl(new TestSecureRandomProvider(), null);
|
|
||||||
private final TransportCrypto transportCrypto =
|
|
||||||
new TransportCryptoImpl(crypto);
|
|
||||||
private final TransportId transportId = getTransportId();
|
|
||||||
private final SecretKey rootKey = getSecretKey();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreDistinct() {
|
|
||||||
HandshakeKeys kA = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, true);
|
|
||||||
HandshakeKeys kB = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, false);
|
|
||||||
assertAllDifferent(kA);
|
|
||||||
assertAllDifferent(kB);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreNotUpdatedToPreviousPeriod() {
|
|
||||||
HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, true);
|
|
||||||
HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 122);
|
|
||||||
assertSame(k, k1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreNotUpdatedToCurrentPeriod() {
|
|
||||||
HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, true);
|
|
||||||
HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 123);
|
|
||||||
assertSame(k, k1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreUpdatedByOnePeriod() {
|
|
||||||
HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, true);
|
|
||||||
HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 124);
|
|
||||||
assertSame(k.getCurrentIncomingKeys(), k1.getPreviousIncomingKeys());
|
|
||||||
assertSame(k.getNextIncomingKeys(), k1.getCurrentIncomingKeys());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreUpdatedByTwoPeriods() {
|
|
||||||
HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, true);
|
|
||||||
HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 125);
|
|
||||||
assertSame(k.getNextIncomingKeys(), k1.getPreviousIncomingKeys());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreUpdatedByThreePeriods() {
|
|
||||||
HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, true);
|
|
||||||
HandshakeKeys k1 = transportCrypto.updateHandshakeKeys(k, 126);
|
|
||||||
assertAllDifferent(k, k1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCurrentKeysMatchContact() {
|
|
||||||
// Start in time period 123
|
|
||||||
HandshakeKeys kA = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, true);
|
|
||||||
HandshakeKeys kB = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, false);
|
|
||||||
// Alice's incoming keys should equal Bob's outgoing keys
|
|
||||||
assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys());
|
|
||||||
// Bob's incoming keys should equal Alice's outgoing keys
|
|
||||||
assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys());
|
|
||||||
// Update into the future
|
|
||||||
kA = transportCrypto.updateHandshakeKeys(kA, 456);
|
|
||||||
kB = transportCrypto.updateHandshakeKeys(kB, 456);
|
|
||||||
// Alice's incoming keys should equal Bob's outgoing keys
|
|
||||||
assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys());
|
|
||||||
// Bob's incoming keys should equal Alice's outgoing keys
|
|
||||||
assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testPreviousKeysMatchContact() {
|
|
||||||
// Start in time period 123
|
|
||||||
HandshakeKeys kA = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, true);
|
|
||||||
HandshakeKeys kB = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, false);
|
|
||||||
// Compare Alice's previous keys in period 456 with Bob's current keys
|
|
||||||
// in period 455
|
|
||||||
kA = transportCrypto.updateHandshakeKeys(kA, 456);
|
|
||||||
kB = transportCrypto.updateHandshakeKeys(kB, 455);
|
|
||||||
// Alice's previous incoming keys should equal Bob's current
|
|
||||||
// outgoing keys
|
|
||||||
assertMatches(kA.getPreviousIncomingKeys(),
|
|
||||||
kB.getCurrentOutgoingKeys());
|
|
||||||
// Compare Alice's current keys in period 456 with Bob's previous keys
|
|
||||||
// in period 457
|
|
||||||
kB = transportCrypto.updateHandshakeKeys(kB, 457);
|
|
||||||
// Bob's previous incoming keys should equal Alice's current
|
|
||||||
// outgoing keys
|
|
||||||
assertMatches(kB.getPreviousIncomingKeys(),
|
|
||||||
kA.getCurrentOutgoingKeys());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNextKeysMatchContact() {
|
|
||||||
// Start in time period 123
|
|
||||||
HandshakeKeys kA = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, true);
|
|
||||||
HandshakeKeys kB = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, false);
|
|
||||||
// Compare Alice's current keys in period 456 with Bob's next keys in
|
|
||||||
// period 455
|
|
||||||
kA = transportCrypto.updateHandshakeKeys(kA, 456);
|
|
||||||
kB = transportCrypto.updateHandshakeKeys(kB, 455);
|
|
||||||
// Bob's next incoming keys should equal Alice's current outgoing keys
|
|
||||||
assertMatches(kB.getNextIncomingKeys(), kA.getCurrentOutgoingKeys());
|
|
||||||
// Compare Alice's next keys in period 456 with Bob's current keys
|
|
||||||
// in period 457
|
|
||||||
kB = transportCrypto.updateHandshakeKeys(kB, 457);
|
|
||||||
// Alice's next incoming keys should equal Bob's current outgoing keys
|
|
||||||
assertMatches(kA.getNextIncomingKeys(), kB.getCurrentOutgoingKeys());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRootKeyAffectsOutput() {
|
|
||||||
SecretKey rootKey1 = getSecretKey();
|
|
||||||
assertFalse(Arrays.equals(rootKey.getBytes(), rootKey1.getBytes()));
|
|
||||||
HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, true);
|
|
||||||
HandshakeKeys k1 = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey1, 123, true);
|
|
||||||
assertAllDifferent(k, k1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransportIdAffectsOutput() {
|
|
||||||
TransportId transportId1 = getTransportId();
|
|
||||||
assertNotEquals(transportId.getString(), transportId1.getString());
|
|
||||||
HandshakeKeys k = transportCrypto.deriveHandshakeKeys(transportId,
|
|
||||||
rootKey, 123, true);
|
|
||||||
HandshakeKeys k1 = transportCrypto.deriveHandshakeKeys(transportId1,
|
|
||||||
rootKey, 123, true);
|
|
||||||
assertAllDifferent(k, k1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
package org.briarproject.bramble.crypto;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Bytes;
|
||||||
|
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.TransportKeys;
|
||||||
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.briarproject.bramble.test.TestSecureRandomProvider;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class KeyDerivationTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
private final CryptoComponent crypto =
|
||||||
|
new CryptoComponentImpl(new TestSecureRandomProvider(), null);
|
||||||
|
private final TransportCrypto transportCrypto =
|
||||||
|
new TransportCryptoImpl(crypto);
|
||||||
|
private final TransportId transportId = getTransportId();
|
||||||
|
private final SecretKey master = getSecretKey();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeysAreDistinct() {
|
||||||
|
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
||||||
|
master, 123, true, true);
|
||||||
|
assertAllDifferent(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCurrentKeysMatchCurrentKeysOfContact() {
|
||||||
|
// Start in rotation period 123
|
||||||
|
TransportKeys kA = transportCrypto.deriveTransportKeys(transportId,
|
||||||
|
master, 123, true, true);
|
||||||
|
TransportKeys kB = transportCrypto.deriveTransportKeys(transportId,
|
||||||
|
master, 123, false, true);
|
||||||
|
// Alice's incoming keys should equal Bob's outgoing keys
|
||||||
|
assertArrayEquals(kA.getCurrentIncomingKeys().getTagKey().getBytes(),
|
||||||
|
kB.getCurrentOutgoingKeys().getTagKey().getBytes());
|
||||||
|
assertArrayEquals(kA.getCurrentIncomingKeys().getHeaderKey().getBytes(),
|
||||||
|
kB.getCurrentOutgoingKeys().getHeaderKey().getBytes());
|
||||||
|
// Alice's outgoing keys should equal Bob's incoming keys
|
||||||
|
assertArrayEquals(kA.getCurrentOutgoingKeys().getTagKey().getBytes(),
|
||||||
|
kB.getCurrentIncomingKeys().getTagKey().getBytes());
|
||||||
|
assertArrayEquals(kA.getCurrentOutgoingKeys().getHeaderKey().getBytes(),
|
||||||
|
kB.getCurrentIncomingKeys().getHeaderKey().getBytes());
|
||||||
|
// Rotate into the future
|
||||||
|
kA = transportCrypto.rotateTransportKeys(kA, 456);
|
||||||
|
kB = transportCrypto.rotateTransportKeys(kB, 456);
|
||||||
|
// Alice's incoming keys should equal Bob's outgoing keys
|
||||||
|
assertArrayEquals(kA.getCurrentIncomingKeys().getTagKey().getBytes(),
|
||||||
|
kB.getCurrentOutgoingKeys().getTagKey().getBytes());
|
||||||
|
assertArrayEquals(kA.getCurrentIncomingKeys().getHeaderKey().getBytes(),
|
||||||
|
kB.getCurrentOutgoingKeys().getHeaderKey().getBytes());
|
||||||
|
// Alice's outgoing keys should equal Bob's incoming keys
|
||||||
|
assertArrayEquals(kA.getCurrentOutgoingKeys().getTagKey().getBytes(),
|
||||||
|
kB.getCurrentIncomingKeys().getTagKey().getBytes());
|
||||||
|
assertArrayEquals(kA.getCurrentOutgoingKeys().getHeaderKey().getBytes(),
|
||||||
|
kB.getCurrentIncomingKeys().getHeaderKey().getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPreviousKeysMatchPreviousKeysOfContact() {
|
||||||
|
// Start in rotation period 123
|
||||||
|
TransportKeys kA = transportCrypto.deriveTransportKeys(transportId,
|
||||||
|
master, 123, true, true);
|
||||||
|
TransportKeys kB = transportCrypto.deriveTransportKeys(transportId,
|
||||||
|
master, 123, false, true);
|
||||||
|
// Compare Alice's previous keys in period 456 with Bob's current keys
|
||||||
|
// in period 455
|
||||||
|
kA = transportCrypto.rotateTransportKeys(kA, 456);
|
||||||
|
kB = transportCrypto.rotateTransportKeys(kB, 455);
|
||||||
|
// Alice's previous incoming keys should equal Bob's outgoing keys
|
||||||
|
assertArrayEquals(kA.getPreviousIncomingKeys().getTagKey().getBytes(),
|
||||||
|
kB.getCurrentOutgoingKeys().getTagKey().getBytes());
|
||||||
|
assertArrayEquals(
|
||||||
|
kA.getPreviousIncomingKeys().getHeaderKey().getBytes(),
|
||||||
|
kB.getCurrentOutgoingKeys().getHeaderKey().getBytes());
|
||||||
|
// Compare Alice's current keys in period 456 with Bob's previous keys
|
||||||
|
// in period 457
|
||||||
|
kB = transportCrypto.rotateTransportKeys(kB, 457);
|
||||||
|
// Alice's outgoing keys should equal Bob's previous incoming keys
|
||||||
|
assertArrayEquals(kA.getCurrentOutgoingKeys().getTagKey().getBytes(),
|
||||||
|
kB.getPreviousIncomingKeys().getTagKey().getBytes());
|
||||||
|
assertArrayEquals(kA.getCurrentOutgoingKeys().getHeaderKey().getBytes(),
|
||||||
|
kB.getPreviousIncomingKeys().getHeaderKey().getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNextKeysMatchNextKeysOfContact() {
|
||||||
|
// Start in rotation period 123
|
||||||
|
TransportKeys kA = transportCrypto.deriveTransportKeys(transportId,
|
||||||
|
master, 123, true, true);
|
||||||
|
TransportKeys kB = transportCrypto.deriveTransportKeys(transportId,
|
||||||
|
master, 123, false, true);
|
||||||
|
// Compare Alice's current keys in period 456 with Bob's next keys in
|
||||||
|
// period 455
|
||||||
|
kA = transportCrypto.rotateTransportKeys(kA, 456);
|
||||||
|
kB = transportCrypto.rotateTransportKeys(kB, 455);
|
||||||
|
// Alice's outgoing keys should equal Bob's next incoming keys
|
||||||
|
assertArrayEquals(kA.getCurrentOutgoingKeys().getTagKey().getBytes(),
|
||||||
|
kB.getNextIncomingKeys().getTagKey().getBytes());
|
||||||
|
assertArrayEquals(kA.getCurrentOutgoingKeys().getHeaderKey().getBytes(),
|
||||||
|
kB.getNextIncomingKeys().getHeaderKey().getBytes());
|
||||||
|
// Compare Alice's next keys in period 456 with Bob's current keys
|
||||||
|
// in period 457
|
||||||
|
kB = transportCrypto.rotateTransportKeys(kB, 457);
|
||||||
|
// Alice's next incoming keys should equal Bob's outgoing keys
|
||||||
|
assertArrayEquals(kA.getNextIncomingKeys().getTagKey().getBytes(),
|
||||||
|
kB.getCurrentOutgoingKeys().getTagKey().getBytes());
|
||||||
|
assertArrayEquals(kA.getNextIncomingKeys().getHeaderKey().getBytes(),
|
||||||
|
kB.getCurrentOutgoingKeys().getHeaderKey().getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMasterKeyAffectsOutput() {
|
||||||
|
SecretKey master1 = getSecretKey();
|
||||||
|
assertFalse(Arrays.equals(master.getBytes(), master1.getBytes()));
|
||||||
|
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
||||||
|
master, 123, true, true);
|
||||||
|
TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId,
|
||||||
|
master1, 123, true, true);
|
||||||
|
assertAllDifferent(k, k1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransportIdAffectsOutput() {
|
||||||
|
TransportId transportId1 = getTransportId();
|
||||||
|
assertFalse(transportId.getString().equals(transportId1.getString()));
|
||||||
|
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
||||||
|
master, 123, true, true);
|
||||||
|
TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId1,
|
||||||
|
master, 123, true, true);
|
||||||
|
assertAllDifferent(k, k1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertAllDifferent(TransportKeys... transportKeys) {
|
||||||
|
List<SecretKey> secretKeys = new ArrayList<>();
|
||||||
|
for (TransportKeys k : transportKeys) {
|
||||||
|
secretKeys.add(k.getPreviousIncomingKeys().getTagKey());
|
||||||
|
secretKeys.add(k.getPreviousIncomingKeys().getHeaderKey());
|
||||||
|
secretKeys.add(k.getCurrentIncomingKeys().getTagKey());
|
||||||
|
secretKeys.add(k.getCurrentIncomingKeys().getHeaderKey());
|
||||||
|
secretKeys.add(k.getNextIncomingKeys().getTagKey());
|
||||||
|
secretKeys.add(k.getNextIncomingKeys().getHeaderKey());
|
||||||
|
secretKeys.add(k.getCurrentOutgoingKeys().getTagKey());
|
||||||
|
secretKeys.add(k.getCurrentOutgoingKeys().getHeaderKey());
|
||||||
|
}
|
||||||
|
assertAllDifferent(secretKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertAllDifferent(List<SecretKey> keys) {
|
||||||
|
Set<Bytes> set = new HashSet<>();
|
||||||
|
for (SecretKey k : keys) assertTrue(set.add(new Bytes(k.getBytes())));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package org.briarproject.bramble.crypto;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.Bytes;
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
|
||||||
import org.briarproject.bramble.api.transport.AbstractTransportKeys;
|
|
||||||
import org.briarproject.bramble.api.transport.IncomingKeys;
|
|
||||||
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
class KeyDerivationTestUtils {
|
|
||||||
|
|
||||||
static void assertAllDifferent(AbstractTransportKeys... transportKeys) {
|
|
||||||
List<SecretKey> secretKeys = new ArrayList<>();
|
|
||||||
for (AbstractTransportKeys k : transportKeys) {
|
|
||||||
secretKeys.add(k.getPreviousIncomingKeys().getTagKey());
|
|
||||||
secretKeys.add(k.getPreviousIncomingKeys().getHeaderKey());
|
|
||||||
secretKeys.add(k.getCurrentIncomingKeys().getTagKey());
|
|
||||||
secretKeys.add(k.getCurrentIncomingKeys().getHeaderKey());
|
|
||||||
secretKeys.add(k.getNextIncomingKeys().getTagKey());
|
|
||||||
secretKeys.add(k.getNextIncomingKeys().getHeaderKey());
|
|
||||||
secretKeys.add(k.getCurrentOutgoingKeys().getTagKey());
|
|
||||||
secretKeys.add(k.getCurrentOutgoingKeys().getHeaderKey());
|
|
||||||
}
|
|
||||||
assertAllDifferent(secretKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void assertAllDifferent(List<SecretKey> keys) {
|
|
||||||
Set<Bytes> set = new HashSet<>();
|
|
||||||
for (SecretKey k : keys) assertTrue(set.add(new Bytes(k.getBytes())));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void assertMatches(IncomingKeys in, OutgoingKeys out) {
|
|
||||||
assertArrayEquals(in.getTagKey().getBytes(),
|
|
||||||
out.getTagKey().getBytes());
|
|
||||||
assertArrayEquals(in.getHeaderKey().getBytes(),
|
|
||||||
out.getHeaderKey().getBytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
package org.briarproject.bramble.crypto;
|
|
||||||
|
|
||||||
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.TransportKeys;
|
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
|
||||||
import org.briarproject.bramble.test.TestSecureRandomProvider;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import static org.briarproject.bramble.crypto.KeyDerivationTestUtils.assertAllDifferent;
|
|
||||||
import static org.briarproject.bramble.crypto.KeyDerivationTestUtils.assertMatches;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotEquals;
|
|
||||||
import static org.junit.Assert.assertSame;
|
|
||||||
|
|
||||||
public class TransportKeyDerivationTest extends BrambleTestCase {
|
|
||||||
|
|
||||||
private final CryptoComponent crypto =
|
|
||||||
new CryptoComponentImpl(new TestSecureRandomProvider(), null);
|
|
||||||
private final TransportCrypto transportCrypto =
|
|
||||||
new TransportCryptoImpl(crypto);
|
|
||||||
private final TransportId transportId = getTransportId();
|
|
||||||
private final SecretKey rootKey = getSecretKey();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreDistinct() {
|
|
||||||
TransportKeys kA = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, true, true);
|
|
||||||
TransportKeys kB = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, false, true);
|
|
||||||
assertAllDifferent(kA);
|
|
||||||
assertAllDifferent(kB);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreNotRotatedToPreviousPeriod() {
|
|
||||||
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, true, true);
|
|
||||||
TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 122);
|
|
||||||
assertSame(k, k1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreNotRotatedToCurrentPeriod() {
|
|
||||||
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, true, true);
|
|
||||||
TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 123);
|
|
||||||
assertSame(k, k1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreRotatedByOnePeriod() {
|
|
||||||
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, true, true);
|
|
||||||
TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 124);
|
|
||||||
assertSame(k.getCurrentIncomingKeys(), k1.getPreviousIncomingKeys());
|
|
||||||
assertSame(k.getNextIncomingKeys(), k1.getCurrentIncomingKeys());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreRotatedByTwoPeriods() {
|
|
||||||
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, true, true);
|
|
||||||
TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 125);
|
|
||||||
assertSame(k.getNextIncomingKeys(), k1.getPreviousIncomingKeys());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreRotatedByThreePeriods() {
|
|
||||||
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, true, true);
|
|
||||||
TransportKeys k1 = transportCrypto.rotateTransportKeys(k, 126);
|
|
||||||
assertAllDifferent(k, k1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCurrentKeysMatchContact() {
|
|
||||||
// Start in time period 123
|
|
||||||
TransportKeys kA = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, true, true);
|
|
||||||
TransportKeys kB = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, false, true);
|
|
||||||
// Alice's incoming keys should equal Bob's outgoing keys
|
|
||||||
assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys());
|
|
||||||
// Bob's incoming keys should equal Alice's outgoing keys
|
|
||||||
assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys());
|
|
||||||
// Rotate into the future
|
|
||||||
kA = transportCrypto.rotateTransportKeys(kA, 456);
|
|
||||||
kB = transportCrypto.rotateTransportKeys(kB, 456);
|
|
||||||
// Alice's incoming keys should equal Bob's outgoing keys
|
|
||||||
assertMatches(kA.getCurrentIncomingKeys(), kB.getCurrentOutgoingKeys());
|
|
||||||
// Bob's incoming keys should equal Alice's outgoing keys
|
|
||||||
assertMatches(kB.getCurrentIncomingKeys(), kA.getCurrentOutgoingKeys());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testPreviousKeysMatchContact() {
|
|
||||||
// Start in time period 123
|
|
||||||
TransportKeys kA = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, true, true);
|
|
||||||
TransportKeys kB = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, false, true);
|
|
||||||
// Compare Alice's previous keys in period 456 with Bob's current keys
|
|
||||||
// in period 455
|
|
||||||
kA = transportCrypto.rotateTransportKeys(kA, 456);
|
|
||||||
kB = transportCrypto.rotateTransportKeys(kB, 455);
|
|
||||||
// Alice's previous incoming keys should equal Bob's current
|
|
||||||
// outgoing keys
|
|
||||||
assertMatches(kA.getPreviousIncomingKeys(),
|
|
||||||
kB.getCurrentOutgoingKeys());
|
|
||||||
// Compare Alice's current keys in period 456 with Bob's previous keys
|
|
||||||
// in period 457
|
|
||||||
kB = transportCrypto.rotateTransportKeys(kB, 457);
|
|
||||||
// Bob's previous incoming keys should equal Alice's current
|
|
||||||
// outgoing keys
|
|
||||||
assertMatches(kB.getPreviousIncomingKeys(),
|
|
||||||
kA.getCurrentOutgoingKeys());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNextKeysMatchContact() {
|
|
||||||
// Start in time period 123
|
|
||||||
TransportKeys kA = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, true, true);
|
|
||||||
TransportKeys kB = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, false, true);
|
|
||||||
// Compare Alice's current keys in period 456 with Bob's next keys in
|
|
||||||
// period 455
|
|
||||||
kA = transportCrypto.rotateTransportKeys(kA, 456);
|
|
||||||
kB = transportCrypto.rotateTransportKeys(kB, 455);
|
|
||||||
// Bob's next incoming keys should equal Alice's current outgoing keys
|
|
||||||
assertMatches(kB.getNextIncomingKeys(), kA.getCurrentOutgoingKeys());
|
|
||||||
// Compare Alice's next keys in period 456 with Bob's current keys
|
|
||||||
// in period 457
|
|
||||||
kB = transportCrypto.rotateTransportKeys(kB, 457);
|
|
||||||
// Alice's next incoming keys should equal Bob's current outgoing keys
|
|
||||||
assertMatches(kA.getNextIncomingKeys(), kB.getCurrentOutgoingKeys());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRootKeyAffectsOutput() {
|
|
||||||
SecretKey rootKey1 = getSecretKey();
|
|
||||||
assertFalse(Arrays.equals(rootKey.getBytes(), rootKey1.getBytes()));
|
|
||||||
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, true, true);
|
|
||||||
TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey1, 123, true, true);
|
|
||||||
assertAllDifferent(k, k1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransportIdAffectsOutput() {
|
|
||||||
TransportId transportId1 = getTransportId();
|
|
||||||
assertNotEquals(transportId.getString(), transportId1.getString());
|
|
||||||
TransportKeys k = transportCrypto.deriveTransportKeys(transportId,
|
|
||||||
rootKey, 123, true, true);
|
|
||||||
TransportKeys k1 = transportCrypto.deriveTransportKeys(transportId1,
|
|
||||||
rootKey, 123, true, true);
|
|
||||||
assertAllDifferent(k, k1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,9 +2,9 @@ package org.briarproject.bramble.db;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
|
||||||
import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||||
|
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.ContactExistsException;
|
import org.briarproject.bramble.api.db.ContactExistsException;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
@@ -13,9 +13,7 @@ import org.briarproject.bramble.api.db.NoSuchContactException;
|
|||||||
import org.briarproject.bramble.api.db.NoSuchGroupException;
|
import org.briarproject.bramble.api.db.NoSuchGroupException;
|
||||||
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
|
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
|
||||||
import org.briarproject.bramble.api.db.NoSuchMessageException;
|
import org.briarproject.bramble.api.db.NoSuchMessageException;
|
||||||
import org.briarproject.bramble.api.db.NoSuchPendingContactException;
|
|
||||||
import org.briarproject.bramble.api.db.NoSuchTransportException;
|
import org.briarproject.bramble.api.db.NoSuchTransportException;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
@@ -45,21 +43,18 @@ import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
|
|||||||
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
|
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
|
||||||
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
|
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
|
||||||
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
|
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
|
||||||
import org.briarproject.bramble.api.transport.HandshakeKeys;
|
|
||||||
import org.briarproject.bramble.api.transport.IncomingKeys;
|
import org.briarproject.bramble.api.transport.IncomingKeys;
|
||||||
|
import org.briarproject.bramble.api.transport.KeySet;
|
||||||
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeySet;
|
|
||||||
import org.briarproject.bramble.api.transport.TransportKeySetId;
|
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.CaptureArgumentAction;
|
import org.briarproject.bramble.test.CaptureArgumentAction;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.jmock.Sequence;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
@@ -75,13 +70,13 @@ import static org.briarproject.bramble.api.transport.TransportConstants.REORDERI
|
|||||||
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getClientId;
|
import static org.briarproject.bramble.test.TestUtils.getClientId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContact;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@@ -92,10 +87,9 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private final Database<Object> database = context.mock(Database.class);
|
private final Database<Object> database = context.mock(Database.class);
|
||||||
private final ShutdownManager shutdownManager =
|
private final ShutdownManager shutdown =
|
||||||
context.mock(ShutdownManager.class);
|
context.mock(ShutdownManager.class);
|
||||||
private final EventBus eventBus = context.mock(EventBus.class);
|
private final EventBus eventBus = context.mock(EventBus.class);
|
||||||
private final Executor eventExecutor = context.mock(Executor.class);
|
|
||||||
|
|
||||||
private final SecretKey key = getSecretKey();
|
private final SecretKey key = getSecretKey();
|
||||||
private final Object txn = new Object();
|
private final Object txn = new Object();
|
||||||
@@ -113,8 +107,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
private final int maxLatency;
|
private final int maxLatency;
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final Contact contact;
|
private final Contact contact;
|
||||||
private final TransportKeySetId keySetId;
|
private final KeySetId keySetId;
|
||||||
private final PendingContactId pendingContactId;
|
|
||||||
|
|
||||||
public DatabaseComponentImplTest() {
|
public DatabaseComponentImplTest() {
|
||||||
clientId = getClientId();
|
clientId = getClientId();
|
||||||
@@ -123,6 +116,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
groupId = group.getId();
|
groupId = group.getId();
|
||||||
author = getAuthor();
|
author = getAuthor();
|
||||||
localAuthor = getLocalAuthor();
|
localAuthor = getLocalAuthor();
|
||||||
|
alias = getRandomString(5);
|
||||||
message = getMessage(groupId);
|
message = getMessage(groupId);
|
||||||
message1 = getMessage(groupId);
|
message1 = getMessage(groupId);
|
||||||
messageId = message.getId();
|
messageId = message.getId();
|
||||||
@@ -131,18 +125,16 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
metadata.put("foo", new byte[] {'b', 'a', 'r'});
|
metadata.put("foo", new byte[] {'b', 'a', 'r'});
|
||||||
transportId = getTransportId();
|
transportId = getTransportId();
|
||||||
maxLatency = Integer.MAX_VALUE;
|
maxLatency = Integer.MAX_VALUE;
|
||||||
contact = getContact(author, true);
|
contactId = new ContactId(234);
|
||||||
contactId = contact.getId();
|
contact = new Contact(contactId, author, localAuthor.getId(), alias,
|
||||||
alias = contact.getAlias();
|
true, true);
|
||||||
keySetId = new TransportKeySetId(345);
|
keySetId = new KeySetId(345);
|
||||||
pendingContactId = new PendingContactId(getRandomId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DatabaseComponent createDatabaseComponent(Database<Object> database,
|
private DatabaseComponent createDatabaseComponent(Database<Object> database,
|
||||||
EventBus eventBus, Executor eventExecutor,
|
EventBus eventBus, ShutdownManager shutdown) {
|
||||||
ShutdownManager shutdownManager) {
|
|
||||||
return new DatabaseComponentImpl<>(database, Object.class, eventBus,
|
return new DatabaseComponentImpl<>(database, Object.class, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -152,7 +144,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
// open()
|
// open()
|
||||||
oneOf(database).open(key, null);
|
oneOf(database).open(key, null);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(shutdownManager).addShutdownHook(with(any(Runnable.class)));
|
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
||||||
will(returnValue(shutdownHandle));
|
will(returnValue(shutdownHandle));
|
||||||
// startTransaction()
|
// startTransaction()
|
||||||
oneOf(database).startTransaction();
|
oneOf(database).startTransaction();
|
||||||
@@ -163,13 +155,19 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).addLocalAuthor(txn, localAuthor);
|
oneOf(database).addLocalAuthor(txn, localAuthor);
|
||||||
oneOf(eventBus).broadcast(with(any(LocalAuthorAddedEvent.class)));
|
oneOf(eventBus).broadcast(with(any(LocalAuthorAddedEvent.class)));
|
||||||
// addContact()
|
// addContact()
|
||||||
|
oneOf(database).containsLocalAuthor(txn, localAuthor.getId());
|
||||||
|
will(returnValue(true));
|
||||||
oneOf(database).containsLocalAuthor(txn, author.getId());
|
oneOf(database).containsLocalAuthor(txn, author.getId());
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(database).containsContact(txn, author.getId());
|
oneOf(database).containsContact(txn, author.getId(),
|
||||||
|
localAuthor.getId());
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(database).addContact(txn, author, true);
|
oneOf(database).addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true);
|
||||||
will(returnValue(contactId));
|
will(returnValue(contactId));
|
||||||
oneOf(eventBus).broadcast(with(any(ContactAddedEvent.class)));
|
oneOf(eventBus).broadcast(with(any(ContactAddedEvent.class)));
|
||||||
|
oneOf(eventBus).broadcast(with(any(
|
||||||
|
ContactStatusChangedEvent.class)));
|
||||||
// getContacts()
|
// getContacts()
|
||||||
oneOf(database).getContacts(txn);
|
oneOf(database).getContacts(txn);
|
||||||
will(returnValue(singletonList(contact)));
|
will(returnValue(singletonList(contact)));
|
||||||
@@ -209,12 +207,13 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).close();
|
oneOf(database).close();
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
assertFalse(db.open(key, null));
|
assertFalse(db.open(key, null));
|
||||||
db.transaction(false, transaction -> {
|
db.transaction(false, transaction -> {
|
||||||
db.addLocalAuthor(transaction, localAuthor);
|
db.addLocalAuthor(transaction, localAuthor);
|
||||||
assertEquals(contactId, db.addContact(transaction, author, true));
|
assertEquals(contactId, db.addContact(transaction, author,
|
||||||
|
localAuthor.getId(), true, true));
|
||||||
assertEquals(singletonList(contact),
|
assertEquals(singletonList(contact),
|
||||||
db.getContacts(transaction));
|
db.getContacts(transaction));
|
||||||
db.addGroup(transaction, group); // First time - listeners called
|
db.addGroup(transaction, group); // First time - listeners called
|
||||||
@@ -239,7 +238,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).abortTransaction(txn);
|
oneOf(database).abortTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
db.addLocalMessage(transaction, message, metadata, true));
|
db.addLocalMessage(transaction, message, metadata, true));
|
||||||
@@ -264,7 +263,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(eventBus).broadcast(with(any(MessageSharedEvent.class)));
|
oneOf(eventBus).broadcast(with(any(MessageSharedEvent.class)));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
db.addLocalMessage(transaction, message, metadata, true));
|
db.addLocalMessage(transaction, message, metadata, true));
|
||||||
@@ -275,25 +274,14 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Check whether the contact is in the DB (which it's not)
|
// Check whether the contact is in the DB (which it's not)
|
||||||
exactly(18).of(database).startTransaction();
|
exactly(17).of(database).startTransaction();
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
exactly(17).of(database).containsContact(txn, contactId);
|
exactly(17).of(database).containsContact(txn, contactId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(database).containsContact(txn, author.getId());
|
exactly(17).of(database).abortTransaction(txn);
|
||||||
will(returnValue(false));
|
|
||||||
exactly(18).of(database).abortTransaction(txn);
|
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
try {
|
|
||||||
db.transaction(false, transaction ->
|
|
||||||
db.addHandshakeKeys(transaction, contactId,
|
|
||||||
createHandshakeKeys()));
|
|
||||||
fail();
|
|
||||||
} catch (NoSuchContactException expected) {
|
|
||||||
// Expected
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
@@ -344,14 +332,6 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
// Expected
|
// Expected
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
db.transaction(false, transaction ->
|
|
||||||
db.getContact(transaction, author.getId()));
|
|
||||||
fail();
|
|
||||||
} catch (NoSuchContactException expected) {
|
|
||||||
// Expected
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
db.getMessageStatus(transaction, contactId, groupId));
|
db.getMessageStatus(transaction, contactId, groupId));
|
||||||
@@ -419,6 +399,14 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
// Expected
|
// Expected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.transaction(false, transaction ->
|
||||||
|
db.setContactActive(transaction, contactId, true));
|
||||||
|
fail();
|
||||||
|
} catch (NoSuchContactException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
db.setContactAlias(transaction, contactId, alias));
|
db.setContactAlias(transaction, contactId, alias));
|
||||||
@@ -442,15 +430,24 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Check whether the pseudonym is in the DB (which it's not)
|
// Check whether the pseudonym is in the DB (which it's not)
|
||||||
exactly(2).of(database).startTransaction();
|
exactly(3).of(database).startTransaction();
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
exactly(2).of(database).containsLocalAuthor(txn,
|
exactly(3).of(database).containsLocalAuthor(txn,
|
||||||
localAuthor.getId());
|
localAuthor.getId());
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
exactly(2).of(database).abortTransaction(txn);
|
exactly(3).of(database).abortTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.transaction(false, transaction ->
|
||||||
|
db.addContact(transaction, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
|
fail();
|
||||||
|
} catch (NoSuchLocalAuthorException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
@@ -484,7 +481,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
@@ -568,7 +565,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
@@ -671,7 +668,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
exactly(5).of(database).abortTransaction(txn);
|
exactly(5).of(database).abortTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
@@ -716,39 +713,6 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testVariousMethodsThrowExceptionIfPendingContactIsMissing()
|
|
||||||
throws Exception {
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
// Check whether the pending contact is in the DB (which it's not)
|
|
||||||
exactly(2).of(database).startTransaction();
|
|
||||||
will(returnValue(txn));
|
|
||||||
exactly(2).of(database).containsPendingContact(txn,
|
|
||||||
pendingContactId);
|
|
||||||
will(returnValue(false));
|
|
||||||
exactly(2).of(database).abortTransaction(txn);
|
|
||||||
}});
|
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
|
||||||
eventExecutor, shutdownManager);
|
|
||||||
|
|
||||||
try {
|
|
||||||
db.transaction(false, transaction ->
|
|
||||||
db.addHandshakeKeys(transaction, pendingContactId,
|
|
||||||
createHandshakeKeys()));
|
|
||||||
fail();
|
|
||||||
} catch (NoSuchPendingContactException expected) {
|
|
||||||
// Expected
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
db.transaction(false, transaction ->
|
|
||||||
db.removePendingContact(transaction, pendingContactId));
|
|
||||||
fail();
|
|
||||||
} catch (NoSuchPendingContactException expected) {
|
|
||||||
// Expected
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenerateAck() throws Exception {
|
public void testGenerateAck() throws Exception {
|
||||||
Collection<MessageId> messagesToAck = asList(messageId, messageId1);
|
Collection<MessageId> messagesToAck = asList(messageId, messageId1);
|
||||||
@@ -763,7 +727,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction -> {
|
db.transaction(false, transaction -> {
|
||||||
Ack a = db.generateAck(transaction, contactId, 123);
|
Ack a = db.generateAck(transaction, contactId, 123);
|
||||||
@@ -797,7 +761,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(eventBus).broadcast(with(any(MessagesSentEvent.class)));
|
oneOf(eventBus).broadcast(with(any(MessagesSentEvent.class)));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
assertEquals(messages, db.generateBatch(transaction, contactId,
|
assertEquals(messages, db.generateBatch(transaction, contactId,
|
||||||
@@ -822,7 +786,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction -> {
|
db.transaction(false, transaction -> {
|
||||||
Offer o = db.generateOffer(transaction, contactId, 123, maxLatency);
|
Offer o = db.generateOffer(transaction, contactId, 123, maxLatency);
|
||||||
@@ -846,7 +810,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction -> {
|
db.transaction(false, transaction -> {
|
||||||
Request r = db.generateRequest(transaction, contactId, 123);
|
Request r = db.generateRequest(transaction, contactId, 123);
|
||||||
@@ -880,7 +844,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(eventBus).broadcast(with(any(MessagesSentEvent.class)));
|
oneOf(eventBus).broadcast(with(any(MessagesSentEvent.class)));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
assertEquals(messages, db.generateRequestedBatch(transaction,
|
assertEquals(messages, db.generateRequestedBatch(transaction,
|
||||||
@@ -901,7 +865,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(eventBus).broadcast(with(any(MessagesAckedEvent.class)));
|
oneOf(eventBus).broadcast(with(any(MessagesAckedEvent.class)));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction -> {
|
db.transaction(false, transaction -> {
|
||||||
Ack a = new Ack(singletonList(messageId));
|
Ack a = new Ack(singletonList(messageId));
|
||||||
@@ -939,7 +903,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(eventBus).broadcast(with(any(MessageToAckEvent.class)));
|
oneOf(eventBus).broadcast(with(any(MessageToAckEvent.class)));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction -> {
|
db.transaction(false, transaction -> {
|
||||||
// Receive the message twice
|
// Receive the message twice
|
||||||
@@ -967,7 +931,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(eventBus).broadcast(with(any(MessageToAckEvent.class)));
|
oneOf(eventBus).broadcast(with(any(MessageToAckEvent.class)));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
db.receiveMessage(transaction, contactId, message));
|
db.receiveMessage(transaction, contactId, message));
|
||||||
@@ -985,7 +949,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
db.receiveMessage(transaction, contactId, message));
|
db.receiveMessage(transaction, contactId, message));
|
||||||
@@ -1025,7 +989,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(eventBus).broadcast(with(any(MessageToRequestEvent.class)));
|
oneOf(eventBus).broadcast(with(any(MessageToRequestEvent.class)));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
Offer o = new Offer(asList(messageId, messageId1,
|
Offer o = new Offer(asList(messageId, messageId1,
|
||||||
messageId2, messageId3));
|
messageId2, messageId3));
|
||||||
@@ -1048,7 +1012,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(eventBus).broadcast(with(any(MessageRequestedEvent.class)));
|
oneOf(eventBus).broadcast(with(any(MessageRequestedEvent.class)));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
Request r = new Request(singletonList(messageId));
|
Request r = new Request(singletonList(messageId));
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
@@ -1078,7 +1042,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
GroupVisibilityUpdatedEvent.class, 0));
|
GroupVisibilityUpdatedEvent.class, 0));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
db.setGroupVisibility(transaction, contactId, groupId,
|
db.setGroupVisibility(transaction, contactId, groupId,
|
||||||
@@ -1112,7 +1076,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
GroupVisibilityUpdatedEvent.class, 0));
|
GroupVisibilityUpdatedEvent.class, 0));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
db.setGroupVisibility(transaction, contactId, groupId,
|
db.setGroupVisibility(transaction, contactId, groupId,
|
||||||
@@ -1138,7 +1102,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
db.setGroupVisibility(transaction, contactId, groupId,
|
db.setGroupVisibility(transaction, contactId, groupId,
|
||||||
@@ -1148,9 +1112,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testTransportKeys() throws Exception {
|
public void testTransportKeys() throws Exception {
|
||||||
TransportKeys transportKeys = createTransportKeys();
|
TransportKeys transportKeys = createTransportKeys();
|
||||||
TransportKeySet ks =
|
KeySet ks = new KeySet(keySetId, contactId, transportKeys);
|
||||||
new TransportKeySet(keySetId, contactId, transportKeys);
|
Collection<KeySet> keys = singletonList(ks);
|
||||||
Collection<TransportKeySet> keys = singletonList(ks);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// startTransaction()
|
// startTransaction()
|
||||||
@@ -1169,7 +1132,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction -> {
|
db.transaction(false, transaction -> {
|
||||||
db.updateTransportKeys(transaction, keys);
|
db.updateTransportKeys(transaction, keys);
|
||||||
@@ -1208,7 +1171,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(true, transaction -> {
|
db.transaction(true, transaction -> {
|
||||||
// With visible group - return stored status
|
// With visible group - return stored status
|
||||||
@@ -1258,7 +1221,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(true, transaction -> {
|
db.transaction(true, transaction -> {
|
||||||
// With visible group - return stored status
|
// With visible group - return stored status
|
||||||
@@ -1277,27 +1240,6 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private HandshakeKeys createHandshakeKeys() {
|
|
||||||
SecretKey inPrevTagKey = getSecretKey();
|
|
||||||
SecretKey inPrevHeaderKey = getSecretKey();
|
|
||||||
IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey,
|
|
||||||
1, 123, new byte[4]);
|
|
||||||
SecretKey inCurrTagKey = getSecretKey();
|
|
||||||
SecretKey inCurrHeaderKey = getSecretKey();
|
|
||||||
IncomingKeys inCurr = new IncomingKeys(inCurrTagKey, inCurrHeaderKey,
|
|
||||||
2, 234, new byte[4]);
|
|
||||||
SecretKey inNextTagKey = getSecretKey();
|
|
||||||
SecretKey inNextHeaderKey = getSecretKey();
|
|
||||||
IncomingKeys inNext = new IncomingKeys(inNextTagKey, inNextHeaderKey,
|
|
||||||
3, 345, new byte[4]);
|
|
||||||
SecretKey outCurrTagKey = getSecretKey();
|
|
||||||
SecretKey outCurrHeaderKey = getSecretKey();
|
|
||||||
OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey,
|
|
||||||
2, 456, true);
|
|
||||||
return new HandshakeKeys(transportId, inPrev, inCurr, inNext, outCurr,
|
|
||||||
getSecretKey(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TransportKeys createTransportKeys() {
|
private TransportKeys createTransportKeys() {
|
||||||
SecretKey inPrevTagKey = getSecretKey();
|
SecretKey inPrevTagKey = getSecretKey();
|
||||||
SecretKey inPrevHeaderKey = getSecretKey();
|
SecretKey inPrevHeaderKey = getSecretKey();
|
||||||
@@ -1345,7 +1287,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
db.transaction(false, transaction -> {
|
db.transaction(false, transaction -> {
|
||||||
// First merge should broadcast an event
|
// First merge should broadcast an event
|
||||||
@@ -1388,7 +1330,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
assertNotNull(db.startTransaction(firstTxnReadOnly));
|
assertNotNull(db.startTransaction(firstTxnReadOnly));
|
||||||
db.startTransaction(secondTxnReadOnly);
|
db.startTransaction(secondTxnReadOnly);
|
||||||
@@ -1400,6 +1342,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(database).startTransaction();
|
oneOf(database).startTransaction();
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
|
oneOf(database).containsLocalAuthor(txn, localAuthor.getId());
|
||||||
|
will(returnValue(true));
|
||||||
// Contact is a local identity
|
// Contact is a local identity
|
||||||
oneOf(database).containsLocalAuthor(txn, author.getId());
|
oneOf(database).containsLocalAuthor(txn, author.getId());
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
@@ -1407,11 +1351,12 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
db.addContact(transaction, author, true));
|
db.addContact(transaction, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
fail();
|
fail();
|
||||||
} catch (ContactExistsException expected) {
|
} catch (ContactExistsException expected) {
|
||||||
// Expected
|
// Expected
|
||||||
@@ -1423,20 +1368,24 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(database).startTransaction();
|
oneOf(database).startTransaction();
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
|
oneOf(database).containsLocalAuthor(txn, localAuthor.getId());
|
||||||
|
will(returnValue(true));
|
||||||
oneOf(database).containsLocalAuthor(txn, author.getId());
|
oneOf(database).containsLocalAuthor(txn, author.getId());
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
// Contact already exists
|
// Contact already exists for this local identity
|
||||||
oneOf(database).containsContact(txn, author.getId());
|
oneOf(database).containsContact(txn, author.getId(),
|
||||||
|
localAuthor.getId());
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).abortTransaction(txn);
|
oneOf(database).abortTransaction(txn);
|
||||||
}});
|
}});
|
||||||
|
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.transaction(false, transaction ->
|
db.transaction(false, transaction ->
|
||||||
db.addContact(transaction, author, true));
|
db.addContact(transaction, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
fail();
|
fail();
|
||||||
} catch (ContactExistsException expected) {
|
} catch (ContactExistsException expected) {
|
||||||
// Expected
|
// Expected
|
||||||
@@ -1452,7 +1401,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
// open()
|
// open()
|
||||||
oneOf(database).open(key, null);
|
oneOf(database).open(key, null);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(shutdownManager).addShutdownHook(with(any(Runnable.class)));
|
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
||||||
will(returnValue(shutdownHandle));
|
will(returnValue(shutdownHandle));
|
||||||
// startTransaction()
|
// startTransaction()
|
||||||
oneOf(database).startTransaction();
|
oneOf(database).startTransaction();
|
||||||
@@ -1492,7 +1441,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).close();
|
oneOf(database).close();
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
shutdown);
|
||||||
|
|
||||||
assertFalse(db.open(key, null));
|
assertFalse(db.open(key, null));
|
||||||
db.transaction(false, transaction -> {
|
db.transaction(false, transaction -> {
|
||||||
@@ -1506,43 +1455,4 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
});
|
});
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCommitActionsOccurInOrder() throws Exception {
|
|
||||||
TestEvent action1 = new TestEvent();
|
|
||||||
Runnable action2 = () -> {
|
|
||||||
};
|
|
||||||
TestEvent action3 = new TestEvent();
|
|
||||||
Runnable action4 = () -> {
|
|
||||||
};
|
|
||||||
|
|
||||||
Sequence sequence = context.sequence("sequence");
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(database).startTransaction();
|
|
||||||
will(returnValue(txn));
|
|
||||||
inSequence(sequence);
|
|
||||||
oneOf(database).commitTransaction(txn);
|
|
||||||
inSequence(sequence);
|
|
||||||
oneOf(eventBus).broadcast(action1);
|
|
||||||
inSequence(sequence);
|
|
||||||
oneOf(eventExecutor).execute(action2);
|
|
||||||
inSequence(sequence);
|
|
||||||
oneOf(eventBus).broadcast(action3);
|
|
||||||
inSequence(sequence);
|
|
||||||
oneOf(eventExecutor).execute(action4);
|
|
||||||
inSequence(sequence);
|
|
||||||
}});
|
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
|
||||||
eventExecutor, shutdownManager);
|
|
||||||
|
|
||||||
db.transaction(false, transaction -> {
|
|
||||||
transaction.attach(action1);
|
|
||||||
transaction.attach(action2);
|
|
||||||
transaction.attach(action3);
|
|
||||||
transaction.attach(action4);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TestEvent extends Event {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
private final Migration<Connection> migration1 =
|
private final Migration<Connection> migration1 =
|
||||||
context.mock(Migration.class, "migration1");
|
context.mock(Migration.class, "migration1");
|
||||||
|
|
||||||
protected final DatabaseConfig config = new TestDatabaseConfig(testDir);
|
protected final DatabaseConfig config =
|
||||||
|
new TestDatabaseConfig(testDir, 1024 * 1024);
|
||||||
protected final MessageFactory messageFactory = new TestMessageFactory();
|
protected final MessageFactory messageFactory = new TestMessageFactory();
|
||||||
protected final SecretKey key = getSecretKey();
|
protected final SecretKey key = getSecretKey();
|
||||||
protected final Clock clock = new SystemClock();
|
protected final Clock clock = new SystemClock();
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ public abstract class DatabasePerformanceComparisonTest
|
|||||||
private Database<Connection> openDatabase(boolean conditionA)
|
private Database<Connection> openDatabase(boolean conditionA)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
Database<Connection> db = createDatabase(conditionA,
|
Database<Connection> db = createDatabase(conditionA,
|
||||||
new TestDatabaseConfig(testDir), new TestMessageFactory(),
|
new TestDatabaseConfig(testDir, MAX_SIZE),
|
||||||
new SystemClock());
|
new TestMessageFactory(), new SystemClock());
|
||||||
db.open(databaseKey, null);
|
db.open(databaseKey, null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.contact.Contact;
|
|||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Metadata;
|
import org.briarproject.bramble.api.db.Metadata;
|
||||||
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
import org.briarproject.bramble.api.sync.ClientId;
|
import org.briarproject.bramble.api.sync.ClientId;
|
||||||
import org.briarproject.bramble.api.sync.Group;
|
import org.briarproject.bramble.api.sync.Group;
|
||||||
@@ -48,6 +49,9 @@ import static org.junit.Assert.assertTrue;
|
|||||||
|
|
||||||
public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
private static final int ONE_MEGABYTE = 1024 * 1024;
|
||||||
|
static final int MAX_SIZE = 100 * ONE_MEGABYTE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How many contacts to simulate.
|
* How many contacts to simulate.
|
||||||
*/
|
*/
|
||||||
@@ -130,10 +134,11 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testContainsContactByAuthorId() throws Exception {
|
public void testContainsContactByAuthorId() throws Exception {
|
||||||
String name = "containsContact(T, AuthorId)";
|
String name = "containsContact(T, AuthorId, AuthorId)";
|
||||||
benchmark(name, db -> {
|
benchmark(name, db -> {
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
db.containsContact(txn, pickRandom(contacts).getAuthor().getId());
|
AuthorId remote = pickRandom(contacts).getAuthor().getId();
|
||||||
|
db.containsContact(txn, remote, localAuthor.getId());
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -200,7 +205,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetContactByContactId() throws Exception {
|
public void testGetContact() throws Exception {
|
||||||
String name = "getContact(T, ContactId)";
|
String name = "getContact(T, ContactId)";
|
||||||
benchmark(name, db -> {
|
benchmark(name, db -> {
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
@@ -209,16 +214,6 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetContactByAuthorId() throws Exception {
|
|
||||||
String name = "getContact(T, AuthorId)";
|
|
||||||
benchmark(name, db -> {
|
|
||||||
Connection txn = db.startTransaction();
|
|
||||||
db.getContact(txn, pickRandom(contacts).getAuthor().getId());
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetContacts() throws Exception {
|
public void testGetContacts() throws Exception {
|
||||||
String name = "getContacts(T)";
|
String name = "getContacts(T)";
|
||||||
@@ -229,6 +224,27 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetContactsByRemoteAuthorId() throws Exception {
|
||||||
|
String name = "getContactsByAuthorId(T, AuthorId)";
|
||||||
|
benchmark(name, db -> {
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
AuthorId remote = pickRandom(contacts).getAuthor().getId();
|
||||||
|
db.getContactsByAuthorId(txn, remote);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetContactsByLocalAuthorId() throws Exception {
|
||||||
|
String name = "getContacts(T, AuthorId)";
|
||||||
|
benchmark(name, db -> {
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
db.getContacts(txn, localAuthor.getId());
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetGroup() throws Exception {
|
public void testGetGroup() throws Exception {
|
||||||
String name = "getGroup(T, GroupId)";
|
String name = "getGroup(T, GroupId)";
|
||||||
@@ -532,7 +548,8 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
db.addLocalAuthor(txn, localAuthor);
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
for (int i = 0; i < CONTACTS; i++) {
|
for (int i = 0; i < CONTACTS; i++) {
|
||||||
ContactId c = db.addContact(txn, getAuthor(), random.nextBoolean());
|
ContactId c = db.addContact(txn, getAuthor(), localAuthor.getId(),
|
||||||
|
random.nextBoolean(), true);
|
||||||
contacts.add(db.getContact(txn, c));
|
contacts.add(db.getContact(txn, c));
|
||||||
contactGroups.put(c, new ArrayList<>());
|
contactGroups.put(c, new ArrayList<>());
|
||||||
for (int j = 0; j < GROUPS_PER_CONTACT; j++) {
|
for (int j = 0; j < GROUPS_PER_CONTACT; j++) {
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
|
|||||||
|
|
||||||
private Database<Connection> openDatabase() throws DbException {
|
private Database<Connection> openDatabase() throws DbException {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir), new TestMessageFactory(),
|
new TestDatabaseConfig(testDir, MAX_SIZE),
|
||||||
new SystemClock());
|
new TestMessageFactory(), new SystemClock());
|
||||||
db.open(databaseKey, null);
|
db.open(databaseKey, null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.bramble.db;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.PendingContact;
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
@@ -21,13 +20,10 @@ import org.briarproject.bramble.api.sync.MessageId;
|
|||||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
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.IncomingKeys;
|
import org.briarproject.bramble.api.transport.IncomingKeys;
|
||||||
|
import org.briarproject.bramble.api.transport.KeySet;
|
||||||
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeySet;
|
|
||||||
import org.briarproject.bramble.api.transport.TransportKeySetId;
|
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
import org.briarproject.bramble.system.SystemClock;
|
import org.briarproject.bramble.system.SystemClock;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
@@ -56,12 +52,12 @@ import static java.util.Collections.emptyMap;
|
|||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.Collections.singletonMap;
|
import static java.util.Collections.singletonMap;
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
import static org.briarproject.bramble.api.contact.PendingContactState.FAILED;
|
|
||||||
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
|
||||||
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
|
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
|
||||||
import static org.briarproject.bramble.api.sync.validation.MessageState.INVALID;
|
import static org.briarproject.bramble.api.sync.validation.MessageState.INVALID;
|
||||||
import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING;
|
import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING;
|
||||||
@@ -75,7 +71,6 @@ import static org.briarproject.bramble.test.TestUtils.getClientId;
|
|||||||
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getPendingContact;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
||||||
@@ -84,6 +79,7 @@ import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
|||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -92,9 +88,11 @@ import static org.junit.Assert.fail;
|
|||||||
public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||||
|
|
||||||
private static final int ONE_MEGABYTE = 1024 * 1024;
|
private static final int ONE_MEGABYTE = 1024 * 1024;
|
||||||
|
private static final int MAX_SIZE = 5 * ONE_MEGABYTE;
|
||||||
// All our transports use a maximum latency of 30 seconds
|
// All our transports use a maximum latency of 30 seconds
|
||||||
private static final int MAX_LATENCY = 30 * 1000;
|
private static final int MAX_LATENCY = 30 * 1000;
|
||||||
|
|
||||||
|
|
||||||
private final SecretKey key = getSecretKey();
|
private final SecretKey key = getSecretKey();
|
||||||
private final File testDir = getTestDirectory();
|
private final File testDir = getTestDirectory();
|
||||||
private final GroupId groupId;
|
private final GroupId groupId;
|
||||||
@@ -107,9 +105,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
private final MessageId messageId;
|
private final MessageId messageId;
|
||||||
private final TransportId transportId;
|
private final TransportId transportId;
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final TransportKeySetId keySetId, keySetId1;
|
private final KeySetId keySetId, keySetId1;
|
||||||
private final HandshakeKeySetId handshakeKeySetId, handshakeKeySetId1;
|
|
||||||
private final PendingContact pendingContact;
|
|
||||||
private final Random random = new Random();
|
private final Random random = new Random();
|
||||||
|
|
||||||
JdbcDatabaseTest() {
|
JdbcDatabaseTest() {
|
||||||
@@ -123,11 +119,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
messageId = message.getId();
|
messageId = message.getId();
|
||||||
transportId = getTransportId();
|
transportId = getTransportId();
|
||||||
contactId = new ContactId(1);
|
contactId = new ContactId(1);
|
||||||
keySetId = new TransportKeySetId(1);
|
keySetId = new KeySetId(1);
|
||||||
keySetId1 = new TransportKeySetId(2);
|
keySetId1 = new KeySetId(2);
|
||||||
handshakeKeySetId = new HandshakeKeySetId(1);
|
|
||||||
handshakeKeySetId1 = new HandshakeKeySetId(2);
|
|
||||||
pendingContact = getPendingContact();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract JdbcDatabase createDatabase(DatabaseConfig config,
|
protected abstract JdbcDatabase createDatabase(DatabaseConfig config,
|
||||||
@@ -145,7 +138,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
assertFalse(db.containsContact(txn, contactId));
|
assertFalse(db.containsContact(txn, contactId));
|
||||||
db.addLocalAuthor(txn, localAuthor);
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
assertTrue(db.containsContact(txn, contactId));
|
assertTrue(db.containsContact(txn, contactId));
|
||||||
assertFalse(db.containsGroup(txn, groupId));
|
assertFalse(db.containsGroup(txn, groupId));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
@@ -206,7 +200,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, a shared group and a shared message
|
// Add a contact, a shared group and a shared message
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addGroupVisibility(txn, contactId, groupId, true);
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
db.addMessage(txn, message, DELIVERED, true, null);
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
@@ -235,7 +231,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, a shared group and a shared but unvalidated message
|
// Add a contact, a shared group and a shared but unvalidated message
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addGroupVisibility(txn, contactId, groupId, true);
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
db.addMessage(txn, message, UNKNOWN, true, null);
|
db.addMessage(txn, message, UNKNOWN, true, null);
|
||||||
@@ -278,7 +276,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, an invisible group and a shared message
|
// Add a contact, an invisible group and a shared message
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addMessage(txn, message, DELIVERED, true, null);
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
|
|
||||||
@@ -327,7 +327,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, a shared group and an unshared message
|
// Add a contact, a shared group and an unshared message
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addGroupVisibility(txn, contactId, groupId, true);
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
db.addMessage(txn, message, DELIVERED, false, null);
|
db.addMessage(txn, message, DELIVERED, false, null);
|
||||||
@@ -356,14 +358,17 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, a shared group and a shared message
|
// Add a contact, a shared group and a shared message
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addGroupVisibility(txn, contactId, groupId, true);
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
db.addMessage(txn, message, DELIVERED, true, null);
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
|
|
||||||
// The message is sendable, but too large to send
|
// The message is sendable, but too large to send
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids =
|
||||||
message.getRawLength() - 1, MAX_LATENCY);
|
db.getMessagesToSend(txn, contactId, message.getRawLength() - 1,
|
||||||
|
MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
// The message is just the right size to send
|
// The message is just the right size to send
|
||||||
ids = db.getMessagesToSend(txn, contactId, message.getRawLength(),
|
ids = db.getMessagesToSend(txn, contactId, message.getRawLength(),
|
||||||
@@ -380,7 +385,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact and a visible group
|
// Add a contact and a visible group
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addGroupVisibility(txn, contactId, groupId, false);
|
db.addGroupVisibility(txn, contactId, groupId, false);
|
||||||
|
|
||||||
@@ -419,7 +426,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, a shared group and a shared message
|
// Add a contact, a shared group and a shared message
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addGroupVisibility(txn, contactId, groupId, true);
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
db.addMessage(txn, message, DELIVERED, true, null);
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
@@ -445,6 +454,29 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFreeSpace() throws Exception {
|
||||||
|
Message message = getMessage(groupId, MAX_MESSAGE_BODY_LENGTH);
|
||||||
|
Database<Connection> db = open(false);
|
||||||
|
|
||||||
|
// Sanity check: there should be enough space on disk for this test
|
||||||
|
assertTrue(testDir.getFreeSpace() > MAX_SIZE);
|
||||||
|
|
||||||
|
// The free space should not be more than the allowed maximum size
|
||||||
|
long free = db.getFreeSpace();
|
||||||
|
assertTrue(free <= MAX_SIZE);
|
||||||
|
assertTrue(free > 0);
|
||||||
|
|
||||||
|
// Storing a message should reduce the free space
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
db.addGroup(txn, group);
|
||||||
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
assertTrue(db.getFreeSpace() < free);
|
||||||
|
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCloseWaitsForCommit() throws Exception {
|
public void testCloseWaitsForCommit() throws Exception {
|
||||||
CountDownLatch closing = new CountDownLatch(1);
|
CountDownLatch closing = new CountDownLatch(1);
|
||||||
@@ -549,7 +581,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact and a shared group
|
// Add a contact and a shared group
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addGroupVisibility(txn, contactId, groupId, true);
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
|
|
||||||
@@ -567,7 +601,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact
|
// Add a contact
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
|
|
||||||
// The group is not in the database
|
// The group is not in the database
|
||||||
assertFalse(db.containsVisibleMessage(txn, contactId, messageId));
|
assertFalse(db.containsVisibleMessage(txn, contactId, messageId));
|
||||||
@@ -583,7 +619,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, an invisible group and a message
|
// Add a contact, an invisible group and a message
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addMessage(txn, message, DELIVERED, true, null);
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
|
|
||||||
@@ -600,7 +638,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact and a group
|
// Add a contact and a group
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
|
|
||||||
// The group should not be visible to the contact
|
// The group should not be visible to the contact
|
||||||
@@ -638,10 +678,10 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransportKeys() throws Exception {
|
public void testTransportKeys() throws Exception {
|
||||||
long timePeriod = 123, timePeriod1 = 234;
|
long rotationPeriod = 123, rotationPeriod1 = 234;
|
||||||
boolean active = random.nextBoolean();
|
boolean active = random.nextBoolean();
|
||||||
TransportKeys keys = createTransportKeys(timePeriod, active);
|
TransportKeys keys = createTransportKeys(rotationPeriod, active);
|
||||||
TransportKeys keys1 = createTransportKeys(timePeriod1, active);
|
TransportKeys keys1 = createTransportKeys(rotationPeriod1, active);
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
@@ -650,44 +690,43 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
assertEquals(emptyList(), db.getTransportKeys(txn, transportId));
|
assertEquals(emptyList(), db.getTransportKeys(txn, transportId));
|
||||||
|
|
||||||
// Add the contact, the transport and the transport keys
|
// Add the contact, the transport and the transport keys
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, active));
|
||||||
db.addTransport(txn, transportId, 123);
|
db.addTransport(txn, transportId, 123);
|
||||||
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
||||||
assertEquals(keySetId1, db.addTransportKeys(txn, contactId, keys1));
|
assertEquals(keySetId1, db.addTransportKeys(txn, contactId, keys1));
|
||||||
|
|
||||||
// Retrieve the transport keys
|
// Retrieve the transport keys
|
||||||
Collection<TransportKeySet> allKeys =
|
Collection<KeySet> allKeys = db.getTransportKeys(txn, transportId);
|
||||||
db.getTransportKeys(txn, transportId);
|
|
||||||
assertEquals(2, allKeys.size());
|
assertEquals(2, allKeys.size());
|
||||||
for (TransportKeySet ks : allKeys) {
|
for (KeySet ks : allKeys) {
|
||||||
assertEquals(contactId, ks.getContactId());
|
assertEquals(contactId, ks.getContactId());
|
||||||
if (ks.getKeySetId().equals(keySetId)) {
|
if (ks.getKeySetId().equals(keySetId)) {
|
||||||
assertKeysEquals(keys, ks.getKeys());
|
assertKeysEquals(keys, ks.getTransportKeys());
|
||||||
} else {
|
} else {
|
||||||
assertEquals(keySetId1, ks.getKeySetId());
|
assertEquals(keySetId1, ks.getKeySetId());
|
||||||
assertKeysEquals(keys1, ks.getKeys());
|
assertKeysEquals(keys1, ks.getTransportKeys());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotate the transport keys
|
// Rotate the transport keys
|
||||||
TransportKeys rotated = createTransportKeys(timePeriod + 1, active);
|
TransportKeys rotated = createTransportKeys(rotationPeriod + 1, active);
|
||||||
TransportKeys rotated1 =
|
TransportKeys rotated1 =
|
||||||
createTransportKeys(timePeriod1 + 1, active);
|
createTransportKeys(rotationPeriod1 + 1, active);
|
||||||
db.updateTransportKeys(txn, new TransportKeySet(keySetId, contactId,
|
db.updateTransportKeys(txn, new KeySet(keySetId, contactId, rotated));
|
||||||
rotated));
|
db.updateTransportKeys(txn, new KeySet(keySetId1, contactId, rotated1));
|
||||||
db.updateTransportKeys(txn, new TransportKeySet(keySetId1, contactId,
|
|
||||||
rotated1));
|
|
||||||
|
|
||||||
// Retrieve the transport keys again
|
// Retrieve the transport keys again
|
||||||
allKeys = db.getTransportKeys(txn, transportId);
|
allKeys = db.getTransportKeys(txn, transportId);
|
||||||
assertEquals(2, allKeys.size());
|
assertEquals(2, allKeys.size());
|
||||||
for (TransportKeySet ks : allKeys) {
|
for (KeySet ks : allKeys) {
|
||||||
assertEquals(contactId, ks.getContactId());
|
assertEquals(contactId, ks.getContactId());
|
||||||
if (ks.getKeySetId().equals(keySetId)) {
|
if (ks.getKeySetId().equals(keySetId)) {
|
||||||
assertKeysEquals(rotated, ks.getKeys());
|
assertKeysEquals(rotated, ks.getTransportKeys());
|
||||||
} else {
|
} else {
|
||||||
assertEquals(keySetId1, ks.getKeySetId());
|
assertEquals(keySetId1, ks.getKeySetId());
|
||||||
assertKeysEquals(rotated1, ks.getKeys());
|
assertKeysEquals(rotated1, ks.getTransportKeys());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -702,7 +741,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
private void assertKeysEquals(TransportKeys expected,
|
private void assertKeysEquals(TransportKeys expected,
|
||||||
TransportKeys actual) {
|
TransportKeys actual) {
|
||||||
assertEquals(expected.getTransportId(), actual.getTransportId());
|
assertEquals(expected.getTransportId(), actual.getTransportId());
|
||||||
assertEquals(expected.getTimePeriod(), actual.getTimePeriod());
|
assertEquals(expected.getRotationPeriod(), actual.getRotationPeriod());
|
||||||
assertKeysEquals(expected.getPreviousIncomingKeys(),
|
assertKeysEquals(expected.getPreviousIncomingKeys(),
|
||||||
actual.getPreviousIncomingKeys());
|
actual.getPreviousIncomingKeys());
|
||||||
assertKeysEquals(expected.getCurrentIncomingKeys(),
|
assertKeysEquals(expected.getCurrentIncomingKeys(),
|
||||||
@@ -718,7 +757,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
actual.getTagKey().getBytes());
|
actual.getTagKey().getBytes());
|
||||||
assertArrayEquals(expected.getHeaderKey().getBytes(),
|
assertArrayEquals(expected.getHeaderKey().getBytes(),
|
||||||
actual.getHeaderKey().getBytes());
|
actual.getHeaderKey().getBytes());
|
||||||
assertEquals(expected.getTimePeriod(), actual.getTimePeriod());
|
assertEquals(expected.getRotationPeriod(), actual.getRotationPeriod());
|
||||||
assertEquals(expected.getWindowBase(), actual.getWindowBase());
|
assertEquals(expected.getWindowBase(), actual.getWindowBase());
|
||||||
assertArrayEquals(expected.getWindowBitmap(), actual.getWindowBitmap());
|
assertArrayEquals(expected.getWindowBitmap(), actual.getWindowBitmap());
|
||||||
}
|
}
|
||||||
@@ -728,240 +767,39 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
actual.getTagKey().getBytes());
|
actual.getTagKey().getBytes());
|
||||||
assertArrayEquals(expected.getHeaderKey().getBytes(),
|
assertArrayEquals(expected.getHeaderKey().getBytes(),
|
||||||
actual.getHeaderKey().getBytes());
|
actual.getHeaderKey().getBytes());
|
||||||
assertEquals(expected.getTimePeriod(), actual.getTimePeriod());
|
assertEquals(expected.getRotationPeriod(), actual.getRotationPeriod());
|
||||||
assertEquals(expected.getStreamCounter(), actual.getStreamCounter());
|
assertEquals(expected.getStreamCounter(), actual.getStreamCounter());
|
||||||
assertEquals(expected.isActive(), actual.isActive());
|
assertEquals(expected.isActive(), actual.isActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHandshakeKeys() throws Exception {
|
|
||||||
long timePeriod = 123, timePeriod1 = 234;
|
|
||||||
boolean alice = random.nextBoolean();
|
|
||||||
SecretKey rootKey = getSecretKey();
|
|
||||||
SecretKey rootKey1 = getSecretKey();
|
|
||||||
HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice);
|
|
||||||
HandshakeKeys keys1 = createHandshakeKeys(timePeriod1, rootKey1, alice);
|
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
|
||||||
Connection txn = db.startTransaction();
|
|
||||||
|
|
||||||
// Initially there should be no handshake keys in the database
|
|
||||||
assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId));
|
|
||||||
|
|
||||||
// Add the contact, the transport and the handshake keys
|
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
|
||||||
db.addTransport(txn, transportId, 123);
|
|
||||||
assertEquals(handshakeKeySetId,
|
|
||||||
db.addHandshakeKeys(txn, contactId, keys));
|
|
||||||
assertEquals(handshakeKeySetId1,
|
|
||||||
db.addHandshakeKeys(txn, contactId, keys1));
|
|
||||||
|
|
||||||
// Retrieve the handshake keys
|
|
||||||
Collection<HandshakeKeySet> allKeys =
|
|
||||||
db.getHandshakeKeys(txn, transportId);
|
|
||||||
assertEquals(2, allKeys.size());
|
|
||||||
for (HandshakeKeySet ks : allKeys) {
|
|
||||||
assertEquals(contactId, ks.getContactId());
|
|
||||||
assertNull(ks.getPendingContactId());
|
|
||||||
if (ks.getKeySetId().equals(handshakeKeySetId)) {
|
|
||||||
assertKeysEquals(keys, ks.getKeys());
|
|
||||||
} else {
|
|
||||||
assertEquals(handshakeKeySetId1, ks.getKeySetId());
|
|
||||||
assertKeysEquals(keys1, ks.getKeys());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the handshake keys
|
|
||||||
HandshakeKeys updated =
|
|
||||||
createHandshakeKeys(timePeriod + 1, rootKey, alice);
|
|
||||||
HandshakeKeys updated1 =
|
|
||||||
createHandshakeKeys(timePeriod1 + 1, rootKey1, alice);
|
|
||||||
db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId,
|
|
||||||
contactId, updated));
|
|
||||||
db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId1,
|
|
||||||
contactId, updated1));
|
|
||||||
|
|
||||||
// Retrieve the handshake keys again
|
|
||||||
allKeys = db.getHandshakeKeys(txn, transportId);
|
|
||||||
assertEquals(2, allKeys.size());
|
|
||||||
for (HandshakeKeySet ks : allKeys) {
|
|
||||||
assertEquals(contactId, ks.getContactId());
|
|
||||||
assertNull(ks.getPendingContactId());
|
|
||||||
if (ks.getKeySetId().equals(handshakeKeySetId)) {
|
|
||||||
assertKeysEquals(updated, ks.getKeys());
|
|
||||||
} else {
|
|
||||||
assertEquals(handshakeKeySetId1, ks.getKeySetId());
|
|
||||||
assertKeysEquals(updated1, ks.getKeys());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removing the contact should remove the handshake keys
|
|
||||||
db.removeContact(txn, contactId);
|
|
||||||
assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId));
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertKeysEquals(HandshakeKeys expected,
|
|
||||||
HandshakeKeys actual) {
|
|
||||||
assertEquals(expected.getTransportId(), actual.getTransportId());
|
|
||||||
assertEquals(expected.getTimePeriod(), actual.getTimePeriod());
|
|
||||||
assertArrayEquals(expected.getRootKey().getBytes(),
|
|
||||||
actual.getRootKey().getBytes());
|
|
||||||
assertEquals(expected.isAlice(), actual.isAlice());
|
|
||||||
assertKeysEquals(expected.getPreviousIncomingKeys(),
|
|
||||||
actual.getPreviousIncomingKeys());
|
|
||||||
assertKeysEquals(expected.getCurrentIncomingKeys(),
|
|
||||||
actual.getCurrentIncomingKeys());
|
|
||||||
assertKeysEquals(expected.getNextIncomingKeys(),
|
|
||||||
actual.getNextIncomingKeys());
|
|
||||||
assertKeysEquals(expected.getCurrentOutgoingKeys(),
|
|
||||||
actual.getCurrentOutgoingKeys());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHandshakeKeysForPendingContact() throws Exception {
|
|
||||||
long timePeriod = 123, timePeriod1 = 234;
|
|
||||||
boolean alice = random.nextBoolean();
|
|
||||||
SecretKey rootKey = getSecretKey();
|
|
||||||
SecretKey rootKey1 = getSecretKey();
|
|
||||||
HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice);
|
|
||||||
HandshakeKeys keys1 = createHandshakeKeys(timePeriod1, rootKey1, alice);
|
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
|
||||||
Connection txn = db.startTransaction();
|
|
||||||
|
|
||||||
// Initially there should be no handshake keys in the database
|
|
||||||
assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId));
|
|
||||||
|
|
||||||
// Add the pending contact, the transport and the handshake keys
|
|
||||||
db.addPendingContact(txn, pendingContact);
|
|
||||||
db.addTransport(txn, transportId, 123);
|
|
||||||
assertEquals(handshakeKeySetId, db.addHandshakeKeys(txn,
|
|
||||||
pendingContact.getId(), keys));
|
|
||||||
assertEquals(handshakeKeySetId1, db.addHandshakeKeys(txn,
|
|
||||||
pendingContact.getId(), keys1));
|
|
||||||
|
|
||||||
// Retrieve the handshake keys
|
|
||||||
Collection<HandshakeKeySet> allKeys =
|
|
||||||
db.getHandshakeKeys(txn, transportId);
|
|
||||||
assertEquals(2, allKeys.size());
|
|
||||||
for (HandshakeKeySet ks : allKeys) {
|
|
||||||
assertNull(ks.getContactId());
|
|
||||||
assertEquals(pendingContact.getId(), ks.getPendingContactId());
|
|
||||||
if (ks.getKeySetId().equals(handshakeKeySetId)) {
|
|
||||||
assertKeysEquals(keys, ks.getKeys());
|
|
||||||
} else {
|
|
||||||
assertEquals(handshakeKeySetId1, ks.getKeySetId());
|
|
||||||
assertKeysEquals(keys1, ks.getKeys());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the handshake keys
|
|
||||||
HandshakeKeys updated =
|
|
||||||
createHandshakeKeys(timePeriod + 1, rootKey, alice);
|
|
||||||
HandshakeKeys updated1 =
|
|
||||||
createHandshakeKeys(timePeriod1 + 1, rootKey1, alice);
|
|
||||||
db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId,
|
|
||||||
pendingContact.getId(), updated));
|
|
||||||
db.updateHandshakeKeys(txn, new HandshakeKeySet(handshakeKeySetId1,
|
|
||||||
pendingContact.getId(), updated1));
|
|
||||||
|
|
||||||
// Retrieve the handshake keys again
|
|
||||||
allKeys = db.getHandshakeKeys(txn, transportId);
|
|
||||||
assertEquals(2, allKeys.size());
|
|
||||||
for (HandshakeKeySet ks : allKeys) {
|
|
||||||
assertNull(ks.getContactId());
|
|
||||||
assertEquals(pendingContact.getId(), ks.getPendingContactId());
|
|
||||||
if (ks.getKeySetId().equals(handshakeKeySetId)) {
|
|
||||||
assertKeysEquals(updated, ks.getKeys());
|
|
||||||
} else {
|
|
||||||
assertEquals(handshakeKeySetId1, ks.getKeySetId());
|
|
||||||
assertKeysEquals(updated1, ks.getKeys());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removing the pending contact should remove the handshake keys
|
|
||||||
db.removePendingContact(txn, pendingContact.getId());
|
|
||||||
assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId));
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIncrementStreamCounter() throws Exception {
|
public void testIncrementStreamCounter() throws Exception {
|
||||||
long timePeriod = 123;
|
long rotationPeriod = 123;
|
||||||
TransportKeys keys = createTransportKeys(timePeriod, true);
|
TransportKeys keys = createTransportKeys(rotationPeriod, true);
|
||||||
long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter();
|
long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter();
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add the contact, transport and transport keys
|
// Add the contact, transport and transport keys
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addTransport(txn, transportId, 123);
|
db.addTransport(txn, transportId, 123);
|
||||||
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
||||||
|
|
||||||
// Increment the stream counter twice and retrieve the transport keys
|
// Increment the stream counter twice and retrieve the transport keys
|
||||||
db.incrementStreamCounter(txn, transportId, keySetId);
|
db.incrementStreamCounter(txn, transportId, keySetId);
|
||||||
db.incrementStreamCounter(txn, transportId, keySetId);
|
db.incrementStreamCounter(txn, transportId, keySetId);
|
||||||
Collection<TransportKeySet> newKeys =
|
Collection<KeySet> newKeys = db.getTransportKeys(txn, transportId);
|
||||||
db.getTransportKeys(txn, transportId);
|
|
||||||
assertEquals(1, newKeys.size());
|
assertEquals(1, newKeys.size());
|
||||||
TransportKeySet ks = newKeys.iterator().next();
|
KeySet ks = newKeys.iterator().next();
|
||||||
assertEquals(keySetId, ks.getKeySetId());
|
assertEquals(keySetId, ks.getKeySetId());
|
||||||
assertEquals(contactId, ks.getContactId());
|
assertEquals(contactId, ks.getContactId());
|
||||||
TransportKeys k = ks.getKeys();
|
TransportKeys k = ks.getTransportKeys();
|
||||||
assertEquals(transportId, k.getTransportId());
|
assertEquals(transportId, k.getTransportId());
|
||||||
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
|
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
|
||||||
assertEquals(timePeriod, outCurr.getTimePeriod());
|
assertEquals(rotationPeriod, outCurr.getRotationPeriod());
|
||||||
assertEquals(streamCounter + 2, outCurr.getStreamCounter());
|
|
||||||
|
|
||||||
// The rest of the keys should be unaffected
|
|
||||||
assertKeysEquals(keys.getPreviousIncomingKeys(),
|
|
||||||
k.getPreviousIncomingKeys());
|
|
||||||
assertKeysEquals(keys.getCurrentIncomingKeys(),
|
|
||||||
k.getCurrentIncomingKeys());
|
|
||||||
assertKeysEquals(keys.getNextIncomingKeys(), k.getNextIncomingKeys());
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIncrementStreamCounterForHandshakeKeys() throws Exception {
|
|
||||||
long timePeriod = 123;
|
|
||||||
SecretKey rootKey = getSecretKey();
|
|
||||||
boolean alice = random.nextBoolean();
|
|
||||||
HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice);
|
|
||||||
long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter();
|
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
|
||||||
Connection txn = db.startTransaction();
|
|
||||||
|
|
||||||
// Add the contact, transport and handshake keys
|
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
|
||||||
db.addTransport(txn, transportId, 123);
|
|
||||||
assertEquals(handshakeKeySetId,
|
|
||||||
db.addHandshakeKeys(txn, contactId, keys));
|
|
||||||
|
|
||||||
// Increment the stream counter twice and retrieve the handshake keys
|
|
||||||
db.incrementStreamCounter(txn, transportId, handshakeKeySetId);
|
|
||||||
db.incrementStreamCounter(txn, transportId, handshakeKeySetId);
|
|
||||||
Collection<HandshakeKeySet> newKeys =
|
|
||||||
db.getHandshakeKeys(txn, transportId);
|
|
||||||
assertEquals(1, newKeys.size());
|
|
||||||
HandshakeKeySet ks = newKeys.iterator().next();
|
|
||||||
assertEquals(handshakeKeySetId, ks.getKeySetId());
|
|
||||||
assertEquals(contactId, ks.getContactId());
|
|
||||||
HandshakeKeys k = ks.getKeys();
|
|
||||||
assertEquals(transportId, k.getTransportId());
|
|
||||||
assertArrayEquals(rootKey.getBytes(), k.getRootKey().getBytes());
|
|
||||||
assertEquals(alice, k.isAlice());
|
|
||||||
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
|
|
||||||
assertEquals(timePeriod, outCurr.getTimePeriod());
|
|
||||||
assertEquals(streamCounter + 2, outCurr.getStreamCounter());
|
assertEquals(streamCounter + 2, outCurr.getStreamCounter());
|
||||||
|
|
||||||
// The rest of the keys should be unaffected
|
// The rest of the keys should be unaffected
|
||||||
@@ -978,8 +816,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testSetReorderingWindow() throws Exception {
|
public void testSetReorderingWindow() throws Exception {
|
||||||
boolean active = random.nextBoolean();
|
boolean active = random.nextBoolean();
|
||||||
long timePeriod = 123;
|
long rotationPeriod = 123;
|
||||||
TransportKeys keys = createTransportKeys(timePeriod, active);
|
TransportKeys keys = createTransportKeys(rotationPeriod, active);
|
||||||
long base = keys.getCurrentIncomingKeys().getWindowBase();
|
long base = keys.getCurrentIncomingKeys().getWindowBase();
|
||||||
byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap();
|
byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap();
|
||||||
|
|
||||||
@@ -987,24 +825,25 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add the contact, transport and transport keys
|
// Add the contact, transport and transport keys
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, active));
|
||||||
db.addTransport(txn, transportId, 123);
|
db.addTransport(txn, transportId, 123);
|
||||||
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
||||||
|
|
||||||
// Update the reordering window and retrieve the transport keys
|
// Update the reordering window and retrieve the transport keys
|
||||||
random.nextBytes(bitmap);
|
random.nextBytes(bitmap);
|
||||||
db.setReorderingWindow(txn, keySetId, transportId, timePeriod,
|
db.setReorderingWindow(txn, keySetId, transportId, rotationPeriod,
|
||||||
base + 1, bitmap);
|
base + 1, bitmap);
|
||||||
Collection<TransportKeySet> newKeys =
|
Collection<KeySet> newKeys = db.getTransportKeys(txn, transportId);
|
||||||
db.getTransportKeys(txn, transportId);
|
|
||||||
assertEquals(1, newKeys.size());
|
assertEquals(1, newKeys.size());
|
||||||
TransportKeySet ks = newKeys.iterator().next();
|
KeySet ks = newKeys.iterator().next();
|
||||||
assertEquals(keySetId, ks.getKeySetId());
|
assertEquals(keySetId, ks.getKeySetId());
|
||||||
assertEquals(contactId, ks.getContactId());
|
assertEquals(contactId, ks.getContactId());
|
||||||
TransportKeys k = ks.getKeys();
|
TransportKeys k = ks.getTransportKeys();
|
||||||
assertEquals(transportId, k.getTransportId());
|
assertEquals(transportId, k.getTransportId());
|
||||||
IncomingKeys inCurr = k.getCurrentIncomingKeys();
|
IncomingKeys inCurr = k.getCurrentIncomingKeys();
|
||||||
assertEquals(timePeriod, inCurr.getTimePeriod());
|
assertEquals(rotationPeriod, inCurr.getRotationPeriod());
|
||||||
assertEquals(base + 1, inCurr.getWindowBase());
|
assertEquals(base + 1, inCurr.getWindowBase());
|
||||||
assertArrayEquals(bitmap, inCurr.getWindowBitmap());
|
assertArrayEquals(bitmap, inCurr.getWindowBitmap());
|
||||||
|
|
||||||
@@ -1020,90 +859,54 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetReorderingWindowForHandshakeKeys() throws Exception {
|
public void testGetContactsByAuthorId() throws Exception {
|
||||||
long timePeriod = 123;
|
|
||||||
SecretKey rootKey = getSecretKey();
|
|
||||||
boolean alice = random.nextBoolean();
|
|
||||||
HandshakeKeys keys = createHandshakeKeys(timePeriod, rootKey, alice);
|
|
||||||
long base = keys.getCurrentIncomingKeys().getWindowBase();
|
|
||||||
byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap();
|
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add the contact, transport and handshake keys
|
// Add a local author - no contacts should be associated
|
||||||
assertEquals(contactId, db.addContact(txn, author,true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
db.addTransport(txn, transportId, 123);
|
|
||||||
assertEquals(handshakeKeySetId,
|
|
||||||
db.addHandshakeKeys(txn, contactId, keys));
|
|
||||||
|
|
||||||
// Update the reordering window and retrieve the handshake keys
|
// Add a contact associated with the local author
|
||||||
random.nextBytes(bitmap);
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
db.setReorderingWindow(txn, handshakeKeySetId, transportId, timePeriod,
|
true, true));
|
||||||
base + 1, bitmap);
|
|
||||||
Collection<HandshakeKeySet> newKeys =
|
|
||||||
db.getHandshakeKeys(txn, transportId);
|
|
||||||
assertEquals(1, newKeys.size());
|
|
||||||
HandshakeKeySet ks = newKeys.iterator().next();
|
|
||||||
assertEquals(handshakeKeySetId, ks.getKeySetId());
|
|
||||||
assertEquals(contactId, ks.getContactId());
|
|
||||||
HandshakeKeys k = ks.getKeys();
|
|
||||||
assertEquals(transportId, k.getTransportId());
|
|
||||||
assertArrayEquals(rootKey.getBytes(), k.getRootKey().getBytes());
|
|
||||||
assertEquals(alice, k.isAlice());
|
|
||||||
IncomingKeys inCurr = k.getCurrentIncomingKeys();
|
|
||||||
assertEquals(timePeriod, inCurr.getTimePeriod());
|
|
||||||
assertEquals(base + 1, inCurr.getWindowBase());
|
|
||||||
assertArrayEquals(bitmap, inCurr.getWindowBitmap());
|
|
||||||
|
|
||||||
// The rest of the keys should be unaffected
|
// Ensure contact is returned from database by Author ID
|
||||||
assertKeysEquals(keys.getPreviousIncomingKeys(),
|
Collection<Contact> contacts =
|
||||||
k.getPreviousIncomingKeys());
|
db.getContactsByAuthorId(txn, author.getId());
|
||||||
assertKeysEquals(keys.getNextIncomingKeys(), k.getNextIncomingKeys());
|
assertEquals(1, contacts.size());
|
||||||
assertKeysEquals(keys.getCurrentOutgoingKeys(),
|
assertEquals(contactId, contacts.iterator().next().getId());
|
||||||
k.getCurrentOutgoingKeys());
|
|
||||||
|
// Ensure no contacts are returned after contact was deleted
|
||||||
|
db.removeContact(txn, contactId);
|
||||||
|
contacts = db.getContactsByAuthorId(txn, author.getId());
|
||||||
|
assertEquals(0, contacts.size());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetContactByContactId() throws Exception {
|
public void testGetContactsByLocalAuthorId() throws Exception {
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact
|
// Add a local author - no contacts should be associated
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
Collection<ContactId> contacts =
|
||||||
|
db.getContacts(txn, localAuthor.getId());
|
||||||
|
assertEquals(emptyList(), contacts);
|
||||||
|
|
||||||
// Check the contact is returned
|
// Add a contact associated with the local author
|
||||||
Contact c = db.getContact(txn, contactId);
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
assertEquals(contactId, c.getId());
|
true, true));
|
||||||
assertEquals(author.getId(), c.getAuthor().getId());
|
contacts = db.getContacts(txn, localAuthor.getId());
|
||||||
assertEquals(author.getFormatVersion(),
|
assertEquals(singletonList(contactId), contacts);
|
||||||
c.getAuthor().getFormatVersion());
|
|
||||||
assertEquals(author.getName(), c.getAuthor().getName());
|
|
||||||
assertArrayEquals(author.getPublicKey(), c.getAuthor().getPublicKey());
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
// Remove the local author - the contact should be removed
|
||||||
db.close();
|
db.removeLocalAuthor(txn, localAuthor.getId());
|
||||||
}
|
contacts = db.getContacts(txn, localAuthor.getId());
|
||||||
|
assertEquals(emptyList(), contacts);
|
||||||
@Test
|
assertFalse(db.containsContact(txn, contactId));
|
||||||
public void testGetContactByAuthorId() throws Exception {
|
|
||||||
Database<Connection> db = open(false);
|
|
||||||
Connection txn = db.startTransaction();
|
|
||||||
|
|
||||||
// Add a contact
|
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
|
||||||
|
|
||||||
// Check the contact is returned
|
|
||||||
Contact c = db.getContact(txn, author.getId());
|
|
||||||
assertEquals(contactId, c.getId());
|
|
||||||
assertEquals(author.getId(), c.getAuthor().getId());
|
|
||||||
assertEquals(author.getFormatVersion(),
|
|
||||||
c.getAuthor().getFormatVersion());
|
|
||||||
assertEquals(author.getName(), c.getAuthor().getName());
|
|
||||||
assertArrayEquals(author.getPublicKey(), c.getAuthor().getPublicKey());
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
db.close();
|
db.close();
|
||||||
@@ -1115,7 +918,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact - initially there should be no offered messages
|
// Add a contact - initially there should be no offered messages
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
assertEquals(0, db.countOfferedMessages(txn, contactId));
|
assertEquals(0, db.countOfferedMessages(txn, contactId));
|
||||||
|
|
||||||
// Add some offered messages and count them
|
// Add some offered messages and count them
|
||||||
@@ -1697,7 +1502,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, a shared group and a shared message
|
// Add a contact, a shared group and a shared message
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addGroupVisibility(txn, contactId, groupId, true);
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
db.addMessage(txn, message, DELIVERED, true, null);
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
@@ -1794,13 +1601,43 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDifferentLocalAuthorsCanHaveTheSameContact()
|
||||||
|
throws Exception {
|
||||||
|
LocalAuthor localAuthor1 = getLocalAuthor();
|
||||||
|
|
||||||
|
Database<Connection> db = open(false);
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
|
// Add two local authors
|
||||||
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
db.addLocalAuthor(txn, localAuthor1);
|
||||||
|
|
||||||
|
// Add the same contact for each local author
|
||||||
|
ContactId contactId =
|
||||||
|
db.addContact(txn, author, localAuthor.getId(), true, true);
|
||||||
|
ContactId contactId1 =
|
||||||
|
db.addContact(txn, author, localAuthor1.getId(), true, true);
|
||||||
|
|
||||||
|
// The contacts should be distinct
|
||||||
|
assertNotEquals(contactId, contactId1);
|
||||||
|
assertEquals(2, db.getContacts(txn).size());
|
||||||
|
assertEquals(1, db.getContacts(txn, localAuthor.getId()).size());
|
||||||
|
assertEquals(1, db.getContacts(txn, localAuthor1.getId()).size());
|
||||||
|
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteMessage() throws Exception {
|
public void testDeleteMessage() throws Exception {
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, a shared group and a shared message
|
// Add a contact, a shared group and a shared message
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addGroupVisibility(txn, contactId, groupId, true);
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
db.addMessage(txn, message, DELIVERED, true, null);
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
@@ -1846,13 +1683,47 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetContactActive() throws Exception {
|
||||||
|
Database<Connection> db = open(false);
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
|
// Add a contact
|
||||||
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
|
|
||||||
|
// The contact should be active
|
||||||
|
Contact contact = db.getContact(txn, contactId);
|
||||||
|
assertTrue(contact.isActive());
|
||||||
|
|
||||||
|
// Set the contact inactive
|
||||||
|
db.setContactActive(txn, contactId, false);
|
||||||
|
|
||||||
|
// The contact should be inactive
|
||||||
|
contact = db.getContact(txn, contactId);
|
||||||
|
assertFalse(contact.isActive());
|
||||||
|
|
||||||
|
// Set the contact active
|
||||||
|
db.setContactActive(txn, contactId, true);
|
||||||
|
|
||||||
|
// The contact should be active
|
||||||
|
contact = db.getContact(txn, contactId);
|
||||||
|
assertTrue(contact.isActive());
|
||||||
|
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetContactAlias() throws Exception {
|
public void testSetContactAlias() throws Exception {
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact
|
// Add a contact
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
|
|
||||||
// The contact should have no alias
|
// The contact should have no alias
|
||||||
Contact contact = db.getContact(txn, contactId);
|
Contact contact = db.getContact(txn, contactId);
|
||||||
@@ -1907,7 +1778,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, a group and a message
|
// Add a contact, a group and a message
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addMessage(txn, message, UNKNOWN, false, null);
|
db.addMessage(txn, message, UNKNOWN, false, null);
|
||||||
|
|
||||||
@@ -1989,7 +1862,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, a shared group and a shared message
|
// Add a contact, a shared group and a shared message
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addGroupVisibility(txn, contactId, groupId, true);
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
db.addMessage(txn, message, DELIVERED, true, null);
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
@@ -2032,7 +1907,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, a shared group and a shared message
|
// Add a contact, a shared group and a shared message
|
||||||
assertEquals(contactId, db.addContact(txn, author, true));
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
db.addGroup(txn, group);
|
db.addGroup(txn, group);
|
||||||
db.addGroupVisibility(txn, contactId, groupId, true);
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
db.addMessage(txn, message, DELIVERED, true, null);
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
@@ -2113,94 +1990,41 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testPendingContacts() throws Exception {
|
|
||||||
Database<Connection> db = open(false);
|
|
||||||
Connection txn = db.startTransaction();
|
|
||||||
|
|
||||||
assertEquals(emptyList(), db.getPendingContacts(txn));
|
|
||||||
|
|
||||||
db.addPendingContact(txn, pendingContact);
|
|
||||||
Collection<PendingContact> pendingContacts =
|
|
||||||
db.getPendingContacts(txn);
|
|
||||||
assertEquals(1, pendingContacts.size());
|
|
||||||
PendingContact retrieved = pendingContacts.iterator().next();
|
|
||||||
assertEquals(pendingContact.getId(), retrieved.getId());
|
|
||||||
assertEquals(pendingContact.getAlias(), retrieved.getAlias());
|
|
||||||
assertEquals(pendingContact.getState(), retrieved.getState());
|
|
||||||
assertEquals(pendingContact.getTimestamp(), retrieved.getTimestamp());
|
|
||||||
|
|
||||||
db.setPendingContactState(txn, pendingContact.getId(), FAILED);
|
|
||||||
pendingContacts = db.getPendingContacts(txn);
|
|
||||||
assertEquals(1, pendingContacts.size());
|
|
||||||
retrieved = pendingContacts.iterator().next();
|
|
||||||
assertEquals(pendingContact.getId(), retrieved.getId());
|
|
||||||
assertEquals(pendingContact.getAlias(), retrieved.getAlias());
|
|
||||||
assertEquals(FAILED, retrieved.getState());
|
|
||||||
assertEquals(pendingContact.getTimestamp(), retrieved.getTimestamp());
|
|
||||||
|
|
||||||
db.removePendingContact(txn, pendingContact.getId());
|
|
||||||
assertEquals(emptyList(), db.getPendingContacts(txn));
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Database<Connection> open(boolean resume) throws Exception {
|
private Database<Connection> open(boolean resume) throws Exception {
|
||||||
return open(resume, new TestMessageFactory(), new SystemClock());
|
return open(resume, new TestMessageFactory(), new SystemClock());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Database<Connection> open(boolean resume,
|
private Database<Connection> open(boolean resume,
|
||||||
MessageFactory messageFactory, Clock clock) throws Exception {
|
MessageFactory messageFactory, Clock clock) throws Exception {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db =
|
||||||
new TestDatabaseConfig(testDir), messageFactory, clock);
|
createDatabase(new TestDatabaseConfig(testDir, MAX_SIZE),
|
||||||
|
messageFactory, clock);
|
||||||
if (!resume) deleteTestDirectory(testDir);
|
if (!resume) deleteTestDirectory(testDir);
|
||||||
db.open(key, null);
|
db.open(key, null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TransportKeys createTransportKeys(long timePeriod, boolean active) {
|
private TransportKeys createTransportKeys(long rotationPeriod,
|
||||||
|
boolean active) {
|
||||||
SecretKey inPrevTagKey = getSecretKey();
|
SecretKey inPrevTagKey = getSecretKey();
|
||||||
SecretKey inPrevHeaderKey = getSecretKey();
|
SecretKey inPrevHeaderKey = getSecretKey();
|
||||||
IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey,
|
IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey,
|
||||||
timePeriod - 1, 123, new byte[4]);
|
rotationPeriod - 1, 123, new byte[4]);
|
||||||
SecretKey inCurrTagKey = getSecretKey();
|
SecretKey inCurrTagKey = getSecretKey();
|
||||||
SecretKey inCurrHeaderKey = getSecretKey();
|
SecretKey inCurrHeaderKey = getSecretKey();
|
||||||
IncomingKeys inCurr = new IncomingKeys(inCurrTagKey, inCurrHeaderKey,
|
IncomingKeys inCurr = new IncomingKeys(inCurrTagKey, inCurrHeaderKey,
|
||||||
timePeriod, 234, new byte[4]);
|
rotationPeriod, 234, new byte[4]);
|
||||||
SecretKey inNextTagKey = getSecretKey();
|
SecretKey inNextTagKey = getSecretKey();
|
||||||
SecretKey inNextHeaderKey = getSecretKey();
|
SecretKey inNextHeaderKey = getSecretKey();
|
||||||
IncomingKeys inNext = new IncomingKeys(inNextTagKey, inNextHeaderKey,
|
IncomingKeys inNext = new IncomingKeys(inNextTagKey, inNextHeaderKey,
|
||||||
timePeriod + 1, 345, new byte[4]);
|
rotationPeriod + 1, 345, new byte[4]);
|
||||||
SecretKey outCurrTagKey = getSecretKey();
|
SecretKey outCurrTagKey = getSecretKey();
|
||||||
SecretKey outCurrHeaderKey = getSecretKey();
|
SecretKey outCurrHeaderKey = getSecretKey();
|
||||||
OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey,
|
OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey,
|
||||||
timePeriod, 456, active);
|
rotationPeriod, 456, active);
|
||||||
return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr);
|
return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HandshakeKeys createHandshakeKeys(long timePeriod,
|
|
||||||
SecretKey rootKey, boolean alice) {
|
|
||||||
SecretKey inPrevTagKey = getSecretKey();
|
|
||||||
SecretKey inPrevHeaderKey = getSecretKey();
|
|
||||||
IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey,
|
|
||||||
timePeriod - 1, 123, new byte[4]);
|
|
||||||
SecretKey inCurrTagKey = getSecretKey();
|
|
||||||
SecretKey inCurrHeaderKey = getSecretKey();
|
|
||||||
IncomingKeys inCurr = new IncomingKeys(inCurrTagKey, inCurrHeaderKey,
|
|
||||||
timePeriod, 234, new byte[4]);
|
|
||||||
SecretKey inNextTagKey = getSecretKey();
|
|
||||||
SecretKey inNextHeaderKey = getSecretKey();
|
|
||||||
IncomingKeys inNext = new IncomingKeys(inNextTagKey, inNextHeaderKey,
|
|
||||||
timePeriod + 1, 345, new byte[4]);
|
|
||||||
SecretKey outCurrTagKey = getSecretKey();
|
|
||||||
SecretKey outCurrHeaderKey = getSecretKey();
|
|
||||||
OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey,
|
|
||||||
timePeriod, 456, true);
|
|
||||||
return new HandshakeKeys(transportId, inPrev, inCurr, inNext, outCurr,
|
|
||||||
rootKey, alice);
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
deleteTestDirectory(testDir);
|
deleteTestDirectory(testDir);
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ public abstract class SingleDatabasePerformanceTest
|
|||||||
|
|
||||||
private Database<Connection> openDatabase() throws DbException {
|
private Database<Connection> openDatabase() throws DbException {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir), new TestMessageFactory(),
|
new TestDatabaseConfig(testDir, MAX_SIZE),
|
||||||
new SystemClock());
|
new TestMessageFactory(), new SystemClock());
|
||||||
db.open(databaseKey, null);
|
db.open(databaseKey, null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import org.junit.Rule;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_KEY_LABEL;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.MASTER_SECRET_LABEL;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.SHARED_SECRET_LABEL;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
@@ -74,7 +74,7 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
|||||||
Payload ourPayload = new Payload(aliceCommit, null);
|
Payload ourPayload = new Payload(aliceCommit, null);
|
||||||
KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
|
KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
|
||||||
SecretKey sharedSecret = getSecretKey();
|
SecretKey sharedSecret = getSecretKey();
|
||||||
SecretKey masterKey = getSecretKey();
|
SecretKey masterSecret = getSecretKey();
|
||||||
|
|
||||||
KeyAgreementProtocol protocol = new KeyAgreementProtocol(callbacks,
|
KeyAgreementProtocol protocol = new KeyAgreementProtocol(callbacks,
|
||||||
crypto, keyAgreementCrypto, payloadEncoder, transport,
|
crypto, keyAgreementCrypto, payloadEncoder, transport,
|
||||||
@@ -134,13 +134,13 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
|||||||
true, false);
|
true, false);
|
||||||
will(returnValue(bobConfirm));
|
will(returnValue(bobConfirm));
|
||||||
|
|
||||||
// Alice derives master key
|
// Alice computes master secret
|
||||||
oneOf(crypto).deriveKey(MASTER_KEY_LABEL, sharedSecret);
|
oneOf(crypto).deriveKey(MASTER_SECRET_LABEL, sharedSecret);
|
||||||
will(returnValue(masterKey));
|
will(returnValue(masterSecret));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
assertThat(masterKey, is(equalTo(protocol.perform())));
|
assertThat(masterSecret, is(equalTo(protocol.perform())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -150,7 +150,7 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
|||||||
Payload ourPayload = new Payload(bobCommit, null);
|
Payload ourPayload = new Payload(bobCommit, null);
|
||||||
KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
|
KeyPair ourKeyPair = new KeyPair(ourPubKey, null);
|
||||||
SecretKey sharedSecret = getSecretKey();
|
SecretKey sharedSecret = getSecretKey();
|
||||||
SecretKey masterKey = getSecretKey();
|
SecretKey masterSecret = getSecretKey();
|
||||||
|
|
||||||
KeyAgreementProtocol protocol = new KeyAgreementProtocol(callbacks,
|
KeyAgreementProtocol protocol = new KeyAgreementProtocol(callbacks,
|
||||||
crypto, keyAgreementCrypto, payloadEncoder, transport,
|
crypto, keyAgreementCrypto, payloadEncoder, transport,
|
||||||
@@ -209,13 +209,13 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
|||||||
will(returnValue(bobConfirm));
|
will(returnValue(bobConfirm));
|
||||||
oneOf(transport).sendConfirm(bobConfirm);
|
oneOf(transport).sendConfirm(bobConfirm);
|
||||||
|
|
||||||
// Bob derives master key
|
// Bob computes master secret
|
||||||
oneOf(crypto).deriveKey(MASTER_KEY_LABEL, sharedSecret);
|
oneOf(crypto).deriveKey(MASTER_SECRET_LABEL, sharedSecret);
|
||||||
will(returnValue(masterKey));
|
will(returnValue(masterSecret));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
assertThat(masterKey, is(equalTo(protocol.perform())));
|
assertThat(masterSecret, is(equalTo(protocol.perform())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = AbortException.class)
|
@Test(expected = AbortException.class)
|
||||||
@@ -373,8 +373,8 @@ public class KeyAgreementProtocolTest extends BrambleTestCase {
|
|||||||
// Alice aborts
|
// Alice aborts
|
||||||
oneOf(transport).sendAbort(false);
|
oneOf(transport).sendAbort(false);
|
||||||
|
|
||||||
// Alice never derives master key
|
// Alice never computes master secret
|
||||||
never(crypto).deriveKey(MASTER_KEY_LABEL, sharedSecret);
|
never(crypto).deriveKey(MASTER_SECRET_LABEL, sharedSecret);
|
||||||
}});
|
}});
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -29,8 +28,8 @@ public class ConnectionRegistryImplTest extends BrambleTestCase {
|
|||||||
private final TransportId transportId, transportId1;
|
private final TransportId transportId, transportId1;
|
||||||
|
|
||||||
public ConnectionRegistryImplTest() {
|
public ConnectionRegistryImplTest() {
|
||||||
contactId = getContactId();
|
contactId = new ContactId(1);
|
||||||
contactId1 = getContactId();
|
contactId1 = new ContactId(2);
|
||||||
transportId = getTransportId();
|
transportId = getTransportId();
|
||||||
transportId1 = getTransportId();
|
transportId1 = getTransportId();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.briarproject.bramble.plugin;
|
package org.briarproject.bramble.plugin;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
@@ -36,7 +36,6 @@ import static java.util.Collections.emptyList;
|
|||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.Collections.singletonMap;
|
import static java.util.Collections.singletonMap;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
|
||||||
public class PollerTest extends BrambleMockTestCase {
|
public class PollerTest extends BrambleMockTestCase {
|
||||||
@@ -57,7 +56,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
private final Executor ioExecutor = new ImmediateExecutor();
|
private final Executor ioExecutor = new ImmediateExecutor();
|
||||||
private final TransportId transportId = getTransportId();
|
private final TransportId transportId = getTransportId();
|
||||||
private final ContactId contactId = getContactId();
|
private final ContactId contactId = new ContactId(234);
|
||||||
private final TransportProperties properties = new TransportProperties();
|
private final TransportProperties properties = new TransportProperties();
|
||||||
private final int pollingInterval = 60 * 1000;
|
private final int pollingInterval = 60 * 1000;
|
||||||
private final long now = System.currentTimeMillis();
|
private final long now = System.currentTimeMillis();
|
||||||
@@ -68,7 +67,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConnectOnContactAdded() throws Exception {
|
public void testConnectOnContactStatusChanged() throws Exception {
|
||||||
// Two simplex plugins: one supports polling, the other doesn't
|
// Two simplex plugins: one supports polling, the other doesn't
|
||||||
SimplexPlugin simplexPlugin = context.mock(SimplexPlugin.class);
|
SimplexPlugin simplexPlugin = context.mock(SimplexPlugin.class);
|
||||||
SimplexPlugin simplexPlugin1 =
|
SimplexPlugin simplexPlugin1 =
|
||||||
@@ -144,7 +143,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
connectionRegistry, pluginManager, transportPropertyManager,
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
random, clock);
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new ContactAddedEvent(contactId));
|
p.eventOccurred(new ContactStatusChangedEvent(contactId, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import org.briarproject.bramble.api.data.MetadataParser;
|
|||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.Metadata;
|
import org.briarproject.bramble.api.db.Metadata;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
@@ -37,11 +36,12 @@ import static java.util.Collections.singletonMap;
|
|||||||
import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_ID;
|
import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_ID;
|
||||||
import static org.briarproject.bramble.api.properties.TransportPropertyManager.MAJOR_VERSION;
|
import static org.briarproject.bramble.api.properties.TransportPropertyManager.MAJOR_VERSION;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContact;
|
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
@@ -49,8 +49,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
private final ClientHelper clientHelper = context.mock(ClientHelper.class);
|
private final ClientHelper clientHelper = context.mock(ClientHelper.class);
|
||||||
private final IdentityManager identityManager =
|
|
||||||
context.mock(IdentityManager.class);
|
|
||||||
private final ClientVersioningManager clientVersioningManager =
|
private final ClientVersioningManager clientVersioningManager =
|
||||||
context.mock(ClientVersioningManager.class);
|
context.mock(ClientVersioningManager.class);
|
||||||
private final MetadataParser metadataParser =
|
private final MetadataParser metadataParser =
|
||||||
@@ -71,6 +69,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
);
|
);
|
||||||
private final TransportProperties fooProperties, barProperties;
|
private final TransportProperties fooProperties, barProperties;
|
||||||
|
|
||||||
|
private int nextContactId = 0;
|
||||||
|
|
||||||
public TransportPropertyManagerImplTest() throws Exception {
|
public TransportPropertyManagerImplTest() throws Exception {
|
||||||
fooProperties = new TransportProperties();
|
fooProperties = new TransportProperties();
|
||||||
for (String key : fooPropertiesDict.keySet())
|
for (String key : fooPropertiesDict.keySet())
|
||||||
@@ -87,26 +87,24 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(localGroup));
|
will(returnValue(localGroup));
|
||||||
}});
|
}});
|
||||||
return new TransportPropertyManagerImpl(db, clientHelper,
|
return new TransportPropertyManagerImpl(db, clientHelper,
|
||||||
identityManager, clientVersioningManager, metadataParser,
|
clientVersioningManager, metadataParser, contactGroupFactory,
|
||||||
contactGroupFactory, clock);
|
clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreatesGroupsAtStartup() throws Exception {
|
public void testCreatesGroupsAtStartup() throws Exception {
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
Contact contact = getContact();
|
Contact contact = getContact(true);
|
||||||
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(db).containsGroup(txn, localGroup.getId());
|
oneOf(db).containsGroup(txn, localGroup.getId());
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(db).addGroup(txn, localGroup);
|
oneOf(db).addGroup(txn, localGroup);
|
||||||
oneOf(identityManager).getLocalAuthor(txn);
|
|
||||||
will(returnValue(localAuthor));
|
|
||||||
oneOf(db).getContacts(txn);
|
oneOf(db).getContacts(txn);
|
||||||
will(returnValue(singletonList(contact)));
|
will(returnValue(singletonList(contact)));
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, contact, localAuthor.getId());
|
MAJOR_VERSION, contact);
|
||||||
will(returnValue(contactGroup));
|
will(returnValue(contactGroup));
|
||||||
oneOf(db).addGroup(txn, contactGroup);
|
oneOf(db).addGroup(txn, contactGroup);
|
||||||
oneOf(clientVersioningManager).getClientVisibility(txn,
|
oneOf(clientVersioningManager).getClientVisibility(txn,
|
||||||
@@ -143,15 +141,13 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testCreatesContactGroupWhenAddingContact() throws Exception {
|
public void testCreatesContactGroupWhenAddingContact() throws Exception {
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
Contact contact = getContact();
|
Contact contact = getContact(true);
|
||||||
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Create the group and share it with the contact
|
// Create the group and share it with the contact
|
||||||
oneOf(identityManager).getLocalAuthor(txn);
|
|
||||||
will(returnValue(localAuthor));
|
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, contact, localAuthor.getId());
|
MAJOR_VERSION, contact);
|
||||||
will(returnValue(contactGroup));
|
will(returnValue(contactGroup));
|
||||||
oneOf(db).addGroup(txn, contactGroup);
|
oneOf(db).addGroup(txn, contactGroup);
|
||||||
oneOf(clientVersioningManager).getClientVisibility(txn,
|
oneOf(clientVersioningManager).getClientVisibility(txn,
|
||||||
@@ -174,14 +170,12 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testRemovesGroupWhenRemovingContact() throws Exception {
|
public void testRemovesGroupWhenRemovingContact() throws Exception {
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
Contact contact = getContact();
|
Contact contact = getContact(true);
|
||||||
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(identityManager).getLocalAuthor(txn);
|
|
||||||
will(returnValue(localAuthor));
|
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, contact, localAuthor.getId());
|
MAJOR_VERSION, contact);
|
||||||
will(returnValue(contactGroup));
|
will(returnValue(contactGroup));
|
||||||
oneOf(db).removeGroup(txn, contactGroup);
|
oneOf(db).removeGroup(txn, contactGroup);
|
||||||
}});
|
}});
|
||||||
@@ -308,7 +302,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStoresRemotePropertiesWithVersion0() throws Exception {
|
public void testStoresRemotePropertiesWithVersion0() throws Exception {
|
||||||
Contact contact = getContact();
|
Contact contact = getContact(true);
|
||||||
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
Map<TransportId, TransportProperties> properties =
|
Map<TransportId, TransportProperties> properties =
|
||||||
@@ -319,10 +313,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(db).getContact(txn, contact.getId());
|
oneOf(db).getContact(txn, contact.getId());
|
||||||
will(returnValue(contact));
|
will(returnValue(contact));
|
||||||
oneOf(identityManager).getLocalAuthor(txn);
|
|
||||||
will(returnValue(localAuthor));
|
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, contact, localAuthor.getId());
|
MAJOR_VERSION, contact);
|
||||||
will(returnValue(contactGroup));
|
will(returnValue(contactGroup));
|
||||||
}});
|
}});
|
||||||
expectStoreMessage(txn, contactGroup.getId(), "foo", fooPropertiesDict,
|
expectStoreMessage(txn, contactGroup.getId(), "foo", fooPropertiesDict,
|
||||||
@@ -414,30 +406,31 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testReturnsRemotePropertiesOrEmptyProperties()
|
public void testReturnsRemotePropertiesOrEmptyProperties()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
Contact contact1 = getContact();
|
Contact contact1 = getContact(false);
|
||||||
Contact contact2 = getContact();
|
Contact contact2 = getContact(true);
|
||||||
List<Contact> contacts = asList(contact1, contact2);
|
Contact contact3 = getContact(true);
|
||||||
Group contactGroup1 = getGroup(CLIENT_ID, MAJOR_VERSION);
|
List<Contact> contacts = asList(contact1, contact2, contact3);
|
||||||
Group contactGroup2 = getGroup(CLIENT_ID, MAJOR_VERSION);
|
Group contactGroup2 = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||||
Map<MessageId, BdfDictionary> messageMetadata2 =
|
Group contactGroup3 = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||||
|
Map<MessageId, BdfDictionary> messageMetadata3 =
|
||||||
new LinkedHashMap<>();
|
new LinkedHashMap<>();
|
||||||
// A remote update for another transport should be ignored
|
// A remote update for another transport should be ignored
|
||||||
MessageId barUpdateId = new MessageId(getRandomId());
|
MessageId barUpdateId = new MessageId(getRandomId());
|
||||||
messageMetadata2.put(barUpdateId, BdfDictionary.of(
|
messageMetadata3.put(barUpdateId, BdfDictionary.of(
|
||||||
new BdfEntry("transportId", "bar"),
|
new BdfEntry("transportId", "bar"),
|
||||||
new BdfEntry("version", 1),
|
new BdfEntry("version", 1),
|
||||||
new BdfEntry("local", false)
|
new BdfEntry("local", false)
|
||||||
));
|
));
|
||||||
// A local update for the right transport should be ignored
|
// A local update for the right transport should be ignored
|
||||||
MessageId localUpdateId = new MessageId(getRandomId());
|
MessageId localUpdateId = new MessageId(getRandomId());
|
||||||
messageMetadata2.put(localUpdateId, BdfDictionary.of(
|
messageMetadata3.put(localUpdateId, BdfDictionary.of(
|
||||||
new BdfEntry("transportId", "foo"),
|
new BdfEntry("transportId", "foo"),
|
||||||
new BdfEntry("version", 1),
|
new BdfEntry("version", 1),
|
||||||
new BdfEntry("local", true)
|
new BdfEntry("local", true)
|
||||||
));
|
));
|
||||||
// A remote update for the right transport should be returned
|
// A remote update for the right transport should be returned
|
||||||
MessageId fooUpdateId = new MessageId(getRandomId());
|
MessageId fooUpdateId = new MessageId(getRandomId());
|
||||||
messageMetadata2.put(fooUpdateId, BdfDictionary.of(
|
messageMetadata3.put(fooUpdateId, BdfDictionary.of(
|
||||||
new BdfEntry("transportId", "foo"),
|
new BdfEntry("transportId", "foo"),
|
||||||
new BdfEntry("version", 1),
|
new BdfEntry("version", 1),
|
||||||
new BdfEntry("local", false)
|
new BdfEntry("local", false)
|
||||||
@@ -446,24 +439,23 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
oneOf(identityManager).getLocalAuthor(txn);
|
|
||||||
will(returnValue(localAuthor));
|
|
||||||
oneOf(db).getContacts(txn);
|
oneOf(db).getContacts(txn);
|
||||||
will(returnValue(contacts));
|
will(returnValue(contacts));
|
||||||
// First contact: no updates
|
// First contact: skipped because not active
|
||||||
|
// Second contact: no updates
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, contact1, localAuthor.getId());
|
MAJOR_VERSION, contact2);
|
||||||
will(returnValue(contactGroup1));
|
|
||||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
|
||||||
contactGroup1.getId());
|
|
||||||
will(returnValue(Collections.emptyMap()));
|
|
||||||
// Second contact: returns an update
|
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
|
||||||
MAJOR_VERSION, contact2, localAuthor.getId());
|
|
||||||
will(returnValue(contactGroup2));
|
will(returnValue(contactGroup2));
|
||||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
contactGroup2.getId());
|
contactGroup2.getId());
|
||||||
will(returnValue(messageMetadata2));
|
will(returnValue(Collections.emptyMap()));
|
||||||
|
// Third contact: returns an update
|
||||||
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
|
MAJOR_VERSION, contact3);
|
||||||
|
will(returnValue(contactGroup3));
|
||||||
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
|
contactGroup3.getId());
|
||||||
|
will(returnValue(messageMetadata3));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
|
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
|
||||||
will(returnValue(fooUpdate));
|
will(returnValue(fooUpdate));
|
||||||
oneOf(clientHelper).parseAndValidateTransportProperties(
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
@@ -474,9 +466,10 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
TransportPropertyManagerImpl t = createInstance();
|
TransportPropertyManagerImpl t = createInstance();
|
||||||
Map<ContactId, TransportProperties> properties =
|
Map<ContactId, TransportProperties> properties =
|
||||||
t.getRemoteProperties(new TransportId("foo"));
|
t.getRemoteProperties(new TransportId("foo"));
|
||||||
assertEquals(2, properties.size());
|
assertEquals(3, properties.size());
|
||||||
assertEquals(0, properties.get(contact1.getId()).size());
|
assertEquals(0, properties.get(contact1.getId()).size());
|
||||||
assertEquals(fooProperties, properties.get(contact2.getId()));
|
assertEquals(0, properties.get(contact2.getId()).size());
|
||||||
|
assertEquals(fooProperties, properties.get(contact3.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -513,7 +506,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testMergingNewPropertiesCreatesUpdate() throws Exception {
|
public void testMergingNewPropertiesCreatesUpdate() throws Exception {
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
Contact contact = getContact();
|
Contact contact = getContact(true);
|
||||||
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
@@ -526,12 +519,10 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
expectStoreMessage(txn, localGroup.getId(), "foo",
|
expectStoreMessage(txn, localGroup.getId(), "foo",
|
||||||
fooPropertiesDict, 1, true, false);
|
fooPropertiesDict, 1, true, false);
|
||||||
// Store the new properties in each contact's group, version 1
|
// Store the new properties in each contact's group, version 1
|
||||||
oneOf(identityManager).getLocalAuthor(txn);
|
|
||||||
will(returnValue(localAuthor));
|
|
||||||
oneOf(db).getContacts(txn);
|
oneOf(db).getContacts(txn);
|
||||||
will(returnValue(singletonList(contact)));
|
will(returnValue(singletonList(contact)));
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, contact, localAuthor.getId());
|
MAJOR_VERSION, contact);
|
||||||
will(returnValue(contactGroup));
|
will(returnValue(contactGroup));
|
||||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
contactGroup.getId());
|
contactGroup.getId());
|
||||||
@@ -547,7 +538,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testMergingUpdatedPropertiesCreatesUpdate() throws Exception {
|
public void testMergingUpdatedPropertiesCreatesUpdate() throws Exception {
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
Contact contact = getContact();
|
Contact contact = getContact(true);
|
||||||
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||||
BdfDictionary oldMetadata = BdfDictionary.of(
|
BdfDictionary oldMetadata = BdfDictionary.of(
|
||||||
new BdfEntry("transportId", "foo"),
|
new BdfEntry("transportId", "foo"),
|
||||||
@@ -584,12 +575,10 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Delete the previous update
|
// Delete the previous update
|
||||||
oneOf(db).removeMessage(txn, localGroupUpdateId);
|
oneOf(db).removeMessage(txn, localGroupUpdateId);
|
||||||
// Store the merged properties in each contact's group, version 2
|
// Store the merged properties in each contact's group, version 2
|
||||||
oneOf(identityManager).getLocalAuthor(txn);
|
|
||||||
will(returnValue(localAuthor));
|
|
||||||
oneOf(db).getContacts(txn);
|
oneOf(db).getContacts(txn);
|
||||||
will(returnValue(singletonList(contact)));
|
will(returnValue(singletonList(contact)));
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, contact, localAuthor.getId());
|
MAJOR_VERSION, contact);
|
||||||
will(returnValue(contactGroup));
|
will(returnValue(contactGroup));
|
||||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
contactGroup.getId());
|
contactGroup.getId());
|
||||||
@@ -604,6 +593,12 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
t.mergeLocalProperties(new TransportId("foo"), fooProperties);
|
t.mergeLocalProperties(new TransportId("foo"), fooProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Contact getContact(boolean active) {
|
||||||
|
ContactId c = new ContactId(nextContactId++);
|
||||||
|
return new Contact(c, getAuthor(), localAuthor.getId(),
|
||||||
|
getRandomString(5), true, active);
|
||||||
|
}
|
||||||
|
|
||||||
private void expectGetLocalProperties(Transaction txn) throws Exception {
|
private void expectGetLocalProperties(Transaction txn) throws Exception {
|
||||||
Map<MessageId, BdfDictionary> messageMetadata = new LinkedHashMap<>();
|
Map<MessageId, BdfDictionary> messageMetadata = new LinkedHashMap<>();
|
||||||
// The latest update for transport "foo" should be returned
|
// The latest update for transport "foo" should be returned
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import java.util.concurrent.Executor;
|
|||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
|
|
||||||
@@ -34,7 +33,7 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
|
|||||||
context.mock(SyncRecordWriter.class);
|
context.mock(SyncRecordWriter.class);
|
||||||
|
|
||||||
private final Executor dbExecutor = new ImmediateExecutor();
|
private final Executor dbExecutor = new ImmediateExecutor();
|
||||||
private final ContactId contactId = getContactId();
|
private final ContactId contactId = new ContactId(234);
|
||||||
private final Message message = getMessage(new GroupId(getRandomId()));
|
private final Message message = getMessage(new GroupId(getRandomId()));
|
||||||
private final MessageId messageId = message.getId();
|
private final MessageId messageId = message.getId();
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
|||||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||||
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@@ -36,8 +37,6 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPT
|
|||||||
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getClientId;
|
import static org.briarproject.bramble.test.TestUtils.getClientId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -74,11 +73,11 @@ public class SyncIntegrationTest extends BrambleTestCase {
|
|||||||
DaggerSyncIntegrationTestComponent.builder().build();
|
DaggerSyncIntegrationTestComponent.builder().build();
|
||||||
component.inject(this);
|
component.inject(this);
|
||||||
|
|
||||||
contactId = getContactId();
|
contactId = new ContactId(234);
|
||||||
transportId = getTransportId();
|
transportId = getTransportId();
|
||||||
// Create the transport keys
|
// Create the transport keys
|
||||||
tagKey = getSecretKey();
|
tagKey = TestUtils.getSecretKey();
|
||||||
headerKey = getSecretKey();
|
headerKey = TestUtils.getSecretKey();
|
||||||
streamNumber = 123;
|
streamNumber = 123;
|
||||||
// Create a group
|
// Create a group
|
||||||
ClientId clientId = getClientId();
|
ClientId clientId = getClientId();
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user